Android 11 以降では、Android チューナー フレームワークを使用して A/V コンテンツを配信できます。このフレームワークは、ベンダーのハードウェア パイプラインを使用するため、ローエンド SoC とハイエンド SoC の両方に適しています。また、高信頼実行環境(TEE)とセキュアなメディアパス(SMP)によって保護された音声および映像(A/V)コンテンツを配信するセキュアな方法を提供するため、制限が厳しいコンテンツ保護環境でも使用できます。
チューナーと Android CAS 間の標準化されたインターフェースにより、チューナー ベンダーと CAS ベンダー間の統合をすばやく行うことができます。チューナー インターフェースは、MediaCodec
および AudioTrack
と連携して、Android TV 用の 1 つのグローバル ソリューションを構築します。チューナー インターフェースは、主要なブロードキャスト標準に基づくデジタルテレビとアナログテレビの両方をサポートしています。
コンポーネント
Android 11 では、TV プラットフォーム用に 3 つのコンポーネントが特別に設計されています。
- Tuner HAL: フレームワークとベンダー間のインターフェース
- Tuner SDK API: フレームワークとアプリ間のインターフェース
- Tuner Resource Manager(TRM): Tuner HW リソースを調整
Android 11 では、次のコンポーネントが拡張されました。
- CAS V2
TvInputService
: TV 入力サービス(TIS)TvInputManagerService
: TV 入力マネージャー サービス(TIMS)MediaCodec
: メディア コーデックAudioTrack
: 音声トラックMediaResourceManager
: メディア リソース マネージャー(MRM)
図 1. Android TV コンポーネント間のインタラクション
機能
フロントエンドは、以下の DTV 標準をサポートしています。
- ATSC
- ATSC3
- DVB C/S/T
- ISDB S/S3/T
- アナログ
Tuner HAL 1.1 以降を搭載した Android 12 のフロントエンドは、以下の DTV 標準をサポートしています。
- DTMB
Demux は以下のストリーム プロトコルをサポートしています。
- トランスポート ストリーム(TS)
- MPEG メディア トランスポート プロトコル(MMTP)
- インターネット プロトコル(IP)
- Type length value (TLV)
- ATSC リンクレイヤ プロトコル(ALP)
Decrambler は、以下のコンテンツの保護をサポートしています。
- セキュアなメディアパス
- 明確なメディアパス
- セキュアなローカル レコード
- セキュアなローカル再生
Tuner API は、以下のユースケースをサポートします。
- スキャン
- ライブ
- 再生
- 録画
チューナー、MediaCodec
、AudioTrack
は、以下のデータフロー モードをサポートします。
- 明確なメモリバッファを含む ES ペイロード
- セキュアなメモリハンドルを含む ES ペイロード
- パススルー
全体的な設計
Tuner HAL は、Android フレームワークとベンダーのハードウェア間で定義されます。Tuner HAL の全体的な設計は以下のとおりです。
- フレームワークがベンダーに期待する内容と、ベンダーがそれを実現する方法を記述します。
IFrontend
、IDemux
、IDescrambler
、IFilter
、IDvr
、ILnb
インターフェースを介して、フロントエンド、Demux、descramber の機能をフレームワークにエクスポートします。MediaCodec
やAudioTrack
など、他のフレームワーク コンポーネントと Tuner HAL を統合する関数が含まれています。
Tuner Java クラスとネイティブ クラスが作成されます。
- Tuner Java API により、アプリは公開 API を通じてチューナー HAL にアクセスできます。
- ネイティブ クラスにより、Tuner HAL を使った大量の録画データや再生データに対する権限の制御と取り扱いが可能になります。
- ネイティブ チューナー モジュールは、Tuner Java クラスと Tuner HAL 間のブリッジとなります。
TRM クラスが作成されます。
- フロントエンド、LNB、CAS セッション、テレビ入力デバイスなどの限られたチューナー リソースを TV 入力 HAL から管理します。
- 不足しているリソースをアプリから再利用するためのルールを適用します。デフォルトのルールでは、フォアグラウンドが優先されます。
Media CAS と CAS HAL が拡張され、次の機能が導入されます。
- さまざまな使用目的とアルゴリズムのために CAS セッションを開きます。
- CICAM の削除や挿入など、動的な CAS システムをサポートします。
- キートークンを提供して Tuner HAL と統合します。
MediaCodec
と AudioTrack
が拡張され、次の機能が導入されます。
- セキュアな A/V メモリをコンテンツ入力として受け取ります。
- トンネルモードの再生でハードウェア A/V 同期を行うように構成されています。
ES_payload
とパススルー モードをサポートするように構成されています。
図 2. Tuner HAL 内のコンポーネントの図
全体的なワークフロー
ライブ配信再生の呼び出しシーケンスを下の図に示します。
セットアップ
図 3. ライブ配信再生の設定シーケンス
A/V の取り扱い
図 4. ライブ配信再生の A/V の取り扱い
スクランブル化されたコンテンツの取り扱い
図 5. ライブ配信再生のスクランブル化されたコンテンツの取り扱い
A/V データの処理
図 6. ライブ配信再生の A/V の処理
Tuner SDK API
Tuner SDK API は、Tuner JNI、Tuner HAL、TunerResourceManager
との連携を扱います。TIS アプリは、Tuner SDK API を使用して、フィルタや descrambler などのチューナーのリソースおよびサブコンポーネントにアクセスします。フロントエンドと demux は内部コンポーネントです。
図 7. Tuner SDK API との連携
バージョン
Android 12 以降、Tuner SDK API は、Tuner 1.0 と下位互換性のあるバージョン アップグレードである Tuner HAL 1.1 の新機能をサポートしています。
次の API を使用して、実行中の HAL のバージョンを確認できます。
android.media.tv.tuner.TunerVersionChecker.getTunerVersion()
最低限必要な HAL バージョンについては、新しい Android 12 API のドキュメントをご覧ください。
パッケージ
Tuner SDK API は以下の 4 つのパッケージを提供します。
android.media.tv.tuner
android.media.tv.tuner.frontend
android.media.tv.tuner.filter
android.media.tv.tuner.dvr
図 8. Tuner SDK API パッケージ
Android.media.tv.tuner
このチューナー パッケージは、チューナー フレームワークを使用するためのエントリ ポイントです。TIS アプリはこのパッケージを使用することで、初期設定とコールバックを指定して、リソース インスタンスを初期化、取得します。
tuner()
:useCase
パラメータとsessionId
パラメータを指定して、チューナー インスタンスを初期化します。tune()
:FrontendSetting
パラメータを指定して、フロントエンド リソースとチューナーを取得します。openFilter()
: フィルタタイプを指定して、フィルタ インスタンスを取得します。openDvrRecorder()
: バッファサイズを指定して、録画インスタンスを取得します。openDvrPlayback()
: バッファサイズを指定して、再生インスタンスを取得します。openDescrambler()
: descrambler インスタンスを取得します。openLnb()
: 内部 LNB インスタンスを取得します。openLnbByName()
: 外部 LNB インスタンスを取得します。openTimeFilter()
: 時間フィルタ インスタンスを取得します。
Tuner パッケージは、フィルタ、DVR、フロントエンド パッケージでは対応していない機能を提供します。該当する機能は以下のとおりです。
cancelTuning
scan
/cancelScanning
getAvSyncHwId
getAvSyncTime
connectCiCam1
/disconnectCiCam
shareFrontendFromTuner
updateResourcePriority
setOnTuneEventListener
setResourceLostListener
Android.media.tv.tuner.frontend
このフロントエンド パッケージには、フロントエンド関連の設定、情報、ステータス、イベント、機能がまとめられています。
クラス
FrontendSettings
は、以下のクラスで異なる DTV 標準用に取得されます。
AnalogFrontendSettings
Atsc3FrontendSettings
AtscFrontendSettings
DvbcFrontendSettings
DvbsFrontendSettings
DvbtFrontendSettings
Isdbs3FrontendSettings
IsdbsFrontendSettings
IsdbtFrontendSettings
Tuner HAL 1.1 以降を搭載した Android 12 以降では、次の DTV 標準がサポートされています。
DtmbFrontendSettings
FrontendCapabilities
は、以下のクラスで異なる DTV 標準用に取得されます。
AnalogFrontendCapabilities
Atsc3FrontendCapabilities
AtscFrontendCapabilities
DvbcFrontendCapabilities
DvbsFrontendCapabilities
DvbtFrontendCapabilities
Isdbs3FrontendCapabilities
IsdbsFrontendCapabilities
IsdbtFrontendCapabilities
Tuner HAL 1.1 以降を搭載した Android 12 以降では、次の DTV 標準がサポートされています。
DtmbFrontendCapabilities
FrontendInfo
は、フロントエンドの情報を取得します。FrontendStatus
は、フロントエンドの現在のステータスを取得します。OnTuneEventListener
は、フロントエンドでイベントをリッスンします。TIS アプリは、ScanCallback
を使用してフロントエンドからのスキャン メッセージを処理します。
チャンネル スキャン
テレビをセットアップするため、アプリは考えられる周波数をスキャンし、ユーザーがアクセスするチャンネル ラインナップを作成します。TIS は、Tuner.tune
、Tuner.scan(BLIND_SCAN)
、または Tuner.scan(AUTO_SCAN)
を使用してチャンネル スキャンを完了します。
周波数、標準規格(T/T2、S/S2 など)、その他の必要な情報(PLD ID など)など、TIS にシグナルの正確な配信情報がある場合、より迅速なオプションとして Tuner.tune
をおすすめします。
ユーザーが Tuner.tune
を呼び出すと、次のアクションが発生します。
- TIS が
Tuner.tune
を使用してFrontendSettings
に必須情報を入力する。 - シグナルがロックされている場合、HAL が Tune
LOCKED
メッセージをレポートする。 - TIS が
Frontend.getStatus
を使用して必要な情報を収集する。 - TIS が周波数リストの次の使用可能な周波数に移動する。
TIS は、すべての周波数がなくなるまで Tuner.tune
を再度呼び出します。
チューニング中、stopTune()
または close()
を呼び出して、Tuner.tune
呼び出しを一時停止または終了できます。
Tuner.scan(AUTO_SCAN)
TIS に Tuner.tune
を使用するための十分な情報がないものの、周波数リストと標準規格タイプ(DVB T/C/S など)がある場合は、Tuner.scan(AUTO_SCAN)
をおすすめします。
ユーザーが Tuner.scan(AUTO_SCAN)
を呼び出すと、次のアクションが発生します。
TIS が
Tuner.scan(AUTO_SCAN)
を周波数が入力されたFrontendSettings
とともに使用する。シグナルがロックされている場合、HAL がスキャン
LOCKED
メッセージをレポートする。HAL は、他のスキャン メッセージをレポートしてシグナルに関する追加情報を提供する場合もあります。TIS が
Frontend.getStatus
を使用して必要な情報を収集する。TIS が、HAL に対して
Tuner.scan
を呼び出し、同じ周波数で次の設定に移行する。FrontendSettings
構造が空の場合、HAL は次の使用可能な設定を使用する。それ以外の場合、HAL が 1 回限りのスキャンにFrontendSettings
を使用し、スキャン操作が完了したことを示すEND
を送信する。TIS が、周波数のすべての設定がなくるまで上記の操作を繰り返す。
HAL が
END
を送信し、スキャン操作が完了したことを示す。TIS が周波数リストの次の使用可能な周波数に移動する。
TIS は、すべての周波数がなくなるまで Tuner.scan(AUTO_SCAN)
を再度呼び出します。
スキャン中、stopScan()
または close()
を呼び出して、スキャンを一時停止または終了できます。
Tuner.scan(BLIND_SCAN)
TIS に周波数リストがなく、ベンダー HAL でユーザー指定のフロントエンドの周波数を検索してフロントエンド リソースを取得できる場合は、Tuner.scan(BLIND_SCAN)
をおすすめします。
- TIS が
Tuner.scan(BLIND_SCAN)
を使用する。周波数の開始周波数はFrontendSettings
で指定できますが、TIS ではFrontendSettings
の他の設定は無視されます。 - シグナルがロックされている場合、HAL がスキャン
LOCKED
メッセージをレポートする。 - TIS が
Frontend.getStatus
を使用して必要な情報を収集する。 - TIS は
Tuner.scan
を再度呼び出し、スキャンを続行する(FrontendSettings
は無視されます)。 - TIS が、周波数のすべての設定がなくるまで上記の操作を繰り返す。HAL が、TIS からのアクションを必要としない周波数の数値を増分する。HAL が
PROGRESS
をレポートする。
TIS は、すべての周波数がなくなるまで Tuner.scan(AUTO_SCAN)
を再度呼び出します。HAL が END
をレポートし、スキャン操作が完了したことを示します。
スキャン中、stopScan()
または close()
を呼び出して、スキャンを一時停止または終了できます。
図 9. TIS スキャンのフロー図
Android.media.tv.tuner.filter
フィルタ パッケージには、構成、設定、コールバック、イベントを含むフィルタ オペレーションがまとめられています。パッケージには、次のオペレーションが含まれます。オペレーションの完全なリストについては、Android のソースコードを参照してください。
configure()
start()
stop()
flush()
read()
完全なリストについては、Android のソースコードを参照してください。
FilterConfiguration
は、以下のクラスから取得されます。この構成はメインのフィルタタイプ用で、フィルタがデータを抽出するために使用するプロトコルを指定します。
AlpFilterConfiguration
IpFilterConfiguration
MmtpFilterConfiguration
TlvFilterConfiguration
TsFilterConfiguration
これらの設定は次のクラスから取得されます。この設定はフィルタ サブタイプ用で、フィルタが除外できるデータの種類を指定します。
SectionSettings
AvSettings
PesSettings
RecordSettings
DownloadSettings
FilterEvent
は、以下のクラスから取得され、さまざまな種類のデータのイベントをレポートします。
SectionEvent
MediaEvent
PesEvent
TsRecordEvent
MmtpRecordEvent
TemiEvent
DownloadEvent
IpPayloadEvent
Tuner HAL 1.1 以降を搭載した Android 12 以降、以下のイベントがサポートされています。
IpCidChangeEvent
RestartEvent
ScramblingStatusEvent
フィルタのイベントとデータ形式
フィルタの種類 | フラグ | イベント | データ オペレーション | データ形式 |
---|---|---|---|---|
TS.SECTION MMTP.SECTION IP.SECTION TLV.SECTION ALP.SECTION |
isRaw: |
必須:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 推奨: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
イベントと内部スケジュールに従って、Filter.read(buffer, offset, adjustedSize) を 1 回以上実行します。データは HAL の MQ からクライアント バッファにコピーされます。 |
構成済みのセッション パッケージは、別のセッション パッケージによって FMQ に入力されます。 |
isRaw: |
必須:DemuxFilterEvent::DemuxFilterSectionEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 省略可: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i++ データは HAL の MQ からクライアント バッファにコピーされます。 |
||
TS.PES |
isRaw: |
必須:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 推奨: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
イベントと内部スケジュールに従って、Filter.read(buffer, offset, adjustedSize) を 1 回以上実行します。データは HAL の MQ からクライアント バッファにコピーされます。 |
構成済みの PES パッケージは、別の PES パッケージによって FMQ に入力されます。 |
isRaw: |
必須:DemuxFilterEvent::DemuxFilterPesEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 省略可: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i++ データは HAL の MQ からクライアント バッファにコピーされます。 |
||
MMTP.PES |
isRaw: |
必須:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 推奨: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
イベントと内部スケジュールに従って、Filter.read(buffer, offset, adjustedSize) を 1 回以上実行します。データは HAL の MQ からクライアント バッファにコピーされます。 |
構成済みの MFU パッケージは、別の MFU パッケージによって FMQ に入力されます。 |
isRaw: |
必須:DemuxFilterEvent::DemuxFilterPesEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 省略可: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i++ データは HAL の MQ からクライアント バッファにコピーされます。 |
||
TS.TS |
該当なし | 必須:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 推奨: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
イベントと内部スケジュールに従って、Filter.read(buffer, offset, adjustedSize) を 1 回以上実行します。データは HAL の MQ からクライアント バッファにコピーされます。 |
ts ヘッダーで除外され除去された ts がFMQ で入力されます。 |
TS.Audio TS.Video MMTP.Audio MMTP.Video |
isPassthrough: |
省略可:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW |
クライアントは DemuxFilterStatus::DATA_READY を受け取った後に MediaCodec を開始できます。クライアントは、 DemuxFilterStatus::DATA_OVERFLOW を受け取った後に Filter.flush を呼び出すことができます。 |
該当なし |
isPassthrough: |
必須:DemuxFilterEvent::DemuxFilterMediaEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 省略可: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
MediaCodec を使用するには:for i=0; i<n; i++ AudioTrack のダイレクト オーディオを使用するには:for i=0; i<n; i++ |
ION メモリ内の ES データまたは部分的な ES データ。 | |
TS.PCR IP.NTP ALP.PTP |
該当なし | 必須: 該当なし
省略可: 該当なし |
該当なし | 該当なし |
TS.RECORD |
該当なし | 必須: DemuxFilterEvent::DemuxFilterTsRecordEvent[n] RecordStatus::DATA_READY RecordStatus::DATA_OVERFLOW RecordStatus::LOW_WATER RecordStatus::HIGH_WATER 省略可: DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
インデックス データの場合:for i=0; i<n; i++ 録画コンテンツの場合、 RecordStatus::* と内部スケジュールに従って、次のいずれかを行います。
|
インデックス データの場合: イベント ペイロードで実施されます。 録画コンテンツの場合: 多重化 TS ストリームが FMQ 内に入力されます。 |
TS.TEMI |
該当なし | 必須:DemuxFilterEvent::DemuxFilterTemiEvent[n] 省略可: DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i++ |
該当なし |
MMTP.MMTP |
該当なし | 必須:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 推奨: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
イベントと内部スケジュールに従って、Filter.read(buffer, offset, adjustedSize) を 1 回以上実行します。データは HAL の MQ からクライアント バッファにコピーされます。 |
mmtp ヘッダーで除外され除去された mmtp がFMQ で入力されます。 |
MMTP.RECORD |
該当なし | 必須:DemuxFilterEvent::DemuxFilterMmtpRecordEvent[n] RecordStatus::DATA_READY RecordStatus::DATA_OVERFLOW RecordStatus::LOW_WATER RecordStatus::HIGH_WATER 省略可: DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
インデックス データの場合: for i=0; i<n; i++ 録画コンテンツの場合、 RecordStatus::* と内部スケジュールに従って、次のいずれかを行います。
|
インデックス データの場合: イベント ペイロードで実施されます。 録画コンテンツの場合: 多重化 TS ストリームが FMQ 内に入力されます。 録音用のフィルタソースが TLV.TLV から IP.IP へのパススルーの場合、録画されたストリームには TLV と IP ヘッダーがあります。 |
MMTP.DOWNLOAD |
該当なし | 必須:DemuxFilterEvent::DemuxFilterDownloadEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 省略可: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterDownloadEvent[i].size) データは HAL の MQ からクライアント バッファにコピーされます。 |
ダウンロード パッケージは、別の IP ダウンロード パッケージによって FMQ に入力されます。 |
IP.IP_PAYLOAD |
該当なし | 必須:DemuxFilterEvent::DemuxFilterIpPayloadEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 省略可: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterIpPayloadEvent[i].size) データは HAL の MQ からクライアント バッファにコピーされます。 |
IP ペイロード パッケージは、別の IP ペイロード パッケージによって FMQ に入力されます。 |
IP.IP TLV.TLV ALP.ALP |
isPassthrough: |
省略可:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW |
除去されたプロトコル サブストリームは、フィルタ チェーンの次のフィルタをフィードします。 | 該当なし |
isPassthrough: |
必須:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 推奨: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
イベントと内部スケジュールに従って、Filter.read(buffer, offset, adjustedSize) を 1 回以上実行します。データは HAL の MQ からクライアント バッファにコピーされます。 |
プロトコル ヘッダーを含む除去されたプロトコル サブストリームは FMQ で入力されます。 | |
IP.PAYLOAD_THROUGH TLV.PAYLOAD_THROUGH ALP.PAYLOAD_THROUGH |
該当なし | 省略可:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW |
除外されたプロトコル ペイロードは、フィルタ チェーンの次のフィルタをフィードします。 | 該当なし |
フィルタを使用して PSI/SI をビルドするフローの例
図 10. PSI/SI をビルドするフロー
フィルタを開きます。
Filter filter = tuner.openFilter( Filter.TYPE_TS, Filter.SUBTYPE_SECTION, /* bufferSize */1000, executor, filterCallback );
フィルタを構成して開始します。
Settings settings = SectionSettingsWithTableInfo .builder(Filter.TYPE_TS) .setTableId(2) .setVersion(1) .setCrcEnabled(true) .setRaw(false) .setRepeat(false) .build(); FilterConfiguration config = TsFilterConfiguration .builder() .setTpid(10) .setSettings(settings) .build(); filter.configure(config); filter.start();
SectionEvent
を処理します。FilterCallback filterCallback = new FilterCallback() { @Override public void onFilterEvent(Filter filter, FilterEvent[] events) { for (FilterEvent event : events) { if (event instanceof SectionEvent) { SectionEvent sectionEvent = (SectionEvent) event; int tableId = sectionEvent.getTableId(); int version = sectionEvent.getVersion(); int dataLength = sectionEvent.getDataLength(); int sectionNumber = sectionEvent.getSectionNumber(); filter.read(buffer, 0, dataLength); } } } };
フィルタから MediaEvent を使用するフローの例
図 11. フィルタから MediaEvent を使用するフロー
- A/V フィルタを開いて構成し、起動します。
MediaEvent
を処理します。MediaEvent
を受信します。- リニアブロックを
codec
にキューします。 - データが消費されたら A/V ハンドルを解放します。
Android.media.tv.tuner.dvr
DvrRecorder
は、録画のための次のメソッドを提供します。
configure
attachFilter
detachFilter
start
flush
stop
setFileDescriptor
write
DvrPlayback
は、再生のための次のメソッドを提供します。
configure
start
flush
stop
setFileDescriptor
read
DvrSettings
は、DvrRecorder
と DvrPlayback
を構成するために使用されます。OnPlaybackStatusChangedListener
と OnRecordStatusChangedListener
は、DVR インスタンスのステータスをレポートするために使用されます。
録画を開始するフローの例
図 12. 録画を開始するフロー
DvrRecorder
を開いて構成し、起動します。DvrRecorder recorder = openDvrRecorder(/* bufferSize */ 1000, executor, listener); DvrSettings dvrSettings = DvrSettings .builder() .setDataFormat(DvrSettings.DATA_FORMAT_TS) .setLowThreshold(100) .setHighThreshold(900) .setPacketSize(188) .build(); recorder.configure(dvrSettings); recorder.attachFilter(filter); recorder.setFileDescriptor(fd); recorder.start();
RecordEvent
を受信し、インデックス情報を取得します。FilterCallback filterCallback = new FilterCallback() { @Override public void onFilterEvent(Filter filter, FilterEvent[] events) { for (FilterEvent event : events) { if (event instanceof TsRecordEvent) { TsRecordEvent recordEvent = (TsRecordEvent) event; int tsMask = recordEvent.getTsIndexMask(); int scMask = recordEvent.getScIndexMask(); int packetId = recordEvent.getPacketId(); long dataLength = recordEvent.getDataLength(); // handle the masks etc. } } } };
OnRecordStatusChangedListener
を初期化し、レコードデータを保存します。OnRecordStatusChangedListener listener = new OnRecordStatusChangedListener() { @Override public void onRecordStatusChanged(int status) { // a customized way to consume data efficiently by using status as a hint. if (status == Filter.STATUS_DATA_READY) { recorder.write(size); } } };
Tuner HAL
Tuner HAL は HIDL をフォローし、フレームワークとベンダー ハードウェア間のインターフェースを定義します。ベンダーはインターフェースを使用して Tuner HAL を実装し、フレームワークはそれを使用して Tuner HAL 実装と通信します。
モジュール
Tuner HAL 1.0
モジュール | 基本的な制御 | モジュール固有の制御 | HAL ファイル |
---|---|---|---|
ITuner |
該当なし | frontend(open, getIds, getInfo) 、openDemux 、openDescrambler 、openLnb 、getDemuxCaps |
ITuner.hal |
IFrontend |
setCallback 、getStatus 、close | tune 、stopTune 、scan 、stopScan 、setLnb |
IFrontend.hal IFrontendCallback.hal |
IDemux |
close |
setFrontendDataSource 、openFilter 、openDvr 、getAvSyncHwId 、getAvSyncTime 、connect / disconnectCiCam |
IDemux.hal |
IDvr |
close 、start 、stop 、configure |
attach/detachFilters 、flush 、getQueueDesc |
IDvr.hal IDvrCallback.hal |
IFilter |
close 、start 、stop 、configure 、getId |
flush 、getQueueDesc 、releaseAvHandle 、setDataSource |
IFilter.hal IFilterCallback.hal |
ILnb |
close 、setCallback |
setVoltage 、setTone 、setSatellitePosition 、sendDiseqcMessage |
ILnb.hal ILnbCallback.hal |
IDescrambler |
close |
setDemuxSource 、setKeyToken 、addPid 、removePid |
IDescrambler.hal |
Tuner HAL 1.1(Tuner HAL 1.0 から取得)
モジュール | 基本的な制御 | モジュール固有の制御 | HAL ファイル |
---|---|---|---|
ITuner |
該当なし | getFrontendDtmbCapabilities |
@1.1::ITuner.hal |
IFrontend |
tune_1_1 、scan_1_1 、getStatusExt1_1 |
link/unlinkCiCam |
@1.1::IFrontend.hal @1.1::IFrontendCallback.hal |
IFilter |
getStatusExt1_1 |
configureIpCid 、configureAvStreamType 、getAvSharedHandle 、configureMonitorEvent |
@1.1::IFilter.hal @1.1::IFilterCallback.hal |
図 13. Tuner HAL のモジュール間のインタラクションのフロー図
フィルタのリンク
Tuner HAL は、複数のレイヤのフィルタを他のフィルタにリンクできるように、フィルタのリンクをサポートしています。フィルタには、次のルールが適用されます。
- フィルタはツリーとしてリンクされ、閉じられたパスは使用できません。
- ルートノードは demux です。
- フィルタは独立して動作します。
- すべてのフィルタでデータの取得が開始されます。
- フィルタのリンクは最後のフィルタでフラッシュされます。
以下のコードブロックと図 14 は、複数のレイヤのフィルタリングの例を示しています。
demuxCaps = ITuner.getDemuxCap;
If (demuxCaps[IP][MMTP] == true) {
ipFilter = ITuner.openFilter(<IP, ..>)
mmtpFilter1 = ITuner.openFilter(<MMTP ..>)
mmtpFilter2 = ITuner.openFilter(<MMTP ..>)
mmtpFilter1.setDataSource(<ipFilter>)
mmtpFilter2.setDataSource(<ipFilter>)
}
図 14. 複数のレイヤのフィルタのリンクを示すフロー図
チューナー リソース マネージャー
チューナー リソース マネージャー(TRM)以前は、2 つのアプリを切り替えるには同じチューナー ハードウェアが必要でした。テレビ入力フレームワーク(TIF)は「先行取得優先」メカニズムを使用しました。これは、最初にリソースを取得したアプリがリソースを保持することを意味します。ただし、このメカニズムは一部の複雑なユースケースには適さない場合があります。
TRM は、アプリのチューナー、TVInput
、CAS のハードウェア リソースを管理するためのシステム サービスとして実行されます。TRM は「フォアグラウンド優先」メカニズムを使用します。このメカニズムでは、アプリのフォアグラウンドまたはバックグラウンドのステータスとユースケースのタイプに基づいてアプリの優先度を計算します。TRM は、その優先度に基づいてリソースを許可または取り消します。TRM は、ブロードキャスト、OTT、DVR の ATV リソース管理を一元管理します。
TRM インターフェース
TRM は、チューナー フレームワーク、MediaCas
、TvInputHardwareManager
の ITunerResourceManager.aidl
で AIDL インターフェースを公開し、リソースを登録、リクエスト、またはリリースします。
クライアント管理のインターフェースは以下のとおりです。
registerClientProfile(in ResourceClientProfile profile, IResourcesReclaimListener listener, out int[] clientId)
unregisterClientProfile(in int clientId)
リソースをリクエストしてリリースするためのインターフェースを以下に示します。
requestFrontend(TunerFrontendRequest request, int[] frontendHandle)
/releaseFrontend
requestDemux(TunerDemuxRequest request, int[] demuxHandle)
/releaseDemux
requestDescrambler(TunerDescramblerRequest request, int[] descramblerHandle)
/releaseDescrambler
requestCasSession(CasSessionRequest request, int[] casSessionHandle)
/releaseCasSession
requestLnb(TunerLnbRequest request, int[] lnbHandle)
/releaseLnb
クライアント クラスとリクエスト クラスを以下に示します。
ResourceClientProfile
ResourcesReclaimListener
TunerFrontendRequest
TunerDemuxRequest
TunerDescramblerRequest
CasSessionRequest
TunerLnbRequest
クライアントの優先度
TRM は、クライアントのプロファイルのパラメータと構成ファイルの優先度値を使用して、クライアントの優先度を計算します。優先度は、クライアントの任意の優先値によって更新される場合もあります。
クライアントのプロファイルのパラメータ
TRM は、mTvInputSessionId
からプロセス ID を取得して、アプリがフォアグラウンド アプリであるかバックグラウンド アプリかを判断します。mTvInputSessionId
、TvInputService.onCreateSession
または TvInputService.onCreateRecordingSession
を作成するには、TIS セッションを初期化します。
mUseCase
はセッションのユースケースを示します。事前定義されたユースケースを以下に示します。
TvInputService.PriorityHintUseCaseType {
PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK
PRIORITY_HINT_USE_CASE_TYPE_LIVE
PRIORITY_HINT_USE_CASE_TYPE_RECORD,
PRIORITY_HINT_USE_CASE_TYPE_SCAN,
PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND
}
構成ファイル
デフォルトの構成ファイル
以下のデフォルト構成ファイルでは、事前定義されたユースケースの優先度を示しています。ユーザーは、カスタマイズされた構成ファイルを使用して値を変更できます。
ユースケース | フォアグラウンド | バックグラウンド |
---|---|---|
LIVE |
490 | 400 |
PLAYBACK |
480 | 300 |
RECORD |
600 | 500 |
SCAN |
450 | 200 |
BACKGROUND |
180 | 100 |
カスタマイズされた構成ファイル
ベンダーは構成ファイル /vendor/etc/tunerResourceManagerUseCaseConfig.xml
をカスタマイズできます。このファイルは、ユースケースのタイプとユースケースの優先度値を追加、削除、または更新するために使用されます。カスタマイズされたファイルでは、platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml
をテンプレートとして使用できます。
たとえば、新しいベンダーのユースケースは VENDOR_USE_CASE__[A-Z0-9]+, [0 - 1000]
です。形式は、platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd
に従う必要があります。
任意の優先度値と nice 値
TRM は、クライアントが任意の優先度値と nice 値を更新するための updateClientPriority
を提供します。任意の優先度値は、ユースケースのタイプとセッション ID から計算された優先度値を上書きします。
nice 値は、別のクライアントとの競合した場合の、クライアントの動作の寛容度を示します。nice 値は、クライアントの優先度値が競合するクライアントと比較される前に、そのクライアントの優先度値を減少させます。
再利用メカニズム
下の図は、リソースの競合が発生したときに、リソースがどのように再利用され、割り当てられるかを示しています。
図 15. チューナー リソース間の競合における再利用メカニズムの図