Skip to main content

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 methodDefaultDescriptionChannel settings
MP4 Progressive DownloadDownloads 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
tip

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 areaMP4 Progressive DownloadHLS streamingMulti DRM
ABR option controlBandwidth settings have no effectAdjustment options such as setInitialBandwidth are applied normallyAdjustment options such as setInitialBandwidth are applied normally
Seek behaviorHTTP Byte-Range request-based controlPosition seeking in segment unitsPosition seeking in segment units
Device level verificationNo hardware security verification stepNo hardware security verification stepDevice security level verification (Widevine L1 specification can be enforced for content)
extraDrmParam specificationPass as nullPass as nullTypically set to null (DRM policy inside the token takes priority; pass only in special environments requiring dynamic parameters)
Common channel operation patterns

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

TypeCharacteristicsRecommended scenario
SurfaceViewLightweight output path, low GPU compositing costGeneral full-screen playback
TextureViewSupports View transformations such as rotation, transparency, and blendingOverlay 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

Limitations

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.

APIDescription
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);
ListenerRole
OnPreparedListenerStreaming preparation complete (the point at which start() can be safely called)
OnCompletionListenerContent playback completed to the end
OnErrorListenerError occurred during playback (analyze cause using what and extra codes)
OnInfoListenerIncidental state information changes (buffering start and end, media information changes, etc.)
OnBufferingUpdateListenerBuffering progress (0–100)
OnSeekCompleteListenerSeek complete
OnVideoSizeChangedListenerVideo resolution change
OnTimedTextDetectListener / OnTimedTextListenerSubtitle track detection / subtitle display
OnExternalDisplayDetectListenerExternal display connection state change
KollusPlayerBookmarkListenerBookmark position information detection
CaptureDetectListenerScreen capture program launch detection
EmulatorCheckerListenerRooted 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));
}
Control authority

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[].live attribute 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.