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

Android 11 以降では、Android Tuner フレームワークを使用して A/V コンテンツを配信できます。このフレームワークは、ベンダーのハードウェア パイプラインを使用するため、ローエンド SoC とハイエンド SoC の両方に適しています。このフレームワークは、信頼できる実行環境 (TEE) とセキュア メディア パス (SMP) によって保護された A/V コンテンツを配信する安全な方法を提供し、高度に制限されたコンテンツ保護環境で使用できるようにします。

Tuner と Android CAS 間の標準化されたインターフェイスにより、Tuner ベンダーと CAS ベンダー間の統合が高速化されます。チューナー インターフェースは、 MediaCodecおよびAudioTrackと連携して、Android TV 向けの世界共通のソリューションを構築します。チューナー インターフェイスは、主要な放送規格に基づいて、デジタル TV とアナログ TV の両方をサポートします。

コンポーネント

Android 11 では、3 つのコンポーネントが TV プラットフォーム用に特別に設計されています。

  • Tuner HAL:フレームワークとベンダー間のインターフェース
  • Tuner SDK API:フレームワークとアプリ間のインターフェース
  • チューナー リソース マネージャー (TRM):チューナー HW リソースを調整します。

Android 11 では、次のコンポーネントが強化されました。

  • CAS V2
  • TvInputServiceまたは TV 入力サービス (TIS)
  • TvInputManagerServiceまたは TV 入力マネージャー サービス (TIMS)
  • MediaCodecまたはメディア コーデック
  • AudioTrackまたはオーディオトラック
  • MediaResourceManagerまたはメディア リソース マネージャー (MRM)

Tuner フレームワーク コンポーネントのフロー図。

図 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)
  • タイプ長値 (TLV)
  • ATSC リンク層プロトコル (ALP)

デスクランブラーは、以下のコンテンツ保護をサポートしています。

  • 安全なメディア パス
  • メディア パスのクリア
  • 安全なローカル レコード
  • 安全なローカル再生

Tuner API は、以下の使用例をサポートしています。

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

Tuner、 MediaCodec 、およびAudioTrackは、以下のデータ フロー モードをサポートします。

  • メモリ バッファをクリアした ES ペイロード
  • セキュア メモリ ハンドルを使用した ES ペイロード
  • パススルー

全体的なデザイン

Tuner HAL は、Android フレームワークとベンダーのハードウェアの間で定義されます。

  • フレームワークがベンダーに期待することと、ベンダーがそれを行う方法について説明します。
  • IFrontendIDemuxIDescramblerIFilterIDvr 、およびILnbインターフェイスを介して、フロントエンド、demux、およびデスクランブラーの機能をフレームワークにエクスポートします。
  • Tuner HAL をMediaCodecAudioTrackなどの他のフレームワーク コンポーネントと統合する関数が含まれています。

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

  • Tuner Java API を使用すると、アプリはパブリック API を介して Tuner HAL にアクセスできます。
  • ネイティブ クラスにより、Tuner HAL を使用した大量の録音または再生データのアクセス許可制御と処理が可能になります。
  • Native Tuner モジュールは、Tuner Java クラスと Tuner HAL の間のブリッジです。

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

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

Media CAS と CAS HAL は、次の機能で強化されています。

  • さまざまな用途とアルゴリズムの CAS セッションを開きます。
  • CICAM の取り外しや挿入など、動的な CAS システムをサポートします。
  • キー トークンを提供することで、チューナー HAL と統合します。

MediaCodecAudioTrackは、以下の機能で強化されています。

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

チューナー HAL の全体的なデザイン。

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

全体的なワークフロー

以下の図は、ライブ ブロードキャスト再生の呼び出しシーケンスを示しています。

設定

生放送再生図の設定シーケンス。

図 3.ライブ ブロードキャスト再生のセットアップ シーケンス

A/V の処理

ライブ ブロードキャスト再生用の A/V の処理図。

図 4.ライブ ブロードキャスト再生用の A/V の処理

スクランブルされたコンテンツの処理

ライブ ブロードキャスト再生図のスクランブル コンテンツの処理。

図 5.ライブ ブロードキャスト再生用のスクランブル コンテンツの処理

A/V データの処理

ライブ ブロードキャストの再生図の A/V データを処理します。

図 6.ライブ ブロードキャスト再生用の A/V の処理

チューナー SDK API

Tuner SDK API は、Tuner JNI、Tuner HAL、およびTunerResourceManagerとの対話を処理します。 TIS アプリは、Tuner SDK API を使用して、フィルターやデスクランブラーなどの Tuner リソースとサブコンポーネントにアクセスします。フロントエンドとデマルチプレクサは内部コンポーネントです。

Tuner 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

