Skip to main content

2. Streaming Playback

Explains how to create a KollusPlayerView using a JWT URL and stream content directly to a device in real time. Unlike playing locally downloaded content, streaming uses a one-time URL freshly issued from the customer's server at each playback.

All example code in this document is based on the official sample app kollus_player_ios.


Content delivery methods

The Kollus service delivers content using one of three delivery methods depending on the channel settings. At the application client layer, you receive the same JWT URL and build a KollusPlayerView(contentURL:) instance, so no separate code branching is required.

However, since Adaptive Bitrate(ABR) behavior, DRM verification and license issuance flow, and AirPlay compatibility policy differ by delivery method, understanding your infrastructure channel configuration will help with debugging and optimization.

Delivery methodDefaultDescriptionChannel settings
MP4 Progressive DownloadDownloads a single MP4 file in real time while playing simultaneously. This is a single-quality method that does not support Adaptive Bitrate(ABR).No separate setting (default channel)
HLS streaming-Composed of a manifest (.m3u8) and segment files. Optimized for the iOS AVKit system, it automatically switches quality in real time (ABR) as network bandwidth changes.Enable HLS output in console channel settings
Multi-DRM (FairPlay)-Combines the HLS media structure with a FairPlay security license issuance flow. The PallyConFPSSDK component is integrated internally.Register DRM policy in console channel settings
tip

In application source code, you can play all three methods simply by calling the KollusPlayerView(contentURL: jwtUrl) constructor. The actual streaming delivery method is determined by the Kollus server based on the channel settings and delivered to the client.

Detailed delivery method comparison

Comparison areaMP4 Progressive DownloadHLS streamingMulti DRM
ABR option controlBandwidth settings have no effectApplied (follows iOS AVKit default policy)Applied (follows iOS AVKit default policy)
Seek behaviorHTTP Byte-Range request-based controlPosition seeking in segment unitsPosition seeking in segment units
Additional framework integrationNo external dependenciesNo external dependenciesMust include PallyConFPSSDK.framework library build
License issuance flowNo license integrationNo license integrationPerforms FairPlay certificate and SPC data extraction, then CKC exchange
AirPlay / external outputExternal display output allowedExternal display output allowedOutput blocking controlled according to content DRM policy
General channel operation pattern

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 (FairPlay) channel only for content that requires copyright protection and DRM security.


Basic streaming playback

Match the infrastructure environment and delegate objects for real-time playback to the KollusPlayerView of the KollusPlayer SDK, then add it to the project UIView hierarchy to start real-time streaming playback.

class PlayerViewController: UIViewController {
var playerView: KollusPlayerView!

// 1. Specify data source (JWT URL)
func play(streamingURL: String) {
DispatchQueue.main.async { [weak self] in
self?.playerView = KollusPlayerView(contentURL: streamingURL)

DispatchQueue.global().async {
self?.initPlayerView()
}
}
}

func initPlayerView() {
// 2. Configure internal environment settings and connect dedicated delegate receiver objects
playerView.debug = false
playerView.storage = StorageManager.shared.storage // Connect KollusStorage
playerView.delegate = self // KollusPlayerDelegate (playback lifecycle)
playerView.DRMDelegate = self // KollusPlayerDRMDelegate (Multi DRM)
playerView.LMSDelegate = self // KollusPlayerLMSDelegate (watch statistics)
playerView.bookmarkDelegate = self // KollusPlayerBookmarkDelegate (bookmark detection)
playerView.scalingMode = .scaleAspectFit
playerView.proxyPort = LICENSE_KEY_PROXY_PORT // Port received when issuing the license key

// 3. Add to UIView hierarchy
view.addSubview(playerView)
playerView.frame = view.bounds

// 4. Prepare for playback
// Using prepareToPlayWithError: is recommended (see [Playback preparation verification] section below)
}
}

KollusPlayerView initialization options

