調諧器框架

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

Tuner 和 Android CAS 之間的標準化接口導致 Tuner 供應商和 CAS 供應商之間的集成更快。 Tuner 界面與MediaCodecAudioTrack一起使用,為 Android TV 構建了一個統一的解決方案。 Tuner 接口支持基於主要廣播標準的數字電視和模擬電視。

成分

對於 Android 11,三個組件是專門為電視平台設計的。

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

對於 Android 11,以下組件已得到增強。

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

Tuner 框架組件的流程圖。

圖 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、 MediaCodecAudioTrack支持以下數據流模式。

  • 具有清除內存緩衝區的 ES 有效負載
  • 具有安全內存句柄的 ES 有效負載
  • 直通

整體設計

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

  • 描述框架對供應商的期望以及供應商如何做到這一點。
  • 通過IFrontendIDemuxIDescramblerIFilterIDvrILnb接口將前端、解復用器和解擾器的功能導出到框架。
  • 包括將 Tuner HAL 與其他框架組件(例如MediaCodecAudioTrack )集成的功能。

創建了 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 集成。

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

  • 將安全的 A/V 內存作為內容輸入。
  • 配置為在隧道播放中進行硬件 A/V 同步。
  • 配置了對ES_payload和直通模式的支持。

Tuner HAL 的整體設計。

圖 2. Tuner HAL 中的組件圖

整體工作流程

下圖說明了直播回放的調用順序。

設置

直播回放圖設置順序。

圖 3.直播回放的設置順序

處理 A/V

處理直播播放圖的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 資源和子組件,例如過濾器和解擾器。 Frontend 和 demux 是內部組件。

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()

可以在新的 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

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() :獲取時間過濾器實例。

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.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調用。

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()來暫停或結束掃描。

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頭的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 中填充的 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++
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.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:
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);
          }
        }
      };
    

調諧器 HAL

Tuner HAL 遵循 HIDL 並定義框架和供應商硬件之間的接口。供應商使用該接口來實現 Tuner HAL,框架使用它與 Tuner HAL 實現進行通信。

模塊

調諧器 HAL 1.0

模塊基本控制特定於模塊的控件HAL 文件
ITuner不適用frontend(open, getIds, getInfo)openDemuxopenDescrambleropenLnbgetDemuxCaps 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 closestartstopconfigure attach/detachFiltersflushgetQueueDesc IDvr.hal
IDvrCallback.hal
IFilter closestartstopconfiguregetId flushgetQueueDescreleaseAvHandlesetDataSource IFilter.hal
IFilterCallback.hal
ILnb closesetCallback 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_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 支持過濾器鏈接,以便過濾器可以鏈接到多個層的其他過濾器。過濾器遵循以下規則。

  • 過濾器以樹的形式鏈接,不允許關閉路徑。
  • 根節點是 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 框架、 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 值表示當客戶端與另一個客戶端發生衝突時,客戶端的行為有多寬容。在將客戶端的優先級值與具有挑戰性的客戶端進行比較之前,nice 值會降低客戶端的優先級值。

回收機制

下圖顯示了發生資源衝突時如何回收和分配資源。

回收機制流程示意圖。

圖 15. Tuner 資源衝突的回收機制示意圖