Tuner パッケージは、Tuner フレームワークを使用するためのエントリ ポイントです。 TIS アプリはパッケージを使用して、初期設定とコールバックを指定することにより、リソース インスタンスを初期化および取得します。

  • tuner tuner() : useCaseおよびsessionIdパラメータを指定して Tuner インスタンスを初期化します。
  • tune() : FrontendSettingパラメータを指定して、フロントエンド リソースとチューニングを取得します。
  • openFilter() : フィルタ タイプを指定してフィルタ インスタンスを取得します。
  • openDvrRecorder() : バッファサイズを指定して記録インスタンスを取得します。
  • openDvrPlayback() : バッファサイズを指定して再生インスタンスを取得します。
  • openDescrambler() : デスクランブラー インスタンスを取得します。
  • openLnb() : 内部 LNB インスタンスを取得します。
  • openLnbByName() : 外部 LNB インスタンスを取得します。
  • openTimeFilter() : 時間フィルター インスタンスを取得します。

チューナー パッケージは、フィルター、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呼び出しを一時停止または終了できます。

チューナー.スキャン(AUTO_SCAN)

TIS にTuner.tuneを使用するための十分な情報がないが、周波数リストと標準タイプ (たとえば、DVB T/C/S) がある場合は、 Tuner.scan(AUTO_SCAN)をお勧めします。

ユーザーがTuner.scan(AUTO_SCAN)を呼び出すと、次のアクションが発生します。

  • TIS は、頻度で満たされたFrontendSettingsTuner.scan(AUTO_SCAN)を使用します。

  • 信号がロックされている場合、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 に周波数リストがなく、Vendor 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 からクライアント バッファにコピーされます。
1 つの組み立てられたセッション パッケージは、別のセッション パッケージによって 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 からクライアント バッファにコピーされます。
組み立てられた 1 つの 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 からクライアント バッファにコピーされます。
組み立てられた 1 つの 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の Direct Audio を使用するには:
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 からクライアント バッファにコピーされます。
インデックス データの場合:イベント ペイロードで運ばれます。

録画コンテンツの場合: FMQ で満たされた多重化 TS ストリーム。
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 からクライアント バッファにコピーされます。
インデックス データの場合:イベント ペイロードで運ばれます。

記録されたコンテンツの場合: FMQ で満たされた多重記録ストリーム。

記録用のフィルター ソースがTLV.TLV to 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は、 DvrRecorderおよびDvrPlaybackを構成するために使用されます。 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);
          }
        }
      };
    

チューナー HAL

チューナー HAL は HIDL に従い、フレームワークとベンダー ハードウェア間のインターフェースを定義します。ベンダーはインターフェイスを使用して Tuner HAL を実装し、フレームワークはそれを使用して Tuner HAL 実装と通信します。

モジュール

チューナー HAL 1.0

モジュール基本的なコントロールモジュール固有のコントロールHAL ファイル
ITunerなしfrontend(open, getIds, getInfo) , openDemux , openDescrambler , openLnb , getDemuxCaps ITuner.hal
IFrontend setCallbackgetStatusclose tunesetLnbチューン、スキャン、 stopScan scanstopTune IFrontend.hal
IFrontendCallback.hal
IDemux close setFrontendDataSourceopenFilteropenDvrgetAvSyncHwIdgetAvSyncTimeconnect / disconnectCiCam CiCam 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

チューナー HAL 1.1 (チューナー 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

チューナー 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 つのアプリを切り替えるには同じチューナー ハードウェアが必要でした。 TV 入力フレームワーク (TIF) は、"先に取得した方が優先される" メカニズムを使用しました。これは、リソースを最初に取得したアプリがリソースを保持することを意味します。ただし、このメカニズムは、一部の複雑なユース ケースには適していない場合があります。

TRM は、アプリのチューナー、 TVInput 、および CAS ハードウェア リソースを管理するシステム サービスとして実行されます。 TRM は、アプリのフォアグラウンドまたはバックグラウンド ステータスとユース ケース タイプに基づいてアプリの優先度を計算する「フォアグラウンド優先」メカニズムを使用します。 TRM は、優先度に基づいてリソースを許可または取り消します。 TRM は、ブロードキャスト、OTT、および DVR の ATV リソース管理を一元化します。

TRM インターフェース

TRM は、チューナー フレームワーク、 MediaCas 、およびTvInputHardwareManagerの ITunerResourceManager.aidl でITunerResourceManager.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に従う必要があります。

任意のプライオリティ値とナイス値

TRM は、クライアントが任意のプライオリティ値とナイス値を更新するためのupdateClientPriorityを提供します。任意の優先度値は、ユース ケース タイプとセッション ID から計算された優先度値を上書きします。

nice 値は、クライアントが別のクライアントと競合している場合に、そのクライアントの動作がどの程度寛大であるかを示します。ナイス値は、クライアントのプライオリティ値が挑戦的なクライアントと比較される前に、クライアントのプライオリティ値を減らします。

回収メカニズム

次の図は、リソースの競合が発生したときに、リソースがどのように再利用され、割り当てられるかを示しています。

再利用メカニズム プロセスの図。

図 15.チューナー リソース間の競合の再利用メカニズムの図