Initialization constructorPurpose
KollusPlayerView(contentURL: String)Streaming playback (JWT URL)
KollusPlayerView(mediaContentKey: String)Offline playback (downloaded content)

The streaming/offline mode is determined at the time of instance creation. You cannot switch between the two modes with the same instance, so it is common to create a new KollusPlayerView and attach it when changing content.

Specifying proxyPort

The playerView.proxyPort property is the port used by the SDK to handle internal communication. Specify the proxy port number received along with the key issuance as-is. Setting an arbitrary value will prevent normal streaming playback.


Playback preparation verification

It is recommended to track the playback preparation state of KollusPlayerView through the delegate callback method prepareToPlayWithError: instead of a simple prepareToPlay call. A simple call makes it difficult to capture precise internal errors triggered during the player initialization phase, but using the prepareToPlayWithError: method receives a specific NSError object at the time of preparation success or failure, enabling specific responses.

func kollusPlayerView(_ playerView: KollusPlayerView,
prepareToPlayWithError error: Error?) {
if let error = error {
// Initialization failed — guide the user based on error code
let nsError = error as NSError
UIApplication.presentErrorViewController(
title: "Playback preparation failed (\(nsError.code))",
errorDescription: nil,
errorReason: error.localizedDescription)
return
}

// Playback preparation complete — integrate control methods to start auto-play or wait for user input.
}

Key player properties

Playback control

The following properties control playback by directly setting (set) their values.

PropertyTypeDescription
contentURLNSStringStreaming playback URL (specified at initialization)
currentPlaybackTimeNSTimeIntervalCurrent playback position (set to seek)
currentPlaybackRatefloatPlayback speed (1.0, 1.25, 1.5, 2.0, etc.)
scalingModeKollusPlayerContentModeScreen output mode
repeatModeKollusPlayerRepeatModePlayback loop section mode
playerContentFrameCGRectPlayer screen area
AIRateEnableBOOLWhether AI Speed is supported
Recommended playback speed control policy

Settings up to 10x speed are possible, but if the currentPlaybackRate value exceeds 2.0, audio-video sync issues or temporary quality degradation may occur.

Seek and playback control examples

// Seek
playerView.currentPlaybackTime = 60.0 // Move playback position to the 60-second mark

// Playback speed
playerView.currentPlaybackRate = 1.5 // Play at 1.5x speed

// Loop section
playerView.repeatMode = .all // Loop all (.none: off, .one: single content loop)

Status information inquiry

The following properties are read-only and used to check the current player state.

PropertyDescription
isPreparedToPlayWhether playback preparation is complete
isPlayingWhether real-time playback is in progress
isBufferingWhether buffering is in progress
isSeekingWhether seeking is in progress
isScrollingWhether screen scrolling is in progress
isAudioOnlyWhether the content is audio-only
naturalSizeOriginal video size (CGSize)
screenConnectEnabledWhether external display output is allowed

Player lifecycle control

Receive playback lifecycle and hardware-integrated runtime event signals through KollusPlayerDelegate and integrate them with the app's business UI logic.

// 1. Playback preparation complete
func kollusPlayerView(_ playerView: KollusPlayerView,
prepareToPlayWithError error: Error?) {
if let error = error {
// Handle preparation failure
return
}
// Auto-play or wait for user input
}

// 2. Playback started
func kollusPlayerView(_ playerView: KollusPlayerView,
play userInteraction: Bool,
error: Error?) {
// userInteraction == true : Playback started by play() command from the application
// userInteraction == false : Auto-play inside the SDK (e.g., auto-resume after earphone disconnect)
}

// 3. Pause
func kollusPlayerView(_ playerView: KollusPlayerView,
pause userInteraction: Bool,
error: Error?) { }

// 4. Buffering state change
func kollusPlayerView(_ playerView: KollusPlayerView,
buffering: Bool,
prepared: Bool,
error: Error?) {
// buffering == true : Buffering started
// buffering == false : Buffering resolved
}

