調諧器框架

對於 Android 11 或更高版本,您可以使用 Android Tuner 框架來傳送 A/V 內容。該框架使用供應商的硬體管道,使其適用於低端和高端 SoC。該框架提供了一種安全的方式來交付受可信任執行環境 (TEE) 和安全媒體路徑 (SMP) 保護的 A/V 內容,使其可以在高度受限的內容保護環境中使用。

Tuner 和 Android CAS 之間的標準化介面可讓 Tuner 供應商和 CAS 供應商之間的整合更快。 Tuner 介面與MediaCodecAudioTrack配合使用,為 Android TV 建構一個統一的解決方案。調諧器介面支援基於主要廣播標準的數位電視和類比電視。

成分

對於 Android 11,三個元件是專門為 TV 平台設計的。

  • Tuner HAL:框架與供應商之間的介面
  • Tuner SDK API:框架和應用程式之間的接口
  • 調諧器資源管理器 (TRM):協調調諧器硬體資源

對於 Android 11,以下元件已增強。

  • CAS V2
  • TvInputService或電視輸入服務 (TIS)
  • TvInputManagerService或電視輸入管理器服務 (TIMS)
  • MediaCodec或媒體編解碼器
  • AudioTrack或音軌
  • MediaResourceManager或媒體資源管理器 (MRM)

Tuner 框架組件的流程圖。

圖 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、 MediaCodecAudioTrack支援以下資料流模式。

  • 具有清除記憶體緩衝區的 ES 有效負載
  • 具有安全記憶體句柄的 ES 有效負載
  • 直通

整體設計

Tuner HAL 是在 Android 框架和供應商硬體之間定義的。

  • 描述框架對供應商的期望以及供應商如何做到這一點。
  • 透過IFrontendIDemuxIDescramblerIFilterIDvrILnb介面將前端、解復用器和解擾器的功能匯出到框架。
  • 包括將 Tuner HAL 與其他框架組件整合的功能,例如MediaCodecAudioTrack

建立 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 整合。

MediaCodecAudioTrack透過以下功能得到增強。

  • 採用安全的 A/V 記憶體作為內容輸入。
  • 配置為在隧道播放中進行硬體 A/V 同步。
  • 配置了對ES_payload和 passthrough 模式的支援。

Tuner HAL 的整體設計。

圖 2. Tuner HAL 內的組件圖

整體工作流程

下圖說明了直播回放的呼叫順序。

設定

設定直播播放圖順序。

圖 3.直播回放設定順序

處理音訊/視訊

處理直播播放圖的 A/V。

圖 4.處理直播播放的 A/V

處理亂碼內容

處理直播播放圖的亂碼內容。

圖 5.處理直播播放的加擾內容

處理 A/V 數據

處理直播回放圖的A/V數據。

圖 6.處理直播回放的 A/V

調諧器 SDK API

Tuner SDK API 處理與 Tuner JNI、Tuner HAL 和TunerResourceManager的互動。 TIS 應用程式使用 Tuner SDK API 來存取 Tuner 資源和子元件,例如過濾器和解擾器。前端和解復用器是內部元件。

Tuner SDK API 的流程圖。

圖 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

Tuner SDK API 套件的流程圖。

圖 8. Tuner SDK API 包

Android.media.tv.tuner

Tuner 套件是使用 Tuner 框架的入口點。 TIS 應用程式使用該套件透過指定初始設定和回調來初始化和取得資源實例。

  • tuner() :透過指定useCasesessionId參數來初始化 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.tuneTuner.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()來暫停或結束掃描。

TIS 掃描過程的流程圖。

圖 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:
true
強制的:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

受到推崇的:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
根據活動及內部日程安排,運行
Filter.read(buffer, offset, adjustedSize)一次或多次。

資料從HAL的MQ複製到客戶端緩衝區。
一個組裝的會話包由另一個會話包填入 FMQ 中。
isRaw:
false
強制的:
DemuxFilterEvent::DemuxFilterSectionEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

選修的:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterSectionEven[i].size)


資料從HAL的MQ複製到客戶端緩衝區。
TS.PES isRaw:
true
強制的:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

受到推崇的:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
根據活動及內部日程安排,運行
Filter.read(buffer, offset, adjustedSize)一次或多次。

資料從 HAL 的 MQ 複製到客戶端緩衝區。
一個組裝好的 PES 封裝由另一個 PES 封裝填入 FMQ 中。
isRaw:
false
強制的:
DemuxFilterEvent::DemuxFilterPesEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

選修的:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterPesEven[i].size)


資料從HAL的MQ複製到客戶端緩衝區。
MMTP.PES isRaw:
true
強制的:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

受到推崇的:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
根據活動及內部日程安排,運行
Filter.read(buffer, offset, adjustedSize)一次或多次。

資料從 HAL 的 MQ 複製到客戶端緩衝區。
一個組裝好的 MFU 封裝由另一個 MFU 封裝填入 FMQ 中。
isRaw:
false
強制的:
DemuxFilterEvent::DemuxFilterPesEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

選修的:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterPesEven[i].size)


資料從 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:
true
選修的:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
用戶端收到DemuxFilterStatus::DATA_READY後即可啟動MediaCodec
客戶端可以在收到DemuxFilterStatus::DATA_OVERFLOW後呼叫Filter.flush
不適用
isPassthrough:
false
強制的:
DemuxFilterEvent::DemuxFilterMediaEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

