튜너 프레임워크

Android 11 이상에서는 Android Tuner 프레임워크를 사용하여 A/V 콘텐츠를 전달할 수 있습니다. 프레임워크는 공급업체의 하드웨어 파이프라인을 사용하므로 로우엔드 및 하이엔드 SoC 모두에 적합합니다. 프레임워크는 TEE(신뢰할 수 있는 실행 환경) 및 SMP(보안 미디어 경로)로 보호되는 A/V 콘텐츠를 제공하는 안전한 방법을 제공하여 매우 제한된 콘텐츠 보호 환경에서 사용할 수 있습니다.

Tuner와 Android CAS 간의 표준화된 인터페이스를 통해 Tuner 공급업체와 CAS 공급업체 간의 통합이 더 빨라졌습니다. Tuner 인터페이스는 MediaCodecAudioTrack 과 함께 작동하여 Android TV를 위한 원월드 솔루션을 구축합니다. 튜너 인터페이스는 주요 방송 표준을 기반으로 디지털 TV와 아날로그 TV를 모두 지원합니다.

구성품

Android 11의 경우 세 가지 구성 요소가 TV 플랫폼을 위해 특별히 설계되었습니다.

  • Tuner HAL: 프레임워크와 공급업체 간의 인터페이스
  • Tuner SDK API: 프레임워크와 앱 간의 인터페이스
  • TRM(튜너 리소스 관리자): Tuner HW 리소스를 조정합니다.

Android 11의 경우 다음 구성 요소가 향상되었습니다.

  • CAS V2
  • TvInputService 또는 TIS(TV 입력 서비스)
  • TvInputManagerService 또는 TIMS(TV 입력 관리자 서비스)
  • 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 표준을 지원합니다.

  • DTMB

Demux는 아래의 스트림 프로토콜을 지원합니다.

  • 전송 스트림(TS)
  • MPEG 미디어 전송 프로토콜(MMTP)
  • 인터넷 프로토콜(IP)
  • 유형 길이 값(TLV)
  • ATSC 링크 계층 프로토콜(ALP)

디스크램블러는 아래의 콘텐츠 보호를 지원합니다.

  • 보안 미디어 경로
  • 미디어 경로 지우기
  • 안전한 로컬 기록
  • 안전한 로컬 재생

Tuner API는 아래의 사용 사례를 지원합니다.

  • 주사
  • 살다
  • 재생
  • 기록

Tuner, MediaCodecAudioTrack 은 아래의 데이터 흐름 모드를 지원합니다.

  • 명확한 메모리 버퍼가 있는 ES 페이로드
  • 보안 메모리 핸들이 있는 ES 페이로드
  • 지나가 다

전체적인 디자인

Tuner HAL은 Android 프레임워크와 공급업체의 하드웨어 간에 정의됩니다.

  • 프레임워크가 벤더에게 기대하는 것과 벤더가 이를 수행하는 방법을 설명합니다.
  • IFrontend , IDemux , IDescrambler , IFilter , IDvrILnb 인터페이스를 통해 프론트엔드, demux 및 디스크램블러의 기능을 프레임워크로 내보냅니다.
  • Tuner HAL을 MediaCodecAudioTrack 과 같은 다른 프레임워크 구성요소와 통합하는 기능을 포함합니다.

Tuner Java 클래스와 네이티브 클래스가 생성됩니다.

  • Tuner Java API를 사용하면 앱에서 공개 API를 통해 Tuner HAL에 액세스할 수 있습니다.
  • 네이티브 클래스를 사용하면 Tuner HAL을 사용하여 많은 양의 녹음 또는 재생 데이터에 대한 권한 제어 및 처리가 가능합니다.
  • Native Tuner 모듈은 Tuner Java 클래스와 Tuner HAL 사이의 다리입니다.

TRM 클래스가 생성됩니다.

  • TV 입력 HAL에서 Frontend, LNB, CAS 세션 및 TV 입력 장치와 같은 제한된 튜너 리소스를 관리합니다.
  • 앱에서 부족한 리소스를 회수하는 규칙을 적용합니다. 기본 규칙은 전경 승리입니다.

