對於 Android 11 或更高版本,您可以使用 Android Tuner 框架來傳送 A/V 內容。該框架使用供應商的硬體管道,使其適用於低端和高端 SoC。該框架提供了一種安全的方式來交付受可信任執行環境 (TEE) 和安全媒體路徑 (SMP) 保護的 A/V 內容,使其可以在高度受限的內容保護環境中使用。
Tuner 和 Android CAS 之間的標準化介面可讓 Tuner 供應商和 CAS 供應商之間的整合更快。 Tuner 介面與MediaCodec
和AudioTrack
配合使用,為 Android TV 建構一個統一的解決方案。調諧器介面支援基於主要廣播標準的數位電視和類比電視。
成分
對於 Android 11,三個元件是專門為 TV 平台設計的。
- Tuner HAL:框架與供應商之間的介面
- Tuner SDK API:框架和應用程式之間的接口
- 調諧器資源管理器 (TRM):協調調諧器硬體資源
對於 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 標準。
- 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。
- Native 類別允許使用 Tuner HAL 進行權限控制和處理大量記錄或播放資料。
- Native Tuner 模組是 Tuner Java 類別和 Tuner HAL 之間的橋樑。
TRM 類別已建立。
- 管理有限的調諧器資源,例如前端、LNB、CAS 會話和電視輸入 HAL 中的電視輸入裝置。
- 應用規則從應用程式回收不足的資源。預設規則是前台獲勝。
Media CAS 和 CAS HAL 透過以下功能增強。
- 開啟不同用途和演算法的 CAS 會話。
- 支援動態 CAS 系統,例如 CICAM 刪除和插入。
- 透過提供密鑰令牌與 Tuner HAL 整合。
MediaCodec
和AudioTrack
透過以下功能得到增強。
- 採用安全的 A/V 記憶體作為內容輸入。
- 配置為在隧道播放中進行硬體 A/V 同步。
- 配置了對
ES_payload
和 passthrough 模式的支援。
圖 2. Tuner HAL 內的組件圖
整體工作流程
下圖說明了直播回放的呼叫順序。
設定
圖 3.直播回放設定順序
處理音訊/視訊
圖 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 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
Tuner 套件是使用 Tuner 框架的入口點。 TIS 應用程式使用該套件透過指定初始設定和回調來初始化和取得資源實例。
-
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)
來完成頻道掃描。
如果 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
呼叫。
調諧器.掃描(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()
來暫停或結束掃描。
調諧器.掃描(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) 一次或多次。資料從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 header 濾掉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 遵循 HIDL,定義框架和供應商硬體之間的介面。供應商使用該介面來實作 Tuner HAL,框架使用它與 Tuner HAL 實作進行通訊。
模組
調諧器 HAL 1.0
模組 | 基本控制 | 模組特定的控件 | 哈爾文件 |
---|---|---|---|
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)
模組 | 基本控制 | 模組特定的控件 | 哈爾文件 |
---|---|---|---|
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 支援過濾器鏈接,以便過濾器可以鏈接到多個層的其他過濾器。過濾器遵循以下規則。
- 過濾器作為樹鏈接,不允許閉合路徑。
- 根節點是解復用器。
- 過濾器獨立運作。
- 所有過濾器開始取得資料。
- 過濾器連桿沖洗最後一個過濾器。
下面的程式碼區塊和圖 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 輸入框架 (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 值會降低客戶端的優先值。
回收機制
下圖展示了發生資源衝突時如何回收和分配資源。
圖 15. Tuner 資源之間衝突的回收機製圖