選修的:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
使用MediaCodec
for i=0; i<n; i++
linearblock = MediaEvent[i].getLinearBlock();
codec.startQueueLinearBlock(linearblock)
linearblock.recycle()


要使用AudioTrack的直接音訊:
for i=0; i<n; i++
audioHandle = MediaEvent[i].getAudioHandle();
audiotrack.write(encapsulated(audiohandle))
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++
DemuxFilterTsRecordEvent[i];


對於錄製的內容,根據RecordStatus::*和內部計劃,執行以下操作之一:
  • 運行DvrRecord.write(adustedSize)一次或多次以進行儲存。
    資料從HAL的MQ傳輸到儲存。
  • 運行DvrRecord.write(buffer, adustedSize)一次或多次以進行緩衝。
    資料從 HAL 的 MQ 複製到客戶端緩衝區。
對於索引資料:在事件負載中攜帶。

對於錄製內容:填滿 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++
DemuxFilterTemiEvent[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++
DemuxFilterMmtpRecordEvent[i];


對於錄製的內容,根據RecordStatus::*和內部計劃,執行以下操作之一:
  • 運行DvrRecord.write(adjustedSize)一次或多次以進行儲存。
    資料從HAL的MQ傳輸到儲存。
  • 運行DvrRecord.write(buffer, adjustedSize)一次或多次以進行緩衝。
    資料從 HAL 的 MQ 複製到客戶端緩衝區。
對於索引資料:在事件負載中攜帶。

對於錄製內容:填入 FMQ 中的複用錄製串流。

如果錄製的過濾源是TLV.TLVIP.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:
true
選修的:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
過濾掉的協議子流饋送到過濾器鏈中的下一個過濾器。不適用
isPassthrough:
false
強制的:
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 的範例流程

使用過濾器建立 PSI/SI 的範例流程。

圖 10.建構 PSI/SI 的流程

  1. 打開過濾器。

    Filter filter = tuner.openFilter(
      Filter.TYPE_TS,
      Filter.SUBTYPE_SECTION,
      /* bufferSize */1000,
      executor,
      filterCallback
    );
    
  2. 配置並啟動過濾器。

    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();
    
  3. 處理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 的範例流程

使用過濾器中的 MediaEvent 的範例流程。

圖 11.從過濾器使用 MediaEvent 的流程

  1. 開啟、設定和啟動 A/V 過濾器。
  2. 處理MediaEvent
  3. 接收MediaEvent
  4. 將線性區塊排隊到codec
  5. 資料消耗完後釋放 A/V 句柄。

Android.media.tv.tuner.dvr

DvrRecorder提供了這些錄製方法。

  • configure
  • attachFilter
  • detachFilter
  • start
  • flush
  • stop
  • setFileDescriptor
  • write

DvrPlayback提供了這些播放方法。

  • configure
  • start
  • flush
  • stop
  • setFileDescriptor
  • read

DvrSettings用於設定DvrRecorderDvrPlaybackOnPlaybackStatusChangedListenerOnRecordStatusChangedListener用於報告 DVR 實例的狀態。

開始記錄的範例流程

開始記錄的範例流程。

圖 12.開始記錄的流程

  1. 開啟、設定並啟動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();
    
  2. 接收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. }
          }
        }
    };
    
  3. 初始化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)openDemuxopenDescrambleropenLnbgetDemuxCaps ITuner.hal
IFrontend setCallbackgetStatusclose tunestopTunescanstopScansetLnb IFrontend.hal
IFrontendCallback.hal
IDemux close setFrontendDataSourceopenFilteropenDvrgetAvSyncHwIdgetAvSyncTimeconnect / disconnectCiCam IDemux.hal
IDvr closestartstopconfigure attach/detachFiltersflushgetQueueDesc IDvr.hal
IDvrCallback.hal
IFilter closestartstopconfiguregetId flushgetQueueDescreleaseAvHandlesetDataSource IFilter.hal
IFilterCallback.hal
ILnb closesetCallback setVoltagesetTonesetSatellitePositionsendDiseqcMessage ILnb.hal
ILnbCallback.hal
IDescrambler close setDemuxSourcesetKeyTokenaddPidremovePid IDescrambler.hal

Tuner HAL 1.1(源自 Tuner HAL 1.0)

模組基本控制模組特定的控件哈爾文件
ITuner不適用getFrontendDtmbCapabilities @1.1::ITuner.hal
IFrontend tune_1_1scan_1_1getStatusExt1_1 link/unlinkCiCam @1.1::IFrontend.hal
@1.1::IFrontendCallback.hal
IFilter getStatusExt1_1 configureIpCidconfigureAvStreamTypegetAvSharedHandleconfigureMonitorEvent @1.1::IFilter.hal
@1.1::IFilterCallback.hal

Tuner 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 框架、 MediaCasTvInputHardwareManager註冊、請求或釋放資源。

下面列出了客戶端管理的介面。

  • 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 來確定應用程式是前台應用程式還是後台應用程式。要建立mTvInputSessionIdTvInputService.onCreateSessionTvInputService.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 資源之間衝突的回收機製圖