調諧器框架

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

Tuner 和 Android CAS 之間的標準化接口可以加快 Tuner 供應商和 CAS 供應商之間的集成。該調諧器接口採用MediaCodecAudioTrack來構建Android電視的一個全球的解決方案。調諧器接口支持基於主要廣播標準的數字電視和模擬電視。

成分

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

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

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

  • CAS V2
  • TvInputService或TV輸入服務(TIS)
  • TvInputManagerService或TV輸入管理服務(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 支持以下用例。

  • 掃描
  • 居住
  • 回放
  • 記錄

調諧器, MediaCodecAudioTrack支持數據流下面模式。

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

整體設計

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

  • 描述框架對供應商的期望以及供應商如何做到這一點。
  • 出口前端,解复用和解擾器的功能通過框架IFrontendIDemuxIDescramblerIFilterIDvrILnb接口。
  • 包括對調諧器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.調諧器HAL內的組件的框圖

整體工作流程

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

設置

直播回放圖設置順序。

對於直播回放圖3.安裝序列

處理 A/V

處理 A/V 用於直播播放圖。

圖4.處理A / V對於實況廣播播放

處理加擾內容

處理直播播放圖的加擾內容。

圖5.處理衛星直播回放亂內容

處理 A/V 數據

處理 A/V 數據用於直播播放圖。

圖6.處理A / V對於實況廣播播放

調諧器 SDK API

該調諧器SDK API處理與調諧器JNI,調諧器HAL和互動TunerResourceManager 。 TIS 應用程序使用 Tuner SDK API 來訪問 Tuner 資源和子組件,例如過濾器和解擾器。 Frontend 和 demux 是內部組件。

Tuner SDK API 的流程圖。

圖7.互動與調諧器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.調諧器SDK API包

Android.media.tv.tuner

Tuner 包是使用 Tuner 框架的入口點。 TIS 應用程序使用包通過指定初始設置和回調來初始化和獲取資源實例。

  • tuner()初始化通過指定一個調諧器實例useCasesessionId參數。
  • tune()獲取由指定一個前端資源和調諧FrontendSetting參數。
  • openFilter()通過指定濾波器類型獲取一個過濾器實例。
  • openDvrRecorder()通過指定緩衝區大小獲取一個記錄實例。
  • openDvrPlayback()通過指定緩衝區大小獲取一個播放實例。
  • openDescrambler()獲取一個解擾器的實例。
  • openLnb()獲取到一個內部LNB實例。
  • openLnbByName()獲取到一個外部LNB實例。
  • openTimeFilter()獲取一個時間濾波器實例。

Tuner 包提供了過濾器、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填充FrontendSettings使用所需的信息Tuner.tune
  • 該報告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不具有頻率列表和賣方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 掃描過程的流程圖。

一個TIS掃描的圖9流程圖

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 複製到客戶端緩衝區。
濾出tsts
填入FMQ。
TS.Audio
TS.Video
MMTP.Audio
MMTP.Video
isPassthrough:
true
可選的:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
客戶端可以啟動MediaCodec接收後DemuxFilterStatus::DATA_READY
客戶端可以調用Filter.flush接收後DemuxFilterStatus::DATA_OVERFLOW
不適用
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))
ES 或 ION 內存中的部分 ES 數據。
TS.PCR
IP.NTP
ALP.PTP
不適用強制性:N / A
可選:N / A
不適用不適用
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 複製到客戶端緩衝區。
對於指標數據:在開展事件負載。

對於錄製的內容:多路復用的TS流填充FMQ。
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 複製到客戶端緩衝區。
過濾掉mmtpmmtp
填入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);
          }
        }
      };
    

調諧器 HAL

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

模塊

調諧器 HAL 1.0

模塊基本控制特定於模塊的控件HAL 文件
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)

模塊基本控件特定於模塊的控件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 模塊之間的交互流程圖。

調諧器模塊HAL之間的相互作用的圖13.

過濾器聯動

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被視為一個系統服務來管理的調諧器, TVInput和CAS硬件資源的應用程序。 TRM 使用“前台獲勝”機制,該機制根據應用程序的前台或後台狀態和用例類型計算應用程序的優先級。 TRM 根據優先級授予或撤銷資源。 TRM 集中管理廣播、OTT 和 DVR 的 ATV 資源。

TRM接口

TRM自曝AIDL接口在ITunerResourceManager.aidl為調諧器框架, 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檢索來自進程ID mTvInputSessionId來決定應用程序是否是前景或背景的應用程序。要創建mTvInputSessionIdTvInputService.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