2. Streaming Playback
Explains how to stream content directly to a device in real time using a JWT URL. Unlike playback of locally downloaded content, streaming uses a one-time URL newly issued from the customer's server at each playback session.
All sample code in this document is based on the official sample app kollus_player_v2_android.
Content delivery methods
The Kollus service delivers content using one of three delivery methods depending on the channel configuration.
At the application client layer, the same JWT URL is received and played back via the setDataSourceByUrl method, so no separate code branching is required.
However, since the ABR behavior, DRM verification, and license issuance flow differ by delivery method, understanding the infrastructure channel configuration is helpful for debugging and optimization.
| Delivery method | Default | Description | Channel settings |
|---|---|---|---|
| MP4 Progressive Download | ◯ | Downloads a single MP4 file in real time while playing it simultaneously. A single-quality method that does not support adaptive bitrate (ABR). | No separate settings required (default channel) |
| HLS streaming | - | Consists of a manifest (.m3u8) and segment files. Bitrate quality switches automatically (ABR) in real time to match changes in network bandwidth. | Enable HLS output in console channel settings |
| Multi DRM (Widevine/PlayReady) | - | A structure that combines HLS or DASH with a DRM security license issuance flow. Validates Widevine L1/L3 device security levels. | Register DRM policy in console channel settings |
In application source code, calling the mMediaPlayer.setDataSourceByUrl(jwtUrl, null) method alone is sufficient to play back all three methods.
The actual streaming delivery method is determined by the Kollus server based on channel settings and delivered to the client.
Detailed delivery method comparison
| Comparison area | MP4 Progressive Download | HLS streaming | Multi DRM |
|---|---|---|---|
| ABR option control | Bandwidth settings have no effect | Adjustment options such as setInitialBandwidth are applied normally | Adjustment options such as setInitialBandwidth are applied normally |
| Seek behavior | HTTP Byte-Range request-based control | Position seeking in segment units | Position seeking in segment units |
| Device level verification | No hardware security verification step | No hardware security verification step | Device security level verification (Widevine L1 specification can be enforced for content) |
extraDrmParam specification | Pass as null | Pass as null | Typically set to null (DRM policy inside the token takes priority; pass only in special environments requiring dynamic parameters) |
Most customers start with the MP4 Progressive method in the early stages of service, then switch to HLS streaming when traffic increases or an adaptive bitrate (ABR) environment is needed. Afterwards, it is common to additionally separate and operate a Multi DRM channel only for content that requires copyright protection and DRM security.
Basic streaming playback
Specify the surface to bind to the MediaPlayer instance of the KollusPlayer SDK and set the issued JWT URL to start real-time streaming playback.
// Example of streaming implementation inside VideoView.openVideo()
mMediaPlayer.setScreenOnWhilePlaying(true);
// 1. Surface binding based on the screen component type (TextureView or SurfaceView)
if (mSurfaceView instanceof TextureView) {
TextureView tv = (TextureView) mSurfaceView;
Surface surface = new Surface(tv.getSurfaceTexture());
mMediaPlayer.setSurface(surface);
} else if (mSurfaceView instanceof SurfaceView) {
mMediaPlayer.setDisplay(((SurfaceView) mSurfaceView).getHolder());
}
// 2. Set ABR fine-grained control options (specify if needed)
mMediaPlayer.setInitialBandwidth(0); // 0: auto-estimate initial bandwidth
mMediaPlayer.setMinDurationForQualityIncreaseMs(1000); // Minimum stable hold time (ms) required for ABR to increase bitrate quality
// 3. Specify data source (JWT URL)
String extraDrmParam = null;
mMediaPlayer.setDataSourceByUrl(jwtUrl, extraDrmParam); // jwtUrl example: https://v.kr.kollus.com/s?jwt=...
mMediaPlayer.prepareAsync();
When prepareAsync() is called, the player's internal state transitions to STATE_PREPARING, and OnPreparedListener.onPrepared() is called when the initial streaming buffer is ready.
Rendering surface settings
| Type | Characteristics | Recommended scenario |
|---|---|---|
SurfaceView | Lightweight output path, low GPU compositing cost | General full-screen playback |
TextureView | Supports View transformations such as rotation, transparency, and blending | Overlay playback on top of UI, PIP, etc. |
// SurfaceView
mMediaPlayer.setDisplay(((SurfaceView) view).getHolder());
// TextureView
Surface surface = new Surface(((TextureView) view).getSurfaceTexture());
mMediaPlayer.setSurface(surface);
DRM content streaming
If the received JWT URL contains a DRM restriction policy, the SDK automatically performs the DRM license verification and renewal process.
DRM streaming starts simply by calling setDataSourceByUrl(jwtUrl, null) without any separate parameter matching at the development layer.
Adaptive bitrate (ABR) control options
ABR options are only effective for HLS streaming and Multi DRM channels. For the default MP4 Progressive Download channel, media is delivered at a single fixed bitrate, so all settings below are ignored.
| API | Description |
|---|---|
setInitialBandwidth(bps) | Specifies the bandwidth estimate (bps) at the time of initial manifest load. When set to 0, the SDK estimates automatically. |
setMinDurationForQualityIncreaseMs(ms) | The time (ms) that the current bandwidth must remain stable before switching to a higher quality. 1000ms is recommended for typical environments. |
The official sample app records the average network bandwidth data from the previous playback session in SharedPreferences,
and passes it as a parameter to setInitialBandwidth at the next streaming initialization to optimize initial buffering wait time.
Player event listeners
Connect listener objects to the MediaPlayer instance to receive media state change events and player control signals.
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
mMediaPlayer.setOnInfoListener(mInfoListener);
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
mMediaPlayer.setOnTimedTextDetectListener(mOnTimedTextDetectListener);
mMediaPlayer.setOnTimedTextListener(mOnTimedTextListener);
mMediaPlayer.setOnExternalDisplayDetectListener(mOnExternalDisplayDetectListener);
mMediaPlayer.setKollusPlayerBookmarkListener(mKollusPlayerBookmarkListener);
mMediaPlayer.setCaptureDetectListener(mCaptureDetectListener);
mMediaPlayer.setEmulatorCheckerListener(mEmulatorCheckListener);
| Listener | Role |
|---|---|
OnPreparedListener | Streaming preparation complete (the point at which start() can be safely called) |
OnCompletionListener | Content playback completed to the end |
OnErrorListener | Error occurred during playback (analyze cause using what and extra codes) |
OnInfoListener | Incidental state information changes (buffering start and end, media information changes, etc.) |
OnBufferingUpdateListener | Buffering progress (0–100) |
OnSeekCompleteListener | Seek complete |
OnVideoSizeChangedListener | Video resolution change |
OnTimedTextDetectListener / OnTimedTextListener | Subtitle track detection / subtitle display |
OnExternalDisplayDetectListener | External display connection state change |
KollusPlayerBookmarkListener | Bookmark position information detection |
CaptureDetectListener | Screen capture program launch detection |
EmulatorCheckerListener | Rooted device or virtual machine (emulator) environment detection |
Playback state control
Directly control the lifecycle of a streaming playback session in real time using MediaPlayer instance methods.
mMediaPlayer.start(); // Start or resume playback
mMediaPlayer.pause(); // Pause
mMediaPlayer.stop(); // Stop
mMediaPlayer.seekTo(positionMs); // Move playback position (ms)
mMediaPlayer.release(); // Release resources (required when Activity is destroyed)
boolean playing = mMediaPlayer.isPlaying(); // Whether currently playing
int currentMs = mMediaPlayer.getCurrentPosition(); // Current playback position (ms)
int durationMs = mMediaPlayer.getDuration(); // Total content duration (ms)
Playback speed control
Since support for playback speed control depends on the decoder type, call supportPlaybackrateControl() before calling the playback speed change API to check for support.
if (mMediaPlayer.supportPlaybackrateControl()) {
// Integrate playback speed change API
}
Background playback
To maintain long-duration background playback, the MediaPlayer instance must be managed inside a Service structure that follows the Android component lifecycle and run as a Foreground Service.
The official sample app includes an implementation pattern that integrates the MoviePlayerService component for this purpose.
Control message design for background playback
To coordinate reliably with system state changes, you must understand the relationship between the following two settings and implement the integration code accordingly.
MoviePlayerService.APP_BACKGROUND: A message that notifies the service side that the application's screen layer has transitioned to the background state. Receiving this message alone does not stop playback.KollusConstants.SUPPORT_BACKGROUND_PLAYBACK: A flag variable that determines whether playback is allowed in the background state. Since this property value is not automatically passed into the service component, the app layer must make the determination and additionally send a stop message.
// Example implementation pattern when the screen layer transitions to background, such as in Activity.onStop()
mMessenger.send(Message.obtain(null, MoviePlayerService.APP_BACKGROUND));
// If background playback is not allowed, explicitly send a PAUSE message
if (!supportBackgroundPlayback) {
mMessenger.send(Message.obtain(null, MoviePlayerService.PAUSE));
}
The supportBackgroundPlayback variable is a local variable initialized by reading the KollusConstants.SUPPORT_BACKGROUND_PLAYBACK setting value. Since the service engine does not directly reference this value, control must be handled at the app layer as shown in the code above.
External display output restriction
When a state change occurs for HDMI mirroring, Chromecast, DLNA, or similar while the application is running, the event is immediately notified via the OnExternalDisplayDetectListener callback.
For content that must block external display output due to a security policy, code that immediately executes a player stop command must be applied at the point the listener callback is triggered.
Live content streaming
Real-time live stream sessions are also received as JWT URL structured data in the same form as a general VOD environment.
- Live identification method: Whether the content is live or VOD can be determined by the presence of the
mc[].liveattribute field in the received JWT Payload. - SDK internal behavior: Once the SDK correctly identifies the data structure as live, it automatically performs timeshift control and DVR behavior optimized for the broadcast specifications.