Android 11以降の場合、Androidチューナーフレームワークを使用してA / Vコンテンツを配信できます。このフレームワークはベンダーのハードウェアパイプラインを使用しているため、ローエンドとハイエンドの両方のSoCに適しています。このフレームワークは、信頼できる実行環境(TEE)と安全なメディアパス(SMP)によって保護されたA / Vコンテンツを配信する安全な方法を提供し、高度に制限されたコンテンツ保護環境で使用できるようにします。
チューナーとAndroidCAS間の標準化されたインターフェースにより、チューナーベンダーとCASベンダー間の統合が高速化されます。チューナーインターフェイスはMediaCodec
およびAudioTrack
とAudioTrack
して、 AudioTrack
向けのワンワールドソリューションを構築します。チューナーインターフェイスは、主要な放送規格に基づいて、デジタルTVとアナログTVの両方をサポートします。
コンポーネント
Android 11の場合、3つのコンポーネントがTVプラットフォーム用に特別に設計されています。
- チューナーHAL:フレームワークとベンダー間のインターフェース
- チューナーSDKAPI:フレームワークとアプリ間のインターフェース
- チューナーリソースマネージャー(TRM):チューナーHWリソースを調整します
Android 11では、次のコンポーネントが拡張されています。
- CAS V2
-
TvInputService
またはTV入力サービス(TIS) -
TvInputManagerService
またはTvInputManagerService
Manager Service(TIMS) -
MediaCodec
またはメディアコーデック AudioTrack
またはオーディオトラックMediaResourceManager
またはメディアリソースマネージャー(MRM)
図1.AndroidTVコンポーネント間の相互作用
特徴
フロントエンドは、以下のDTV規格をサポートしています。
- ATSC
- ATSC3
- DVB C / S / T
- ISDB S / S3 / T
- アナログ
Demuxは、以下のストリームプロトコルをサポートしています。
- トランスポートストリーム(TS)
- MPEGメディアトランスポートプロトコル(MMTP)
- インターネットプロトコル(IP)
- タイプレングス値(TLV)
- ATSCリンク層プロトコル(ALP)
Descramblerは、以下のコンテンツ保護をサポートしています。
- 安全なメディアパス
- メディアパスをクリアする
- ローカルレコードを保護する
- 安全なローカル再生
チューナーAPIは、以下のユースケースをサポートします。
- スキャン
- 住む
- 再生
- 記録
Tuner、 MediaCodec
、およびAudioTrack
は、以下のデータフローモードをサポートしています。
- クリアメモリバッファを備えたESペイロード
- 安全なメモリハンドルを備えたESペイロード
- パススルー
全体的なデザイン
チューナーHALは、Androidフレームワークとベンダーのハードウェアの間で定義されます。
- フレームワークがベンダーに期待することと、ベンダーがそれを行う方法について説明します。
- フロントエンド、デマルチプレクサ、およびデスクランブラーの機能を、
IFrontend
、IDemux
、IDescrambler
、IFilter
、IDvr
、およびILnb
インターフェイスを介してフレームワークにILnb
ます。 - チューナーHALを
MediaCodec
やAudioTrack
などの他のフレームワークコンポーネントと統合するための関数が含まれています。
チューナーJavaクラスとネイティブクラスが作成されます。
- Tuner Java APIを使用すると、アプリはパブリックAPIを介してTunerHALにアクセスできます。
- ネイティブクラスを使用すると、TunerHALを使用して大量の記録または再生データのアクセス許可を制御および処理できます。
- ネイティブチューナーモジュールは、チューナーJavaクラスとチューナーHALの間のブリッジです。
TRMクラスが作成されます。
- フロントエンド、LNB、CASセッション、TV入力HALからのTV入力デバイスなどの限られたチューナーリソースを管理します。
- ルールを適用して、アプリから不十分なリソースを再利用します。デフォルトのルールはフォアグラウンドウィンです。
MediaCASとCASHALは、以下の機能で強化されています。
- さまざまな使用法とアルゴリズムのCASセッションを開きます。
- CICAMの取り外しや挿入などの動的CASシステムをサポートします。
- キートークンを提供することにより、チューナーHALと統合します。
MediaCodec
とAudioTrack
は、以下の機能で拡張されています。
- コンテンツ入力としてセキュアA / Vメモリを取ります。
- トンネル再生でハードウェアA / V同期を行うように構成されています。
-
ES_payload
およびパススルーモードの構成済みサポート。
図2.チューナーHAL内のコンポーネントの図
全体的なワークフロー
次の図は、ライブブロードキャスト再生の呼び出しシーケンスを示しています。
セットアップ
図3.ライブ放送再生のセットアップシーケンス
A / Vの取り扱い
図4.ライブ放送再生のA / Vの処理
スクランブルされたコンテンツの処理
図5.ライブ放送再生のためのスクランブルコンテンツの処理
A / Vデータの処理
図6.ライブ放送再生のためのA / Vの処理
チューナーSDKAPI
Tuner SDK APIは、Tuner JNI、Tuner HAL、およびTunerResourceManager
との相互作用を処理します。 TISアプリは、Tuner SDK APIを使用して、Tunerリソースおよびフィルターやデスクランブラーなどのサブコンポーネントにアクセスします。フロントエンドとデマルチプレクサは内部コンポーネントです。
図7.Tuner SDKAPIとの相互作用
パッケージ
Tuner SDK APIは、以下の4つのパッケージを提供します。
-
android.media.tv.tuner
-
android.media.tv.tuner.frontend
-
android.media.tv.tuner.filter
-
android.media.tv.tuner.dvr
図8.チューナーSDKAPIパッケージ
Android.media.tv.tuner
Tunerパッケージは、Tunerフレームワークを使用するためのエントリポイントです。 TISアプリは、パッケージを使用して、初期設定とコールバックを指定することにより、リソースインスタンスを初期化および取得します。
-
tuner()
指定して初期化チューナーインスタンスuseCase
とsessionId
パラメータを。 -
tune()
:フロントエンドリソースを取得し、FrontendSetting
パラメーターを指定して調整します。 -
openFilter()
:フィルタータイプを指定してフィルターインスタンスを取得します。 -
openDvrRecorder()
:バッファサイズを指定して記録インスタンスを取得します。 -
openDvrPlayback()
:バッファサイズを指定して再生インスタンスを取得します。 -
openDescrambler()
:デスクランブラーインスタンスを取得します。 -
openLnb()
:内部LNBインスタンスを取得します。 -
openLnbByName()
:外部LNBインスタンスを取得します。 -
openTimeFilter()
:時間フィルターインスタンスを取得します。
チューナーパッケージは、フィルター、DVR、およびフロントエンドパッケージでカバーされていない機能を提供します。機能は以下のとおりです。
-
cancelTuning
-
scan
/cancelScanning
scan
-
getAvSyncHwId
-
getAvSyncTime
-
connectCiCam1
/disconnectCiCam
-
shareFrontendFromTuner
-
updateResourcePriority
-
setOnTuneEventListener
-
setResourceLostListener
Android.media.tv.tuner.frontend
フロントエンドパッケージには、フロントエンド関連の設定、情報、ステータス、イベント、および機能のコレクションが含まれています。
クラス
FrontendSettings
は、以下のクラスによってさまざまなDTV標準用に派生しています。
-
AnalogFrontendSettings
-
Atsc3FrontendSettings
-
AtscFrontendSettings
-
DvbcFrontendSettings
-
DvbsFrontendSettings
-
DvbtFrontendSettings
-
Isdbs3FrontendSettings
-
IsdbsFrontendSettings
-
IsdbtFrontendSettings
FrontendCapabilities
は、以下のクラスによってさまざまなDTV標準用に派生しています。
-
AnalogFrontendCapabilities
-
Atsc3FrontendCapabilities
-
AtscFrontendCapabilities
-
DvbcFrontendCapabilities
-
DvbsFrontendCapabilities
-
DvbtFrontendCapabilities
-
Isdbs3FrontendCapabilities
-
IsdbsFrontendCapabilities
-
IsdbtFrontendCapabilities
FrontendInfo
は、フロントエンドの情報を取得します。 FrontendStatus
は、 FrontendStatus
の現在のステータスを取得します。 OnTuneEventListener
は、フロントエンドでイベントをリッスンします。 TISアプリは、 ScanCallback
を使用して、フロントエンドからのスキャンメッセージを処理します。
チャンネルスキャン
テレビをセットアップするために、アプリは可能な周波数をスキャンし、ユーザーがアクセスできるチャンネルラインナップを構築します。 TISは、 Tuner.tune
、 Tuner.scan(BLIND_SCAN)
、またはTuner.scan(AUTO_SCAN)
を使用してチャネルスキャンを完了する場合があります。
TISに周波数、標準(T / T2、S / S2など)、追加の必要な情報(PLD IDなど)などの信号の正確な配信情報がある場合は、より高速なオプションとしてTuner.tune
をお勧めします。 。
ユーザーがTuner.tune
と、次のアクションが発生します。
- TISは、
Tuner.tune
を使用して、FrontendSettings
に必要な情報をTuner.tune
ます。 - 信号がロックされている場合、HALは
LOCKED
メッセージを報告します。 - TISは、
Frontend.getStatus
を使用して必要な情報を収集します。 - TISは、周波数リストで次に使用可能な周波数に移動します。
TISは、すべての周波数が使い果たされるまで、 Tuner.tune
再度呼び出します。
チューニング中に、 stopTune()
またはclose()
を呼び出して、 Tuner.tune
呼び出しを一時停止または終了Tuner.tune
ます。
Tuner.scan(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は
Tuner.scan
を呼び出してHALをTuner.scan
、同じ周波数で次の設定に進みます。FrontendSettings
構造が空の場合、HALは次に使用可能な設定を使用します。それ以外の場合、HALはFrontendSettings
を1回のスキャンに使用し、スキャン操作が終了したことを示すために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
フィルタからのイベントとデータ形式
フィルタタイプ | フラグ | イベント | データ操作 | データ形式 |
---|---|---|---|---|
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 を開始できます。クライアントが呼び出すことができる Filter.flush 受けた後DemuxFilterStatus::DATA_OVERFLOW 。 | 該当なし |
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 | 該当なし | 必須: N / A オプション: N / A | 該当なし | 該当なし |
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で入力されたMuxedTSストリーム。 |
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 を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に入力されたMuxed記録されたストリーム。 記録用のフィルターソースがパススルー付きの 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
処理し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
。 -
MediaEvent
を受信しMediaEvent
。 - 線形ブロックを
codec
キュー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
。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に従い、フレームワークとベンダーハードウェア間のインターフェイスを定義します。ベンダーはインターフェースを使用してTunerHALを実装し、フレームワークはそれを使用してTunerHAL実装と通信します。
モジュール
モジュール | 基本的なコントロール | モジュール固有のコントロール | 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 |
図13.チューナーHALモジュール間の相互作用の図
フィルターリンケージ
チューナー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.複数のレイヤーのフィルターリンケージのフロー図
チューナーリソースマネージャー
Tuner Resource Manager(TRM)以前は、2つのアプリを切り替えるには同じTunerハードウェアが必要でした。 TV Input Framework(TIF)は、「最初に獲得する勝利」メカニズムを使用しました。これは、リソースを最初に取得するアプリがリソースを保持することを意味します。ただし、このメカニズムは、一部の複雑なユースケースには理想的ではない場合があります。
TRMは、アプリのチューナー、 TVInput
、およびCASハードウェアリソースを管理するためのシステムサービスとして実行されます。 TRMは、アプリのフォアグラウンドまたはバックグラウンドステータスとユースケースタイプに基づいてアプリの優先度を計算する「フォアグラウンドウィン」メカニズムを使用します。 TRMは、優先度に基づいてリソースを付与または取り消します。 TRMは、放送、OTT、およびDVRのATVリソース管理を一元化します。
TRMインターフェース
TRMが露出AIDLインターフェイスでITunerResourceManager.aidl
チューナーフレームワークのためのMediaCas
、及びTvInputHardwareManager
登録し、要求、又はリリースリソース。
クライアント管理用のインターフェースを以下に示します。
-
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
な値を更新するためのupdateClientPriority
を提供します。任意の優先度値は、ユースケースタイプとセッションIDから計算された優先度値を上書きします。
nice値は、別のクライアントと競合しているときのクライアントの動作がどれだけ寛大であるかを示します。 nice値は、クライアントの優先度値を、チャレンジングクライアントと比較する前に減少させます。
再利用メカニズム
次の図は、リソースの競合が発生したときにリソースがどのように再利用および割り当てられるかを示しています。
図15.チューナーリソース間の競合に対する再利用メカニズムの図