對於 Android 11 或更高版本,您可以使用 Android Tuner 框架來提供 A/V 內容。該框架使用供應商的硬件管道,使其適用於低端和高端 SoC。該框架提供了一種安全的方式來交付受信任的執行環境 (TEE) 和安全媒體路徑 (SMP) 保護的 A/V 內容,使其能夠在高度受限的內容保護環境中使用。
Tuner 和 Android CAS 之間的標準化接口導致 Tuner 供應商和 CAS 供應商之間的集成更快。 Tuner 界面與MediaCodec
和AudioTrack
一起使用,為 Android TV 構建了一個統一的解決方案。 Tuner 接口支持基於主要廣播標準的數字電視和模擬電視。
成分
對於 Android 11,三個組件是專門為電視平台設計的。
- Tuner HAL:框架和供應商之間的接口
- Tuner SDK API:框架和應用程序之間的接口
- 調諧器資源管理器 (TRM):協調調諧器硬件資源
對於 Android 11,以下組件已得到增強。
- CAS V2
-
TvInputService
或電視輸入服務 (TIS) -
TvInputManagerService
或電視輸入管理器服務 (TIMS) -
MediaCodec
或媒體編解碼器 AudioTrack
或音軌MediaResourceManager
或媒體資源管理器 (MRM)
圖 1. Android TV 組件之間的交互
特徵
前端支持以下 DTV 標準。
- 空中交通管制委員會
- 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)
解擾器支持以下內容保護。
- 安全的媒體路徑
- 清除媒體路徑
- 安全的本地記錄
- 安全的本地播放
調諧器 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 對大量錄製或播放數據進行權限控制和處理。
- Native Tuner 模塊是 Tuner Java 類和 Tuner HAL 之間的橋樑。
創建了一個 TRM 類。
- 管理有限的調諧器資源,例如前端、LNB、CAS 會話和來自 TV 輸入 HAL 的 TV 輸入設備。
- 應用規則從應用程序中回收不足的資源。默認規則是前台獲勝。
媒體 CAS 和 CAS HAL 通過以下功能得到增強。
- 為不同的用途和算法打開 CAS 會話。
- 支持動態 CAS 系統,例如 CICAM 移除和插入。
- 通過提供密鑰令牌與 Tuner 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 資源和子組件,例如過濾器和解擾器。 Frontend 和 demux 是內部組件。
圖 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()
:獲取解擾器實例。 -
openLnb()
:獲取內部 LNB 實例。 -
openLnbByName()
:獲取外部 LNB 實例。 -
openTimeFilter()
:獲取時間過濾器實例。
Tuner 包提供了過濾器、DVR 和前端包中未涵蓋的功能。下面列出了這些功能。
-
cancelTuning
-
scan
/cancelScanning
掃描 getAvSyncHwId
-
getAvSyncTime
- 連接
connectCiCam1
/disconnectCiCam
CiCam -
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 沒有頻率列表,並且 Vendor HAL 可以搜索用戶指定前端的頻率以獲取前端資源,則建議使用Tuner.scan(BLIND_SCAN)
。
- TIS 使用
Tuner.scan(BLIND_SCAN)
。可以在FrontendSettings
中為開始頻率指定頻率,但 TIS 會忽略FrontendSettings
中的其他設置。 - 如果信號被鎖定,HAL 會報告一個 scan
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 中填充的 Muxed 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 to IP.IP with passthrough,則錄製的流有一個 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); } } };
調諧器 HAL
Tuner 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 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.多層過濾器鏈接流程圖
調諧器資源管理器
在 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
。
任意優先級值和nice值
TRM 提供updateClientPriority
供客戶端更新任意優先級值和nice 值。任意優先級值會覆蓋根據用例類型和會話 ID 計算的優先級值。
nice 值表示當客戶端與另一個客戶端發生衝突時,客戶端的行為有多寬容。在將客戶端的優先級值與具有挑戰性的客戶端進行比較之前,nice 值會降低客戶端的優先級值。
回收機制
下圖顯示了發生資源衝突時如何回收和分配資源。
圖 15. Tuner 資源衝突的回收機制示意圖