調諧器架構

若為 Android 11 以上版本,您可以使用 Android Tuner 架構來提供 A/V 內容。這個架構使用供應商的硬體管道,因此適用於低端和高階 SoC。這個架構提供安全的 A/V 內容,可安全提供受信任的執行環境 (TEE) 和安全媒體路徑 (SMP) 保護,以便在設有嚴格限制的內容保護環境中使用。

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

元件

在 Android 11 中,三個元件專為電視平台設計。

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

針對 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 標準。

  • 資料移轉

Demux 支援下列串流通訊協定。

  • 傳輸串流 (TS)
  • MPEG 媒體傳輸通訊協定 (MMTP)
  • 網際網路通訊協定 (IP)
  • 類型長度值 (TLV)
  • ATSC 連結層通訊協定 (ALP)

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

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

Tuner API 支援下列用途。

  • 掃描
  • 直播
  • 播放
  • 錄製

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

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

整體設計

協調器 HAL 是由 Android 架構與供應商硬體定義。

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

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

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

建立 TRM 類別。

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

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

  • 開啟不同用法和演算法的 CAS 工作階段。
  • 支援動態 CAS 系統,例如 CICAM 移除和插入。
  • 提供金鑰權杖,與調諧器 HAL 整合。

使用下列功能強化 MediaCodecAudioTrack

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

Tuner HAL 的整體設計。

圖 2. 調諧器 HAL 內的元件圖表

整體工作流程

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

設定

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

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

處理 A/V

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

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

處理經過加密的內容

處理直播播放圖表的打散內容。

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

正在處理影音設備資料

處理現場直播播放的 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()

您可以參閱新版 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():取得 descrambler 例項。
  • openLnb():取得內部 LNB 執行個體。
  • openLnbByName():取得外部 LNB 例項。
  • openTimeFilter():取得時間篩選器執行個體。

Tuner 套件提供不包含在篩選器、DVR 和前端套件的功能。以下列出這些功能。

  • cancelTuning
  • scan/cancelScanning
  • getAvSyncHwId
  • getAvSyncTime
  • connectCiCam1/disconnectCiCam
  • shareFrontendFromTuner
  • updateResourcePriority
  • setOnTuneEventListener
  • setResourceLostListener

Android.media.tv.tuner.frontend

前端套件包含前端相關設定、資訊、狀態、事件和功能的集合。

類別

下列類別依不同的 DTV 標準衍生 FrontendSettings

  • 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 會為 HAL 呼叫 Tuner.scan,以相同的頻率繼續下一個設定。 如果 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. 開啟、設定及啟動影音濾鏡。
  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

調諧器 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

調諧器 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 硬體,才能在兩個應用程式之間切換。電視輸入架構 (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,讓用戶端更新任意優先順序值和良好值。任意優先順序值會覆寫系統根據用途類型和工作階段 ID 計算出的優先順序值。

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

回收機制

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

回收機制程序的圖表。

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