若為 Android 11 以上版本,您可以使用 Android Tuner 架構來提供 A/V 內容。這個架構使用供應商的硬體管道,因此適用於低端和高階 SoC。這個架構提供安全的 A/V 內容,可安全提供受信任的執行環境 (TEE) 和安全媒體路徑 (SMP) 保護,以便在設有嚴格限制的內容保護環境中使用。
Tuner 與 Android CAS 之間的標準化介面可以加快 Tuner 供應商與 CAS 供應商之間的整合作業。調諧器介面可與 MediaCodec
和 AudioTrack
搭配使用,為 Android TV 建構單一世界解決方案。調諧器介面支援數位電視和類比電視,並依據主要的廣播標準。
元件
在 Android 11 中,三個元件專為電視平台設計。
- Tuner HAL:架構和廠商之間的介面
- Tuner SDK API:架構與應用程式之間的介面
- Tuner Resource Manager (TRM):協調 Tuner 硬體資源
針對 Android 11,我們已強化下列元件。
- CAS V2
TvInputService
或電視輸入服務 (TIS)- 「
TvInputManagerService
」或電視輸入管理員服務 (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 標準。
- 資料移轉
Demux 支援下列串流通訊協定。
- 傳輸串流 (TS)
- MPEG 媒體傳輸通訊協定 (MMTP)
- 網際網路通訊協定 (IP)
- 類型長度值 (TLV)
- ATSC 連結層通訊協定 (ALP)
Descrambler 支援下列內容保護機制。
- 安全的媒體路徑
- 清除媒體路徑
- 安全的本機記錄
- 安全本機播放
Tuner API 支援下列用途。
- 掃描
- 直播
- 播放
- 錄製
Tuner、MediaCodec
和 AudioTrack
支援下列資料流模式。
- 具有清除記憶體緩衝區的 ES 酬載
- 含有安全記憶體句柄的 ES 酬載
- 透視
整體設計
協調器 HAL 是由 Android 架構與供應商硬體定義。
- 說明架構對供應商的期望,以及供應商可能採取的做法。
- 透過
IFrontend
、IDemux
、IDescrambler
、IFilter
、IDvr
和ILnb
介面,將前端、demux 和 descrambler 的功能匯出至架構。 - 包含用於將 Tuner HAL 與其他架構元件 (例如
MediaCodec
和AudioTrack
) 整合的函式。
系統會建立 Tuner Java 類別和原生類別。
- Tuner Java API 可讓應用程式透過公開 API 存取 Tuner HAL。
- 原生類別可透過 Tuner HAL 控制權限,並處理大量錄製或播放資料。
- Native Tuner 模組是 Tuner Java 類別與 Tuner HAL 之間的橋樑。
建立 TRM 類別。
- 管理有限的調諧器資源,例如前端、LNB、CAS 工作階段,以及電視輸入 HAL 中的電視輸入裝置。
- 套用規則來收回應用程式不足的資源。預設規則為前景勝出。
媒體 CAS 和 CAS HAL 已強化以下功能。
- 開啟不同用法和演算法的 CAS 工作階段。
- 支援動態 CAS 系統,例如 CICAM 移除和插入。
- 提供金鑰權杖,與調諧器 HAL 整合。
使用下列功能強化 MediaCodec
和 AudioTrack
。
- 使用安全的 A/V 記憶體做為內容輸入來源。
- 已設定在管道播放中執行硬體 A/V 同步。
- 設定對
ES_payload
和直通模式的支援。
圖 2. 調諧器 HAL 內的元件圖表
整體工作流程
下圖說明直播播放的呼叫序列。
設定
圖 3. 現場直播播放的設定順序
處理 A/V
圖 4. 處理直播播放的 A/V 內容
處理經過加密的內容
圖 5. 處理直播內容的雜訊內容
正在處理影音設備資料
圖 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 HAL 1.1 中的新功能,這是 Tuner 1.0 的回溯相容性版本升級。
使用下列 API 檢查執行中的 HAL 版本。
android.media.tv.tuner.TunerVersionChecker.getTunerVersion()
您可以參閱新版 Android 12 API 的說明文件,瞭解需要的最低 HAL 版本。
套件
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
Tuner 套件是使用 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
前端套件包含前端相關設定、資訊、狀態、事件和功能的集合。
類別
下列類別依不同的 DTV 標準衍生 FrontendSettings
。
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 會為 HAL 呼叫
Tuner.scan
,以相同的頻率繼續下一個設定。 如果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 的流程
- 開啟、設定及啟動影音濾鏡。
- 處理
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
調諧器 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 、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 |
調諧器 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. 多個圖層的篩選器連結流程圖
調諧器資源管理工具
在 Tuner Resource Manager (TRM) 推出之前,您必須使用相同的 Tuner 硬體,才能在兩個應用程式之間切換。電視輸入架構 (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
,讓用戶端更新任意優先順序值和良好值。任意優先順序值會覆寫系統根據用途類型和工作階段 ID 計算出的優先順序值。
nice 值會指出當用戶端與其他用戶端發生衝突時,用戶端行為的寬鬆程度。在優先順序值與挑戰用戶端進行比較前,nice 值會降低用戶端的優先順序值。
回收機制
下圖顯示發生資源衝突時,系統如何收回及指派資源。
圖 15. 圖表:Tuner 資源之間發生衝突時的回收機制