如果是 Android 11 以上版本,您可以使用 Android Tuner 架構來提供 A/V 內容。此架構會使用供應商提供的硬體管道,因此適合用於低階和高階 SoC。此架構提供安全的傳遞方式,可透過受信任的執行環境 (TEE) 和安全媒體路徑 (SMP) 保護影音內容,讓您在受嚴格限制的內容保護環境中使用。
Tuner 和 Android CAS 之間的標準化介面,可加快 Tuner 供應商和 CAS 供應商之間的整合作業。調諧器介面可搭配 MediaCodec
和 AudioTrack
使用,為 Android TV 建構單一世界解決方案。調諧器介面支援數位電視和類比電視,並遵循主要的廣播標準。
元件
針對 Android 11,我們特別設計了三個適用於 TV 平台的元件。
- Tuner HAL:架構與供應商之間的介面
- Tuner SDK API:架構和應用程式之間的介面
- Tuner Resource Manager (TRM):協調 Tuner 硬體資源
針對 Android 11,我們已強化下列元件。
- CAS V2
TvInputService
或 TV 輸入服務 (TIS)TvInputManagerService
或 TV Input Manager Service (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)
Descrambler 支援下列內容保護機制。
- 安全的媒體路徑
- 清除媒體路徑
- 安全的本機記錄
- 安全的本機播放功能
Tuner API 支援下列用途。
- 掃描
- 直播
- 播放
- 錄影
Tuner、MediaCodec
和 AudioTrack
支援下列資料流模式。
- 含有清除記憶體緩衝區的 ES 酬載
- 含有安全記憶體句柄的 ES 酬載
- 透視
整體設計
Tuner HAL 是在 Android 架構和供應商的硬體之間定義。
- 說明架構對供應商的期望,以及供應商可能採取的做法。
- 透過
IFrontend
、IDemux
、IDescrambler
、IFilter
、IDvr
和ILnb
介面,將前端、解多工和解密器的功能匯出至架構。 - 包含用於將 Tuner HAL 與其他架構元件 (例如
MediaCodec
和AudioTrack
) 整合的函式。
系統會建立 Tuner Java 類別和原生類別。
- Tuner Java API 可讓應用程式透過公開 API 存取 Tuner HAL。
- 原生類別可透過 Tuner HAL 控制權限,並處理大量錄製或播放資料。
- 原生 Tuner 模組是 Tuner Java 類別和 Tuner HAL 之間的橋樑。
建立 TRM 類別。
- 管理有限的調諧器資源,例如前端、LNB、CAS 工作階段,以及電視輸入 HAL 中的電視輸入裝置。
- 套用規則,從應用程式中回收不足的資源。預設規則是前景勝出。
媒體 CAS 和 CAS HAL 已強化以下功能。
- 針對不同用途和演算法開啟 CAS 工作階段。
- 支援動態 CAS 系統,例如 CICAM 移除和插入。
- 提供金鑰符記,與 Tuner HAL 整合。
MediaCodec
和 AudioTrack
已強化下列功能。
- 使用安全的 A/V 記憶體做為內容輸入。
- 已設定在管道式播放中執行硬體 A/V 同步。
- 已設定支援
ES_payload
和直通模式。
圖 2. Tuner HAL 內元件的圖表
整體工作流程
下圖說明直播播放的呼叫序列。
設定
圖 3. 直播播放的設定順序
處理影音
圖 4. 處理直播播放的 A/V
處理經過加密的內容
圖 5. 處理直播內容的雜訊內容
處理影音資料
圖 6. 處理 A/V 以便播放直播
Tuner 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 HAL 1.1 中的新功能,這是 Tuner 1.0 的回溯相容性版本升級。
使用下列 API 檢查執行中的 HAL 版本。
android.media.tv.tuner.TunerVersionChecker.getTunerVersion()
如需查看所需的最低 HAL 版本,請參閱新的 Android 12 API 說明文件。
套件
Tuner SDK API 提供下列四個套件。
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
參數,初始化 Tuner 例項。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)
來完成管道掃描作業。
如果 TIS 有正確的訊號提交資訊 (例如頻率、標準 (例如 T/T2、S/S2) 和其他必要資訊 (例如 PLD ID)),建議使用 Tuner.tune
這個更快速的選項。
使用者呼叫 Tuner.tune
時,會發生下列動作:
- TIS 會使用
Tuner.tune
為FrontendSettings
填入必要資訊。 - 如果信號已鎖定,HAL 會回報調音
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 會呼叫
Tuner.scan
,讓 HAL 繼續在相同頻率上進行下一個設定。如果FrontendSettings
結構體為空白,HAL 會使用下一個可用的設定。否則,HAL 會使用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) 一或多次。資料會從 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) 一或多次。系統會將資料從 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) 一或多次。系統會將資料從 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) 一或多次。系統會將資料從 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::* 和內部排程,執行下列任一操作:
|
索引資料:在事件酬載中傳送。 錄製內容:在 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) 一或多次。系統會將資料從 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 到 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) 一或多次。系統會將資料從 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. 多個圖層的篩選器連結流程圖
調諧器資源管理工具
在 Tuner Resource Manager (TRM) 推出之前,您必須使用相同的 Tuner 硬體,才能在兩個應用程式之間切換。TV Input Framework (TIF) 使用「先取得者勝」機制,也就是說,先取得資源的應用程式就能保留該資源。不過,這項機制可能不適合某些複雜的用途。
TRM 會以系統服務的形式執行,管理應用程式的 Tuner、TVInput
和 CAS 硬體資源。TRM 會使用「前景勝出」機制,根據應用程式的前景或背景狀態和用途類型,計算應用程式的優先順序。TRM 會根據優先順序授予或撤銷資源。TRM 可集中管理廣播、OTT 和 DVR 的 ATV 資源。
TRM 介面
TRM 會在 ITunerResourceManager.aidl
中公開 AIDL 介面,供 Tuner 架構、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
,讓用戶端更新任意優先順序值和 nice 值。任意優先順序值會覆寫系統根據用途類型和工作階段 ID 計算出的優先順序值。
nice 值會指出當用戶端與其他用戶端發生衝突時,用戶端行為的寬鬆程度。在優先順序值與挑戰用戶端進行比較前,nice 值會降低用戶端的優先順序值。
回收機制
下圖顯示發生資源衝突時,如何回收及指派資源。
圖 15. 圖表:Tuner 資源之間發生衝突時的回收機制