調諧器架構

如果是 Android 11 以上版本,您可以使用 Android Tuner 架構來提供 A/V 內容。此架構會使用供應商提供的硬體管道,因此適合用於低階和高階 SoC。此架構提供安全的傳遞方式,可透過受信任的執行環境 (TEE) 和安全媒體路徑 (SMP) 保護影音內容,讓您在受嚴格限制的內容保護環境中使用。

Tuner 和 Android CAS 之間的標準化介面,可加快 Tuner 供應商和 CAS 供應商之間的整合作業。調諧器介面可搭配 MediaCodecAudioTrack 使用,為 Android TV 建構單一世界解決方案。調諧器介面支援數位電視和類比電視,並遵循主要的廣播標準。

元件

針對 Android 11,我們特別設計了三個適用於 TV 平台的元件。

  • Tuner HAL:架構與供應商之間的介面
  • Tuner SDK API:架構和應用程式之間的介面
  • Tuner Resource Manager (TRM):協調 Tuner 硬體資源

針對 Android 11,我們已強化下列元件。

  • CAS V2
  • TvInputService 或 TV 輸入服務 (TIS)
  • TvInputManagerService 或 TV Input Manager Service (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)

Descrambler 支援下列內容保護機制。

  • 安全的媒體路徑
  • 清除媒體路徑
  • 安全的本機記錄
  • 安全的本機播放功能

Tuner API 支援下列用途。

  • 掃描
  • 直播
  • 播放
  • 錄影

Tuner、MediaCodecAudioTrack 支援下列資料流模式。

  • 含有清除記憶體緩衝區的 ES 酬載
  • 含有安全記憶體句柄的 ES 酬載
  • 透視

整體設計

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

  • 說明架構對供應商的期望,以及供應商可能採取的做法。
  • 透過 IFrontendIDemuxIDescramblerIFilterIDvrILnb 介面,將前端、解多工和解密器的功能匯出至架構。
  • 包含用於將 Tuner HAL 與其他架構元件 (例如 MediaCodecAudioTrack) 整合的函式。

系統會建立 Tuner Java 類別和原生類別。

  • Tuner Java API 可讓應用程式透過公開 API 存取 Tuner HAL。
  • 原生類別可透過 Tuner HAL 控制權限,並處理大量錄製或播放資料。
  • 原生 Tuner 模組是 Tuner Java 類別和 Tuner HAL 之間的橋樑。

建立 TRM 類別。

  • 管理有限的調諧器資源,例如前端、LNB、CAS 工作階段,以及電視輸入 HAL 中的電視輸入裝置。
  • 套用規則,從應用程式中回收不足的資源。預設規則是前景勝出。

媒體 CAS 和 CAS HAL 已強化以下功能。

  • 針對不同用途和演算法開啟 CAS 工作階段。
  • 支援動態 CAS 系統,例如 CICAM 移除和插入。
  • 提供金鑰符記,與 Tuner HAL 整合。

MediaCodecAudioTrack 已強化下列功能。

  • 使用安全的 A/V 記憶體做為內容輸入。
  • 已設定在管道式播放中執行硬體 A/V 同步。
  • 已設定支援 ES_payload 和直通模式。

Tuner HAL 的整體設計。

圖 2. Tuner HAL 內元件的圖表

整體工作流程

下圖說明直播播放的呼叫序列。

設定

直播播放圖表的設定順序。

圖 3. 直播播放的設定順序

處理影音

處理直播播放功能的 A/V 圖表。

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

處理經過加密的內容

處理直播播放時的雜訊內容。

圖 5. 處理直播內容的雜訊內容

處理影音資料

處理 A/V 資料,以便播放直播。

圖 6. 處理 A/V 以便播放直播

Tuner 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

調音器套件是使用調音器架構的進入點。TIS 應用程式會使用套件,透過指定初始設定和回呼來初始化及取得資源例項。

  • tuner():指定 useCasesessionId 參數,初始化 Tuner 例項。
  • tune():指定 FrontendSetting 參數,取得前端資源並進行調整。
  • openFilter():指定篩選器類型,取得篩選器例項。
  • openDvrRecorder():指定緩衝區大小,取得錄製例項。
  • openDvrPlayback():透過指定緩衝區大小,取得播放例項。
  • openDescrambler():取得 descrambler 例項。
  • 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 會使用 Tuner.tuneFrontendSettings 填入必要資訊。
  • 如果信號已鎖定,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 掃描程序的流程圖。

圖 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 中填入混合 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

Tuner HAL 會遵循 HIDL,並定義架構與供應商硬體之間的介面。供應商會使用此介面實作 Tuner HAL,而架構會使用此介面與 Tuner HAL 實作項目通訊。

模組

Tuner 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 模組之間互動情形的流程圖。

圖 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

任意優先順序值和好值

TRM 會提供 updateClientPriority,讓用戶端更新任意優先順序值和 nice 值。任意優先順序值會覆寫系統根據用途類型和工作階段 ID 計算出的優先順序值。

nice 值會指出當用戶端與其他用戶端發生衝突時,用戶端行為的寬鬆程度。在優先順序值與挑戰用戶端進行比較前,nice 值會降低用戶端的優先順序值。

回收機制

下圖顯示發生資源衝突時,如何回收及指派資源。

回收機制程序的圖表。

圖 15. 圖表:Tuner 資源之間發生衝突時的回收機制