미디어 CAS 및 CAS HAL은 아래 기능으로 향상되었습니다.

  • 다양한 용도 및 알고리즘에 대한 CAS 세션을 엽니다.
  • CICAM 제거 및 삽입과 같은 동적 CAS 시스템을 지원합니다.
  • 키 토큰을 제공하여 튜너 HAL과 통합합니다.

MediaCodecAudioTrack 은 아래 기능으로 향상되었습니다.

  • 보안 A/V 메모리를 콘텐츠 입력으로 사용합니다.
  • 터널링된 재생에서 하드웨어 A/V 동기화를 수행하도록 구성되었습니다.
  • ES_payload 및 통과 모드에 대한 지원을 구성했습니다.

튜너 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 앱은 튜너 SDK API를 사용하여 필터 및 디스크램블러와 같은 튜너 리소스 및 하위 구성 요소에 액세스합니다. Frontend와 demux는 내부 구성 요소입니다.

Tuner SDK API의 흐름도.

그림 7. Tuner SDK API와의 상호 작용

버전

Android 12부터 Tuner SDK API는 Tuner 1.0의 이전 버전과 호환되는 버전 업그레이드인 Tuner HAL 1.1의 새로운 기능을 지원합니다.

다음 API를 사용하여 실행 중인 HAL 버전을 확인하십시오.

  • android.media.tv.tuner.TunerVersionChecker.getTunerVersion()

최소 필수 HAL 버전은 새로운 Android 12 API 문서에서 찾을 수 있습니다.

패키지

Tuner SDK API는 아래 4가지 패키지를 제공합니다.

  • 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 프레임워크를 사용하기 위한 진입점입니다. TIS 앱은 패키지를 사용하여 초기 설정 및 콜백을 지정하여 리소스 인스턴스를 초기화하고 획득합니다.

  • tuner() : useCasesessionId 매개변수를 지정하여 Tuner 인스턴스를 초기화합니다.
  • tune() : 프런트엔드 리소스를 획득하고 FrontendSetting 매개변수를 지정하여 조정합니다.
  • openFilter() : 필터 유형을 지정하여 필터 인스턴스를 가져옵니다.
  • openDvrRecorder() : 버퍼 크기를 지정하여 녹화 인스턴스를 획득합니다.
  • openDvrPlayback() : 버퍼 크기를 지정하여 재생 인스턴스를 획득합니다.
  • openDescrambler() : 디스크램블러 인스턴스를 획득합니다.
  • openLnb() : 내부 LNB 인스턴스를 획득합니다.
  • openLnbByName() : 외부 LNB 인스턴스를 획득합니다.
  • openTimeFilter() : 시간 필터 인스턴스를 가져옵니다.

튜너 패키지는 필터, 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 을 사용하여 프론트엔드의 스캔 메시지를 처리합니다.

채널 스캔

TV를 설정하기 위해 앱은 가능한 주파수를 스캔하고 사용자가 액세스할 수 있는 채널 라인업을 구축합니다. TIS는 Tuner.tune , Tuner.scan(BLIND_SCAN) 또는 Tuner.scan(AUTO_SCAN) 을 사용하여 채널 스캔을 완료할 수 있습니다.

TIS에 주파수, 표준(예: T/T2, S/S2) 및 추가 필요한 정보(예: PLD ID)와 같은 신호에 대한 정확한 전달 정보가 있는 경우 Tuner.tune 이 더 빠른 옵션으로 권장됩니다. .

사용자가 Tuner.tune 을 호출하면 다음 작업이 발생합니다.

  • TIS는 Tuner.tune 을 사용하여 필요한 정보로 FrontendSettings 를 채웁니다.
  • 신호가 잠긴 경우 HAL은 tune 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는 주파수로 채워진 FrontendSettings 와 함께 Tuner.scan(AUTO_SCAN) 을 사용합니다.

  • 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
해당 없음 필수: 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에서 클라이언트 버퍼로 복사됩니다.
인덱스 데이터의 경우: 이벤트 페이로드에서 전달됩니다.

