2. ストリーミング再生
このドキュメントは機械翻訳で作成された下書きであり、現在レビュー中です。機械翻訳の特性上、一部の内容が不正確であったり、韓国語の原文と異なる場合があります。より正確な情報については、韓国語のドキュメントをご参照ください。
JWT URL を使用してKollusPlayerViewを生成し、コンテンツをデバイスに直接リアルタイムストリーミング再生する方法を説明します。
ローカルにダウンロードされたコンテンツの再生とは異なり、ストリーミング時には再生のたびにお客様のサーバーから新たに発行された一回限り(One-time) URL を使用します。
このドキュメントのすべてのサンプルコードは、公式サンプルアプリkollus_player_iosをベースに作成されています。
コンテンツ配信方式
Kollus サービスはチャンネル設定に応じて、3 種類の配信方式のいずれかでコンテンツを提供します。
アプリケーションクライアントレイヤーでは同じ JWT URL を受け取りKollusPlayerView(contentURL:)インスタンスをビルドするため、別途コードの分岐を実装する必要はありません。
ただし、配信方式によってアダプティブビットレート(Adaptive Bitrate, ABR)の動作方式や DRM 検証およびライセンス発行フロー、AirPlay 互換性ポリシーが異なるため、インフラチャンネル構成を把握しておくとデバッグや最適化に役立ちます。
| 配信方式 | デフォルト | 説明 | チャンネル設定 |
|---|---|---|---|
| MP4 Progressive Download | ◯ | 単一の MP4 ファイルをリアルタイムでダウンロードしながら同時再生します。アダプティブビットレート(Adaptive Bitrate, ABR)をサポートしない単一品質方式です。 | 別途設定不要(デフォルトチャンネル) |
| HLS ストリーミング | - | マニフェスト(.m3u8)とセグメントファイルで構成されます。iOS AVKit システムに最適化されており、ネットワーク帯域幅の変化に合わせてリアルタイムで品質が自動切り替え(ABR)されます。 | コンソールのチャンネル設定で HLS 出力を有効化 |
| Multi-DRM (FairPlay) | - | HLS メディア構造に FairPlay セキュアライセンス発行フローを組み合わせた形式です。内部的にPallyConFPSSDKコンポーネントが連携して動作します。 | コンソールのチャンネル設定で DRM ポリシーを登録 |
アプリケーションのソースコードでは、KollusPlayerView(contentURL: jwtUrl)コンストラクターを呼び出すだけで 3 種類の方式すべてを再生できます。
実際のストリーミング配信方式は Kollus サーバー側でチャンネル設定に基づいて決定され、クライアントに配信されます。
配信方式の詳細比較
| 比較項目 | MP4 Progressive Download | HLS ストリーミング | Multi DRM |
|---|---|---|---|
| ABR オプション制御 | 帯域幅設定の影響なし | 適用あり(iOS AVKit デフォルトポリシー準拠) | 適用あり(iOS AVKit デフォルトポリシー準拠) |
| シーク(Seek)動作 | HTTP Byte-Range リクエストベースの制御 | セグメント単位の位置シーク | セグメント単位の位置シーク |
| 追加フレームワーク統合 | 外部依存なし | 外部依存なし | PallyConFPSSDK.frameworkライブラリのビルド組み込みが必須 |
| ライセンス発行フロー | ライセンス連携なし | ライセンス連携なし | FairPlay 証明書および SPC データ抽出後、CKC 交換ステップを実行 |
| AirPlay / 外部出力 | 外部ディスプレイ出力許可 | 外部ディスプレイ出力許可 | コンテンツ DRM ポリシーに応じて出力遮断制御を連携 |
ほとんどのお客様はサービス初期段階でMP4 Progressive方式から始め、トラフィックが増加またはアダプティブビットレート(Adaptive Bitrate, ABR)環境が必要になった時点でHLS ストリーミングに切り替えます。 その後、著作権保護および DRM セキュリティが必須なコンテンツに限り、Multi DRM (FairPlay) チャンネルを追加で分離して運用するパターンが一般的です。
基本ストリーミング再生
KollusPlayer SDK のKollusPlayerViewにリアルタイム再生用のインフラ環境とデリゲートオブジェクトを設定した後、プロジェクトの UIView 階層に追加してリアルタイムストリーミング再生を開始します。
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 the license key was issued
// 3. Add to UIView hierarchy
view.addSubview(playerView)
playerView.frame = view.bounds
// 4. Prepare for playback
// Using prepareToPlayWithError: is recommended (see [Playback readiness verification] section below)
}
}
KollusPlayerView 初期化オプション
| 初期化コンストラクター | 用途 |
|---|---|
KollusPlayerView(contentURL: String) | ストリーミング再生(JWT URL) |
KollusPlayerView(mediaContentKey: String) | オフライン再生(ダウンロード済みコンテンツ) |
ストリーミング/オフラインモードはインスタンス生成時に決定されます。同じインスタンスで 2 つのモードを切り替えることはできないため、コンテンツ変更時は新しいKollusPlayerViewを生成してアタッチするパターンが一般的です。
proxyPort の指定
playerView.proxyPortプロパティは、SDK が内部通信を処理するために使用するポートです。
キー発行時に受け取ったプロキシポート番号をそのまま指定してください。任意の値を設定すると正常なストリーミング再生が行われません。
再生準備完了の検証
KollusPlayerViewの再生準備状態のトラッキングは、単純なprepareToPlay呼び出しの代わりに、デリゲートコールバックメソッドであるprepareToPlayWithError:を通じて処理する方式を推奨します。
単純な呼び出しではプレイヤー初期化段階で発生する精密な内部エラーを捕捉しにくいですが、prepareToPlayWithError:方式を使用すると、準備完了または失敗時点に具体的なNSErrorオブジェクトが一緒に受信されるため、具体的な対応が可能です。
func kollusPlayerView(_ playerView: KollusPlayerView,
prepareToPlayWithError error: Error?) {
if let error = error {
// Initialization failed — guide the user based on the error code
let nsError = error as NSError
UIApplication.presentErrorViewController(
title: "Playback preparation failed (\(nsError.code))",
errorDescription: nil,
errorReason: error.localizedDescription)
return
}
// Playback ready — connect control methods to start auto-play or wait for user input.
}
プレイヤーの主要プロパティ
再生制御
以下のプロパティは値を直接設定(set)することで再生を制御します。
| プロパティ | タイプ | 説明 |
|---|---|---|
contentURL | NSString | ストリーミング再生 URL(初期化時に指定) |
currentPlaybackTime | NSTimeInterval | 現在の再生位置(setでシーク実行) |
currentPlaybackRate | float | 再生速度(1.0、1.25、1.5、2.0 など) |
scalingMode | KollusPlayerContentMode | 画面出力モード |
repeatMode | KollusPlayerRepeatMode | 区間リピートモード |
playerContentFrame | CGRect | プレイヤー画面領域 |
AIRateEnable | BOOL | AI 倍速サポートの有無 |
最大 10 倍速まで設定可能ですが、currentPlaybackRateの値が 2.0 を超えるとオ ーディオとビデオの同期がずれる現象や一時的な品質低下が発生する場合があります。
シーク(Seek)および再生制御の例
// 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: disable, .one: repeat single content)
ステータス情報の照会
以下のプロパティは読み取り専用で、現在のプレイヤー状態を照会するために使用します。
| プロパティ | 説明 |
|---|---|
isPreparedToPlay | 再生準備完了の有無 |
isPlaying | リアルタイム再生中の有無 |
isBuffering | バッファリング進行中の有無 |
isSeeking | シーク(Seek)中の有無 |
isScrolling | 画面スクロール中の有無 |
isAudioOnly | オーディオ専用コンテンツの有無 |
naturalSize | 元の動画サイズ(CGSize) |
screenConnectEnabled | 外部ディスプレイ出力許可の有無 |
プレイヤーライフサイクル制御
KollusPlayerDelegateを通じて再生ライフサイクルおよびハードウェア連携ランタイムイベントシグナルを受信し、アプリのビジネス UI ロジックと連携します。
// 1. Playback ready
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 a play() command from the application
// userInteraction == false : Auto-play initiated internally by the SDK (e.g., auto-resume after earphone detachment)
}
// 3. Paused
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. Stopped
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 by playerView.isSeeking value
}
iOS システム環境の特性上、buffering: true通知イベントシグナルが受信される前に、一時停止(pause)デリゲートメソッドが先に呼び出される場合があります。
そのため、buffering: falseステータスシグナルが受信されるタイミングで、アプリケーションのメイン UI 制御権を参照して明示的に再生状態を復元することが安全です。
DRM コンテンツのストリーミング
JWT URL 構造内に有効な DRM ポリシーが含まれている場合、SDK が自動的にライセンスのパースおよびハンドシェイキング段階を制御します。
- FairPlay (Multi DRM):
PallyConFPSSDKフレームワークコンポーネントが SDK と統合され、FairPlay 証明 書交換および SPC ・ CKC ライセンス発行フロー全般を代行します。 - Kollus DRM: 別途依存関係の追加設定なしにライセンスをパース処理します。
DRM 関連イベントはKollusPlayerDRMDelegateを通じて配信されます。デリゲートメソッドの詳細な仕様については、SDK 内部ヘッダーファイルのインターフェース宣言部を参照してください。
プレイヤータイプの分岐処理
公式サンプルアプリでは、コンテンツ URL 内に受信されたhintメタデータを通じて最適なプレイヤータイプを自動指定します。
ほとんどの一般的な環境では、このようなハードウェア可用性チェックの分岐コードを開発レイヤーで毎回直接調整する必要はなく、SDK 内部の自動検出を使用することを推奨します。
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(視聴統計)データ連携
学習管理システム(LMS)への視聴統計送信が必要なコンテンツは、SDK が定期的に LMS Callback を呼び出します。
送信状態および統計処理結果のフィードバックは、接続されたKollusPlayerLMSDelegate Callback を通じて処理されます。
オフライン視聴時に送信に失敗した LMS データはローカルのKollusStorageストレージに蓄積されます。
その後ネットワーク状態が回復した時点で明示的にstorage.sendStoredLms()メソッドを呼び出すと、蓄積されていたローカル視聴統計データが LMS サーバーに一括送信されます。
詳細につ いては8. ダウンロードイベント/コールバックドキュメントを参照してください。
バックグラウンド再生
長時間のバックグラウンド再生を維持するには、iOS オペレーティングシステムが規定するメディアバックグラウンド実行権限の構造が事前に明示されている必要があります。
Info.plistのUIBackgroundModesにaudioオプションを追加- アプリケーション起動時にハードウェアオーディオセッションを再生モードに昇格させるコードを設定
AVAudioSession.sharedInstance().setCategory(.playback, ...) - 設定したオーディオセッションをシステムに最終登録して有効化
AVAudioSession.sharedInstance().setActive(true)
KollusPlayerViewインスタンス自体は iOS オペレーティングシステムのバックグラウンドオーディオ実行権限を取得しません。
そのため、上記 3 つのハードウェアオーディオセッションの承認および有効化処理を直接実装することで、バックグラウンドオーディオ出力が途切れなく維持されます。
ライブコンテンツのストリーミング
リアルタイムライブ配信ストリーミングセッションも、一般的な VOD 環境と同じcontentURL形式で受け取ります。
- ライブの識別方法: ライブか VOD かの判別処理は、受信した JWT Payload 内の
mc[].liveプロパティフィールドの存在有無によって判断できます。 - SDK 内部動作: SDK がライブデータ構造であることを正常に識別すると、その放送仕様に最適化されたタイムシフト(Timeshift)機能制御および DVR 動作を自動的に実行します。
let liveDuration = playerView.liveDuration // Timeshiftable duration (s)
リソースの解放
ユーザーが再生画面を完全に離れるタイミングで、実行中のKollusPlayerViewオブジェクトのリソースを完全に解放し、ビュー階層から明示的に削除する必要があります。
この作業を省略した場合、画面が消えた後もバックグラウンド状態でオーディオ出力が継続するエラーが発生する場合があります。
deinit {
playerView?.removeFromSuperview()
playerView = nil
}