チューナー フレームワーク

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

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 は、以下のユースケースをサポートします。

  • スキャン
  • ライブ
  • 再生
  • 録画

チューナー、MediaCodecAudioTrack は、以下のデータフロー モードをサポートします。

  • 明確なメモリバッファを含む ES ペイロード
  • セキュアなメモリハンドルを含む ES ペイロード
  • パススルー

全体的な設計

Tuner HAL は、Android フレームワークとベンダーのハードウェア間で定義されます。Tuner HAL の全体的な設計は以下のとおりです。

  • フレームワークがベンダーに期待する内容と、ベンダーがそれを実現する方法を記述します。
  • IFrontendIDemuxIDescramblerIFilterIDvrILnb インターフェースを介して、フロントエンド、Demux、descramber の機能をフレームワークにエクスポートします。
  • MediaCodecAudioTrack など、他のフレームワーク コンポーネントと Tuner HAL を統合する関数が含まれています。

Tuner Java クラスとネイティブ クラスが作成されます。

  • Tuner Java API により、アプリは公開 API を通じてチューナー HAL にアクセスできます。
  • ネイティブ クラスにより、Tuner HAL を使った大量の録画データや再生データに対する権限の制御と取り扱いが可能になります。
  • ネイティブ チューナー モジュールは、Tuner Java クラスと Tunerer HAL 間のブリッジとなります。

TRM クラスが作成されます。

  • フロントエンド、LNB、CAS セッション、テレビ入力デバイスなどの限られたチューナー リソースを TV 入力 HAL から管理します。
  • 不足しているリソースをアプリから再利用するためのルールを適用します。デフォルトのルールでは、フォアグラウンドが優先されます。

Media CAS と CAS HAL が拡張され、次の機能が導入されます。

  • さまざまな使用目的とアルゴリズムのために CAS セッションを開きます。
  • CICAM の削除や挿入など、動的な CAS システムをサポートします。
  • キートークンを提供して Tuner HAL と統合します。

MediaCodecAudioTrack が拡張され、次の機能が導入されます。

  • セキュアな A/V メモリをコンテンツ入力として受け取ります。
  • トンネルモードの再生でハードウェア A/V 同期を行うように構成されています。
  • ES_payload とパススルー モードをサポートするように構成されています。

Tuner HAL の全体的な設計。

図 2. Tuner HAL 内のコンポーネントの図

全体的なワークフロー

ライブ配信再生の呼び出しシーケンスを下の図に示します。

セットアップ

ライブ配信再生の設定シーケンスの図

図 3. ライブ配信再生の設定シーケンス

A/V の取り扱い

ライブ配信再生の A/V の取り扱いを示す図。

図 4. ライブ配信再生の A/V の取り扱い

スクランブル化されたコンテンツの取り扱い

ライブ配信再生のスクランブル化されたコンテンツの取り扱いを示す図

図 5. ライブ配信再生のスクランブル化されたコンテンツの取り扱い

A/V データの処理

ライブ配信再生の A/V データの処理を示す図。

図 6. ライブ配信再生の A/V の処理

Tuner SDK API

Tuner SDK API は、Tuner JNI、Tuner HAL、TunerResourceManager との連携を扱います。TIS アプリは、Tuner SDK API を使用して、フィルタや descrambler などのチューナーのリソースおよびサブコンポーネントにアクセスします。フロントエンドと demux は内部コンポーネントです。

Adjust SDK API のフロー図

図 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

Tuner SDK API パッケージのフロー図。

図 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.tuneTuner.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() を呼び出して、スキャンを一時停止または終了できます。

TIS スキャン プロセスのフロー図。

図 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:
true
必須:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

推奨:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
イベントと内部スケジュールに従って、
Filter.read(buffer, offset, adjustedSize) を 1 回以上実行します。

データは HAL の MQ からクライアント バッファにコピーされます。
構成済みのセッション パッケージは、別のセッション パッケージによって FMQ に入力されます。
isRaw:
false
必須:
DemuxFilterEvent::DemuxFilterSectionEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

省略可:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterSectionEven[i].size)


データは HAL の MQ からクライアント バッファにコピーされます。
TS.PES isRaw:
true
必須:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

推奨:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
イベントと内部スケジュールに従って、
Filter.read(buffer, offset, adjustedSize) を 1 回以上実行します。

データは HAL の MQ からクライアント バッファにコピーされます。
構成済みの PES パッケージは、別の PES パッケージによって FMQ に入力されます。
isRaw:
false
必須:
DemuxFilterEvent::DemuxFilterPesEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

省略可:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterPesEven[i].size)


データは HAL の MQ からクライアント バッファにコピーされます。
MMTP.PES isRaw:
true
必須:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

推奨:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
イベントと内部スケジュールに従って、
Filter.read(buffer, offset, adjustedSize) を 1 回以上実行します。

データは HAL の MQ からクライアント バッファにコピーされます。
構成済みの MFU パッケージは、別の MFU パッケージによって FMQ に入力されます。
isRaw:
false
必須:
DemuxFilterEvent::DemuxFilterPesEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

省略可:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterPesEven[i].size)


データは 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:
true
省略可:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
クライアントは DemuxFilterStatus::DATA_READY を受け取った後に MediaCodec を開始できます。
クライアントは、DemuxFilterStatus::DATA_OVERFLOW を受け取った後に Filter.flush を呼び出すことができます。
該当なし
isPassthrough:
false
必須:
DemuxFilterEvent::DemuxFilterMediaEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

