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)
図 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 フレームワークとベンダーのハードウェアの間で定義されます。
- フレームワークがベンダーに期待することと、ベンダーがそれを行う方法について説明します。
-
IFrontend
、IDemux
、IDescrambler
、IFilter
、IDvr
、およびILnb
インターフェイスを介して、フロントエンド、demux、およびデスクランブラーの機能をフレームワークにエクスポートします。 - Tuner HAL を
MediaCodec
やAudioTrack
などの他のフレームワーク コンポーネントと統合する関数が含まれています。
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 と統合します。
MediaCodec
とAudioTrack
は、以下の機能で強化されています。
- セキュア A/V メモリをコンテンツ入力として受け取ります。
- トンネル再生でハードウェア A/V 同期を行うように構成されています。
-
ES_payload
とパススルー モードの構成済みサポート。
図 2. Tuner HAL 内のコンポーネントの図
全体的なワークフロー
以下の図は、ライブ ブロードキャスト再生の呼び出しシーケンスを示しています。
設定
図 3.ライブ ブロードキャスト再生のセットアップ シーケンス
A/V の処理
図 4.ライブ ブロードキャスト再生用の A/V の処理
スクランブルされたコンテンツの処理
図 5.ライブ ブロードキャスト再生用のスクランブル コンテンツの処理
A/V データの処理
図 6.ライブ ブロードキャスト再生用の A/V の処理
チューナー SDK API
Tuner SDK API は、Tuner JNI、Tuner HAL、およびTunerResourceManager
との対話を処理します。 TIS アプリは、Tuner SDK API を使用して、フィルターやデスクランブラーなどの Tuner リソースとサブコンポーネントにアクセスします。フロントエンドとデマルチプレクサは内部コンポーネントです。
図 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
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.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
呼び出しを一時停止または終了できます。
チューナー.スキャン(AUTO_SCAN)
TIS にTuner.tune
を使用するための十分な情報がないが、周波数リストと標準タイプ (たとえば、DVB T/C/S) がある場合は、 Tuner.scan(AUTO_SCAN)
をお勧めします。
ユーザーがTuner.scan(AUTO_SCAN)
を呼び出すと、次のアクションが発生します。
TIS は、頻度で満たされた
FrontendSettings
でTuner.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()
を呼び出して、スキャンを一時停止または終了できます。
図 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 からクライアント バッファにコピーされます。 | 1 つの組み立てられたセッション パッケージは、別のセッション パッケージによって 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 からクライアント バッファにコピーされます。 | 組み立てられた 1 つの 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 からクライアント バッファにコピーされます。 | 組み立てられた 1 つの 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 の Direct Audio を使用するには: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::* および内部スケジュールに従って、次のいずれかを実行します。
| インデックス データの場合:イベント ペイロードで運ばれます。 録画コンテンツの場合: 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++ | なし |
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::* および内部スケジュールに従って、次のいずれかを実行します。
| インデックス データの場合:イベント ペイロードで運ばれます。 記録されたコンテンツの場合: 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: | オプション: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); } } };
チューナー HAL
チューナー HAL は HIDL に従い、フレームワークとベンダー ハードウェア間のインターフェースを定義します。ベンダーはインターフェイスを使用して Tuner HAL を実装し、フレームワークはそれを使用して Tuner HAL 実装と通信します。
モジュール
チューナー HAL 1.0
モジュール | 基本的なコントロール | モジュール固有のコントロール | HAL ファイル |
---|---|---|---|
ITuner | なし | frontend(open, getIds, getInfo) , openDemux , openDescrambler , openLnb , getDemuxCaps | ITuner.hal |
IFrontend | setCallback 、 getStatus 、 close | tune 、 setLnb チューン、スキャン、 stopScan scan 、 stopTune | IFrontend.hal IFrontendCallback.hal |
IDemux | close | setFrontendDataSource 、 openFilter 、 openDvr 、 getAvSyncHwId 、 getAvSyncTime 、 connect / disconnectCiCam CiCam | 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 |
チューナー HAL 1.1 (チューナー 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 つのアプリを切り替えるには同じチューナー ハードウェアが必要でした。 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 を取得して、アプリがフォアグラウンド アプリかバックグラウンド アプリかを判断します。 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
に従う必要があります。
任意のプライオリティ値とナイス値
TRM は、クライアントが任意のプライオリティ値とナイス値を更新するためのupdateClientPriority
を提供します。任意の優先度値は、ユース ケース タイプとセッション ID から計算された優先度値を上書きします。
nice 値は、クライアントが別のクライアントと競合している場合に、そのクライアントの動作がどの程度寛大であるかを示します。ナイス値は、クライアントのプライオリティ値が挑戦的なクライアントと比較される前に、クライアントのプライオリティ値を減らします。
回収メカニズム
次の図は、リソースの競合が発生したときに、リソースがどのように再利用され、割り当てられるかを示しています。
図 15.チューナー リソース間の競合の再利用メカニズムの図