Android 11 이상에서는 Android Tuner 프레임워크를 사용하여 A/V 콘텐츠를 전달할 수 있습니다. 프레임워크는 공급업체의 하드웨어 파이프라인을 사용하므로 로우엔드 및 하이엔드 SoC 모두에 적합합니다. 프레임워크는 TEE(신뢰할 수 있는 실행 환경) 및 SMP(보안 미디어 경로)로 보호되는 A/V 콘텐츠를 제공하는 안전한 방법을 제공하여 매우 제한된 콘텐츠 보호 환경에서 사용할 수 있습니다.
Tuner와 Android CAS 간의 표준화된 인터페이스를 통해 Tuner 공급업체와 CAS 공급업체 간의 통합이 더 빨라졌습니다. Tuner 인터페이스는 MediaCodec
및 AudioTrack
과 함께 작동하여 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, MediaCodec
및 AudioTrack
은 아래의 데이터 흐름 모드를 지원합니다.
- 명확한 메모리 버퍼가 있는 ES 페이로드
- 보안 메모리 핸들이 있는 ES 페이로드
- 지나가 다
전체적인 디자인
Tuner HAL은 Android 프레임워크와 공급업체의 하드웨어 간에 정의됩니다.
- 프레임워크가 벤더에게 기대하는 것과 벤더가 이를 수행하는 방법을 설명합니다.
-
IFrontend
,IDemux
,IDescrambler
,IFilter
,IDvr
및ILnb
인터페이스를 통해 프론트엔드, demux 및 디스크램블러의 기능을 프레임워크로 내보냅니다. - Tuner HAL을
MediaCodec
및AudioTrack
과 같은 다른 프레임워크 구성요소와 통합하는 기능을 포함합니다.
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과 통합합니다.
MediaCodec
및 AudioTrack
은 아래 기능으로 향상되었습니다.
- 보안 A/V 메모리를 콘텐츠 입력으로 사용합니다.
- 터널링된 재생에서 하드웨어 A/V 동기화를 수행하도록 구성되었습니다.
-
ES_payload
및 통과 모드에 대한 지원을 구성했습니다.
그림 2. Tuner HAL 내의 구성 요소 다이어그램
전체 워크플로
아래 다이어그램은 라이브 방송 재생을 위한 호출 시퀀스를 보여줍니다.
설정
그림 3. 생방송 재생을 위한 설정 순서
A/V 처리
그림 4. 라이브 방송 재생을 위한 A/V 처리
스크램블된 콘텐츠 처리
그림 5. 생방송 재생을 위한 스크램블된 콘텐츠 처리
A/V 데이터 처리
그림 6. 생방송 재생을 위한 A/V 처리
튜너 SDK API
Tuner SDK API는 Tuner JNI, Tuner HAL 및 TunerResourceManager
와의 상호 작용을 처리합니다. TIS 앱은 튜너 SDK API를 사용하여 필터 및 디스크램블러와 같은 튜너 리소스 및 하위 구성 요소에 액세스합니다. Frontend와 demux는 내부 구성 요소입니다.
그림 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
그림 8. 튜너 SDK API 패키지
Android.media.tv.튜너
Tuner 패키지는 Tuner 프레임워크를 사용하기 위한 진입점입니다. TIS 앱은 패키지를 사용하여 초기 설정 및 콜백을 지정하여 리소스 인스턴스를 초기화하고 획득합니다.
-
tuner()
:useCase
및sessionId
매개변수를 지정하여 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()
를 호출하여 스캔을 일시 중지하거나 종료할 수 있습니다.
그림 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: | 필수적인:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 추천: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | 행사 및 내부 일정에 따라 진행Filter.read(buffer, offset, adjustedSize) 한 번 이상 수행합니다.데이터는 HAL의 MQ에서 클라이언트 버퍼로 복사됩니다. | 하나의 조립된 세션 패키지는 다른 세션 패키지에 의해 FMQ에 채워집니다. |
isRaw: | 필수적인:DemuxFilterEvent::DemuxFilterSectionEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 선택 과목: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ 데이터는 HAL의 MQ에서 클라이언트 버퍼로 복사됩니다. | ||
TS.PES | isRaw: | 필수적인:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 추천: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | 행사 및 내부 일정에 따라 진행Filter.read(buffer, offset, adjustedSize) 한 번 이상 수행합니다.데이터는 HAL의 MQ에서 클라이언트 버퍼로 복사됩니다. | 하나의 조립된 PES 패키지는 다른 PES 패키지에 의해 FMQ에 채워집니다. |
isRaw: | 필수적인:DemuxFilterEvent::DemuxFilterPesEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 선택 과목: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ 데이터는 HAL의 MQ에서 클라이언트 버퍼로 복사됩니다. | ||
MMTP.PES | isRaw: | 필수적인:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 추천: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | 행사 및 내부 일정에 따라 진행Filter.read(buffer, offset, adjustedSize) 한 번 이상 수행합니다.데이터는 HAL의 MQ에서 클라이언트 버퍼로 복사됩니다. | 하나의 조립된 MFU 패키지는 다른 MFU 패키지에 의해 FMQ에 채워집니다. |
isRaw: | 필수적인:DemuxFilterEvent::DemuxFilterPesEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 선택 과목: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ 데이터는 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: | 선택 과목:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW | 클라이언트는 DemuxFilterStatus::DATA_READY 를 수신한 후 MediaCodec 을 시작할 수 있습니다.클라이언트는 DemuxFilterStatus::DATA_OVERFLOW 를 수신한 후 Filter.flush 를 호출할 수 있습니다. | 해당 없음 |
isPassthrough: | 필수적인:DemuxFilterEvent::DemuxFilterMediaEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW 선택 과목: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | MediaCodec 을 사용하려면:for i=0; i<n; i++ AudioTrack 의 다이렉트 오디오를 사용하려면:for i=0; i<n; i++ | 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++ 녹화된 콘텐츠 의 경우 RecordStatus::* 및 내부 일정에 따라 다음 중 하나를 수행합니다.
| 인덱스 데이터의 경우: 이벤트 페이로드에서 전달됩니다. 녹화된 콘텐츠의 경우: 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++ | 해당 없음 |
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++ 녹화된 콘텐츠 의 경우 RecordStatus::* 및 내부 일정에 따라 다음 중 하나를 수행합니다.
| 인덱스 데이터의 경우: 이벤트 페이로드에서 전달됩니다. 녹화된 콘텐츠의 경우: 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: | 선택 과목:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW | 필터링된 프로토콜 하위 스트림은 필터 체인의 다음 필터를 피드합니다. | 해당 없음 |
isPassthrough: | 필수적인: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를 구축하는 흐름의 예
그림 10. PSI/SI 구축 흐름
필터를 엽니다.
Filter filter = tuner.openFilter( Filter.TYPE_TS, Filter.SUBTYPE_SECTION, /* bufferSize */1000, executor, filterCallback );
필터를 구성하고 시작합니다.
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();
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를 사용하는 흐름의 예
그림 11. 필터에서 MediaEvent를 사용하는 흐름
- A/V 필터를 열고 구성하고 시작합니다.
-
MediaEvent
를 처리합니다. -
MediaEvent
를 수신합니다. - 선형 블록을
codec
에 대기열에 넣습니다. - 데이터가 소비되면 A/V 핸들을 놓습니다.
Android.media.tv.tuner.dvr
DvrRecorder
는 이러한 녹음 방법을 제공합니다.
-
configure
-
attachFilter
-
detachFilter
-
start
-
flush
-
stop
-
setFileDescriptor
-
write
DvrPlayback
은 이러한 재생 방법을 제공합니다.
-
configure
-
start
-
flush
-
stop
-
setFileDescriptor
-
read
DvrSettings
는 DvrRecorder
및 DvrPlayback
을 구성하는 데 사용됩니다. OnPlaybackStatusChangedListener
및 OnRecordStatusChangedListener
는 DVR 인스턴스의 상태를 보고하는 데 사용됩니다.
레코드를 시작하는 흐름의 예
그림 12. 레코드를 시작하는 흐름
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();
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. } } } };
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 |
그림 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은 튜너 프레임워크, MediaCas
및 TvInputHardwareManager
에 대한 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 리소스 간의 충돌에 대한 회수 메커니즘 다이어그램