省略可:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
MediaCodec を使用するには:
for i=0; i<n; i++
linearblock = MediaEvent[i].getLinearBlock();
codec.startQueueLinearBlock(linearblock)
linearblock.recycle()


AudioTrack のダイレクト オーディオを使用するには:
for i=0; i<n; i++
audioHandle = MediaEvent[i].getAudioHandle();
audiotrack.write(encapsulated(audiohandle))
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++
DemuxFilterTsRecordEvent[i];


録画コンテンツの場合RecordStatus::* と内部スケジュールに従って、次のいずれかを行います。
  • ストレージに対して DvrRecord.write(adustedSize) を 1 回以上実行します。
    データは HAL の MQ からストレージに転送されます。
  • バッファに対して DvrRecord.write(buffer, adustedSize) を 1 回以上実行します。
    データは HAL の MQ からクライアント バッファにコピーされます。
インデックス データの場合: イベント ペイロードで実施されます。

録画コンテンツの場合: 多重化 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++
DemuxFilterTemiEvent[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++
DemuxFilterMmtpRecordEvent[i];


録画コンテンツの場合RecordStatus::* と内部スケジュールに従って、次のいずれかを行います。
  • ストレージに対して DvrRecord.write(adjustedSize) を 1 回以上実行します。
    データは HAL の MQ からストレージに転送されます。
  • バッファに対して DvrRecord.write(buffer, adjustedSize) を 1 回以上実行します。
    データは HAL の MQ からクライアント バッファにコピーされます。
インデックス データの場合: イベント ペイロードで実施されます。

録画コンテンツの場合: 多重化 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:
true
省略可:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
除去されたプロトコル サブストリームは、フィルタ チェーンの次のフィルタをフィードします。 該当なし
isPassthrough:
false
必須:
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 をビルドするフローの例

フィルタを使用して PSI/SI をビルドするフローの例

図 10. PSI/SI をビルドするフロー

  1. フィルタを開きます。

    Filter filter = tuner.openFilter(
      Filter.TYPE_TS,
      Filter.SUBTYPE_SECTION,
      /* bufferSize */1000,
      executor,
      filterCallback
    );
    
  2. フィルタを構成して開始します。

    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();
    
  3. 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 を使用するフローの例

フィルタから MediaEvent を使用するフローの例。

図 11. フィルタから MediaEvent を使用するフロー

  1. A/V フィルタを開いて構成し、起動します。
  2. MediaEvent を処理します。
  3. MediaEvent を受信します。
  4. リニアブロックを codec にキューします。
  5. データが消費されたら A/V ハンドルを解放します。

Android.media.tv.tuner.dvr

DvrRecorder は、録画のための次のメソッドを提供します。

  • configure
  • attachFilter
  • detachFilter
  • start
  • flush
  • stop
  • setFileDescriptor
  • write

DvrPlayback は、再生のための次のメソッドを提供します。

  • configure
  • start
  • flush
  • stop
  • setFileDescriptor
  • read

DvrSettings は、DvrRecorderDvrPlayback を構成するために使用されます。OnPlaybackStatusChangedListenerOnRecordStatusChangedListener は、DVR インスタンスのステータスをレポートするために使用されます。

録画を開始するフローの例

録画を開始するフローの例

図 12. 録画を開始するフロー

  1. 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();
    
  2. 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. }
          }
        }
    };
    
  3. 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)openDemuxopenDescrambleropenLnbgetDemuxCaps ITuner.hal
IFrontend setCallbackgetStatusclosetunestopTunescanstopScansetLnb IFrontend.hal
IFrontendCallback.hal
IDemux close setFrontendDataSourceopenFilteropenDvrgetAvSyncHwIdgetAvSyncTimeconnect / disconnectCiCam IDemux.hal
IDvr closestartstopconfigure attach/detachFiltersflushgetQueueDesc IDvr.hal
IDvrCallback.hal
IFilter closestartstopconfiguregetId flushgetQueueDescreleaseAvHandlesetDataSource IFilter.hal
IFilterCallback.hal
ILnb closesetCallback setVoltagesetTonesetSatellitePositionsendDiseqcMessage ILnb.hal
ILnbCallback.hal
IDescrambler close setDemuxSourcesetKeyTokenaddPidremovePid IDescrambler.hal

Tuner HAL 1.1(Tuner HAL 1.0 から取得)

モジュール 基本的な制御 モジュール固有の制御 HAL ファイル
ITuner 該当なし getFrontendDtmbCapabilities @1.1::ITuner.hal
IFrontend tune_1_1scan_1_1getStatusExt1_1 link/unlinkCiCam @1.1::IFrontend.hal
@1.1::IFrontendCallback.hal
IFilter getStatusExt1_1 configureIpCidconfigureAvStreamTypegetAvSharedHandleconfigureMonitorEvent @1.1::IFilter.hal
@1.1::IFilterCallback.hal

Tuner 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 は、チューナー フレームワーク、MediaCasTvInputHardwareManagerITunerResourceManager.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 を取得して、アプリがフォアグラウンド アプリであるかバックグラウンド アプリかを判断します。mTvInputSessionIdTvInputService.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. チューナー リソース間の競合における再利用メカニズムの図