// 5. Stop
func kollusPlayerView(_ playerView: KollusPlayerView,
stop userInteraction: Bool,
error: Error?) { }

// 6. Seek: called twice in total, before and after seeking
func kollusPlayerView(_ playerView: KollusPlayerView,
position: TimeInterval,
error: Error?) {
// Distinguish before/after using playerView.isSeeking
}
Exception handling when responding to buffering events

Due to iOS system environment characteristics, the pause delegate method may be called before the buffering: true notification event signal is received. Therefore, it is safer to explicitly restore the playback state by referencing the application main UI control at the point when the buffering: false status signal is received.


DRM content streaming

If a valid DRM policy is included inside the JWT URL structure, the SDK automatically controls the license parsing and handshaking phases.

  • FairPlay (Multi DRM): The PallyConFPSSDK framework component is integrated with the SDK and handles the entire FairPlay certificate exchange and SPC·CKC license issuance flow.
  • Kollus DRM: Parses the license without any additional dependency configuration steps.

DRM-related events are delivered through KollusPlayerDRMDelegate. For detailed delegate method specifications, please refer to the interface declarations in the SDK's internal header files.


Player type branching

In the official sample app, the optimal player type is automatically designated through hint metadata received inside the content URL.

In most general environments, it is not necessary to directly coordinate hardware availability check branching code at the development layer every time, and it is recommended to use the SDK's automatic detection.

let strPlayerType = checkPlayerType(streamingURL)
switch strPlayerType {
case "hw": playerType = 0 // Kollus built-in hardware decoder
case "sw": playerType = 1 // Kollus built-in software decoder
case "native": playerType = 2 // iOS AVPlayer
default: break
}

// playerType == 0 or 1 → Assign KollusPlayer
// playerType == 2 → Assign Native AVPlayer
if playerType == 0 || playerType == 1 {
try self.playerView.prepareToPlay(withMode: .PlayerTypeKollus)
} else if playerType == 2 {
try self.playerView.prepareToPlay(withMode: .PlayerTypeNative)
}

LMS (watch statistics) data integration

For content that requires sending watch statistics to a Learning Management System (LMS), the SDK periodically calls LMS callbacks. Transmission status and statistics processing result feedback are handled through the connected KollusPlayerLMSDelegate callback.

LMS data that fails to be transmitted during offline viewing accumulates in the local KollusStorage storage. When network connectivity is restored, explicitly calling the storage.sendStoredLms() method will batch-send the accumulated local watch statistics data to the LMS server. For more information, refer to 8. Download Events/Callbacks.


Background playback

To maintain long-duration background playback, the media background execution permission structure specified by the iOS operating system must be declared in advance.

  1. Add the audio option to UIBackgroundModes in Info.plist
  2. Set code to elevate the hardware audio session to playback mode at application startup
    AVAudioSession.sharedInstance().setCategory(.playback, ...)
  3. Finally register and activate the configured audio session at the system level
    AVAudioSession.sharedInstance().setActive(true)
Audio control authority

The KollusPlayerView instance itself does not acquire background audio execution permission from the iOS operating system. Therefore, you must implement the above three hardware audio session approval and activation steps yourself to maintain uninterrupted background audio output.


Live content streaming

Real-time live stream sessions are also received in the same contentURL format as a general VOD environment.

  • How to identify live: Whether the content is live or VOD can be determined by the presence of the mc[].live property field in the received JWT Payload.
  • SDK internal behavior: Once the SDK successfully identifies the data structure as live, it automatically performs timeshift control and DVR operation optimized for that broadcast specification.
let liveDuration = playerView.liveDuration   // Timeshiftable duration (s)

Resource release

When the user completely leaves the playback screen, you must fully release the resources of the running KollusPlayerView object and explicitly remove it from the view hierarchy. If this is omitted, audio output may continue in the background even after the screen is turned off.

deinit {
playerView?.removeFromSuperview()
playerView = nil
}