녹화된 콘텐츠의 경우: 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로 채워진 Muxed 녹화 스트림.

기록을 위한 필터 소스가 통과가 있는 TLV.TLV 에서 IP.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

DvrSettingsDvrRecorderDvrPlayback 을 구성하는 데 사용됩니다. OnPlaybackStatusChangedListenerOnRecordStatusChangedListener 는 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을 따르고 프레임워크와 공급업체 하드웨어 간의 인터페이스를 정의합니다. 공급업체는 인터페이스를 사용하여 튜너 HAL을 구현하고 프레임워크는 이를 사용하여 튜너 HAL 구현과 통신합니다.

모듈

튜너 HAL 1.0

모듈 기본 컨트롤 모듈별 컨트롤 HAL 파일
ITuner 해당 없음 frontend(open, getIds, getInfo) , openDemux , openDescrambler , openLnb , getDemuxCaps 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 close , start , stop , configure attach/detachFilters , flush , getQueueDesc IDvr.hal
IDvrCallback.hal
IFilter close , start , stop , configure , getId flush , getQueueDesc , releaseAvHandle , setDataSource IFilter.hal
IFilterCallback.hal
ILnb close , setCallback 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_1 , scan_1_1 , getStatusExt1_1 link/unlinkCiCam @1.1::IFrontend.hal
@1.1::IFrontendCallback.hal
IFilter getStatusExt1_1 configureIpCid , configureAvStreamType , getAvSharedHandle , configureMonitorEvent @1.1::IFilter.hal
@1.1::IFilterCallback.hal

튜너 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. 여러 레이어에 대한 필터 연결의 흐름도

튜너 리소스 관리자

TRM(튜너 리소스 관리자) 이전에는 두 앱 간에 전환할 때 동일한 튜너 하드웨어가 필요했습니다. TIF(TV 입력 프레임워크)는 "먼저 획득 승리" 메커니즘을 사용했습니다. 즉, 리소스를 먼저 얻는 앱이 리소스를 유지합니다. 그러나 이 메커니즘은 일부 복잡한 사용 사례에 적합하지 않을 수 있습니다.

TRM은 앱의 Tuner, TVInput 및 CAS 하드웨어 리소스를 관리하는 시스템 서비스로 실행됩니다. TRM은 앱의 포그라운드 또는 백그라운드 상태와 사용 사례 유형을 기반으로 앱의 우선 순위를 계산하는 "포그라운드 승리" 메커니즘을 사용합니다. TRM은 우선 순위에 따라 리소스를 부여하거나 취소합니다. TRM은 방송, OTT 및 DVR에 대한 ATV 리소스 관리를 중앙 집중화합니다.

TRM 인터페이스

TRM은 튜너 프레임워크, MediaCasTvInputHardwareManager 에 대한 ITunerResourceManager.aidl 의 AIDL 인터페이스를 노출하여 리소스를 등록, 요청 또는 해제합니다.

클라이언트 관리를 위한 인터페이스는 다음과 같습니다.

  • 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를 검색하여 앱이 포그라운드 또는 백그라운드 앱인지 결정합니다. mTvInputSessionId , TvInputService.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 를 따라야 합니다.

임의의 우선순위 값과 좋은 값

TRM은 클라이언트가 임의의 우선순위 값과 nice 값을 업데이트할 수 있도록 updateClientPriority 를 ​​제공합니다. 임의의 우선 순위 값은 사용 사례 유형 및 세션 ID에서 계산된 우선 순위 값을 덮어씁니다.

nice 값은 클라이언트가 다른 클라이언트와 충돌할 때 클라이언트의 행동이 얼마나 관대한지를 나타냅니다. nice 값은 우선 순위 값이 도전적인 클라이언트와 비교되기 전에 클라이언트의 우선 순위 값을 줄입니다.

회수 메커니즘

아래 다이어그램은 리소스 충돌이 발생할 때 리소스가 회수되고 할당되는 방법을 보여줍니다.

회수 메커니즘 프로세스의 다이어그램.

그림 15. Tuner 리소스 간의 충돌에 대한 회수 메커니즘 다이어그램