В Android 11 и выше для доставки аудио- и видеоконтента можно использовать фреймворк Android Tuner. Фреймворк использует аппаратный конвейер от поставщиков, что делает его пригодным как для бюджетных, так и для высокопроизводительных SoC. Фреймворк обеспечивает безопасную доставку аудио- и видеоконтента, защищённого доверенной средой выполнения (TEE) и безопасным медиа-путем (SMP), что позволяет использовать его в строго ограниченной среде защиты контента.
Стандартизированный интерфейс между тюнером и Android CAS обеспечивает более быструю интеграцию между поставщиками тюнеров и поставщиками CAS. Интерфейс тюнера работает с MediaCodec
и AudioTrack
, создавая универсальное решение для Android TV. Интерфейс тюнера поддерживает как цифровое, так и аналоговое телевидение на основе основных стандартов вещания.
Компоненты
В Android 11 три компонента специально разработаны для телевизионной платформы.
- Tuner HAL: интерфейс между фреймворком и поставщиками
- Tuner SDK API: интерфейс между фреймворком и приложениями
- Менеджер ресурсов тюнера (TRM): координирует ресурсы аппаратного обеспечения тюнера
В Android 11 были улучшены следующие компоненты.
- КАС V2
-
TvInputService
или Служба телевизионного ввода (TIS) -
TvInputManagerService
или служба диспетчера телевизионных входов (TIMS) -
MediaCodec
или медиакодек -
AudioTrack
или звуковая дорожка -
MediaResourceManager
или менеджер медиаресурсов (MRM)
Рисунок 1. Взаимодействие между компонентами Android TV
Функции
Интерфейс поддерживает стандарты DTV, указанные ниже.
- АТСК
- ATSC3
- DVB C/S/T
- ISDB S/S3/T
- Аналоговый
Интерфейс Android 12 с Tuner HAL 1.1 или выше поддерживает стандарт DTV, указанный ниже.
- ДТМБ
Demux поддерживает перечисленные ниже потоковые протоколы.
- Транспортный поток (ТС)
- Протокол передачи медиаданных MPEG (MMTP)
- Интернет-протокол (IP)
- Значение длины типа (TLV)
- Протокол канального уровня ATSC (ALP)
Дескремблер поддерживает указанные ниже средства защиты контента.
- Безопасный путь к медиа
- Очистить путь для медиа
- Безопасная локальная запись
- Безопасное локальное воспроизведение
API тюнера поддерживают перечисленные ниже варианты использования.
- Сканировать
- Жить
- Воспроизведение
- Записывать
Tuner, MediaCodec
и AudioTrack
поддерживают указанные ниже режимы потока данных.
- Полезная нагрузка ES с чистым буфером памяти
- Полезная нагрузка ES с защищенным дескриптором памяти
- Сквозной
Общий дизайн
Tuner HAL определяется между платформой Android и оборудованием поставщика.
- Описывает, чего фреймворк ожидает от поставщика и как поставщик может это сделать.
- Экспортирует функциональные возможности фронтенда, демультиплексора и дескремблера в фреймворк через интерфейсы
IFrontend
,IDemux
,IDescrambler
,IFilter
,IDvr
иILnb
. - Включает функции для интеграции Tuner HAL с другими компонентами фреймворка, такими как
MediaCodec
иAudioTrack
.
Создаются класс Tuner Java и собственный класс.
- Tuner Java API позволяет приложениям получать доступ к Tuner HAL через общедоступные API.
- Собственный класс позволяет контролировать разрешения и обрабатывать большие объемы данных записи или воспроизведения с помощью тюнера HAL.
- Модуль Native Tuner является мостом между классом Tuner Java и Tuner HAL.
Создан класс TRM.
- Управляет ограниченными ресурсами тюнера, такими как Frontend, LNB, сеансы CAS и входное телевизионное устройство с телевизионного входа HAL.
- Применяет правила для восстановления недостающих ресурсов у приложений. Правило по умолчанию — приоритет переднего плана.
Media CAS и CAS HAL улучшены за счет следующих функций.
- Открывает сеансы CAS для различных применений и алгоритмов.
- Поддерживает динамические системы CAS, такие как удаление и вставка CICAM.
- Интегрируется с Tuner HAL, предоставляя ключевые токены.
MediaCodec
и AudioTrack
улучшены за счет следующих функций.
- В качестве входного контента используется защищенная аудио/видео память.
- Настроено на аппаратную синхронизацию аудио/видео при туннелированном воспроизведении.
- Настроена поддержка
ES_payload
и сквозного режима.
Рисунок 2. Схема компонентов тюнера HAL
Общий рабочий процесс
На диаграммах ниже показаны последовательности вызовов для воспроизведения прямой трансляции.
Настраивать
Рисунок 3. Последовательность настройки для воспроизведения прямой трансляции
Обработка аудио/видео
Рисунок 4. Обработка аудио/видео для воспроизведения прямой трансляции
Обработка зашифрованного контента
Рисунок 5. Обработка зашифрованного контента для воспроизведения в прямом эфире
Обработка аудио/видео данных
Рисунок 6. Обработка аудио/видео для воспроизведения в прямом эфире
API тюнера SDK
API Tuner SDK обеспечивает взаимодействие с Tuner JNI, Tuner HAL и TunerResourceManager
. Приложение TIS использует API Tuner SDK для доступа к ресурсам и подкомпонентам Tuner, таким как фильтр и дешифратор. Интерфейс и демультиплексор являются внутренними компонентами.
Рисунок 7. Взаимодействие с API Tuner SDK
Версии
Начиная с Android 12, Tuner SDK API поддерживает новую функцию в Tuner HAL 1.1, которая представляет собой обратно совместимое обновление версии Tuner 1.0.
Используйте следующий API для проверки текущей версии HAL.
-
android.media.tv.tuner.TunerVersionChecker.getTunerVersion()
Минимально необходимую версию HAL можно найти в документации новых API Android 12.
Пакеты
API Tuner SDK предоставляет четыре пакета, представленных ниже.
-
android.media.tv.tuner
-
android.media.tv.tuner.frontend
-
android.media.tv.tuner.filter
-
android.media.tv.tuner.dvr
Рисунок 8. Пакеты API Tuner SDK
Android.media.tv.tuner
Пакет Tuner — это точка входа для использования фреймворка Tuner. Приложение TIS использует этот пакет для инициализации и получения экземпляров ресурсов, указывая начальные настройки и обратный вызов.
-
tuner()
: инициализирует экземпляр Tuner, указывая параметрыuseCase
иsessionId
. -
tune()
: получает ресурс интерфейса и настраивается путем указания параметраFrontendSetting
. -
openFilter()
: получает экземпляр фильтра, указывая тип фильтра. -
openDvrRecorder()
: получает экземпляр записи, указывая размер буфера. -
openDvrPlayback()
: получает экземпляр воспроизведения, указывая размер буфера. -
openDescrambler()
: получает экземпляр дескремблера. -
openLnb()
: получает внутренний экземпляр LNB. -
openLnbByName()
: приобретает внешний экземпляр LNB. -
openTimeFilter()
: получает экземпляр фильтра времени.
Пакет Tuner предоставляет функции, которые не входят в пакеты Filter, DVR и Frontend. Эти функции перечислены ниже.
-
cancelTuning
-
scan
/cancelScanning
-
getAvSyncHwId
-
getAvSyncTime
-
connectCiCam1
/disconnectCiCam
-
shareFrontendFromTuner
-
updateResourcePriority
-
setOnTuneEventListener
-
setResourceLostListener
Android.media.tv.tuner.frontend
Пакет frontend включает в себя наборы настроек, информации, статусов, событий и возможностей, связанных с frontend.
Классы
FrontendSettings
выводится для различных стандартов DTV с помощью классов, указанных ниже.
-
AnalogFrontendSettings
-
Atsc3FrontendSettings
-
AtscFrontendSettings
-
DvbcFrontendSettings
-
DvbsFrontendSettings
-
DvbtFrontendSettings
-
Isdbs3FrontendSettings
-
IsdbsFrontendSettings
-
IsdbtFrontendSettings
Начиная с Android 12 с Tuner HAL 1.1 или выше поддерживается следующий стандарт DTV.
-
DtmbFrontendSettings
FrontendCapabilities
выводится для различных стандартов DTV с помощью классов, указанных ниже.
-
AnalogFrontendCapabilities
-
Atsc3FrontendCapabilities
-
AtscFrontendCapabilities
-
DvbcFrontendCapabilities
-
DvbsFrontendCapabilities
-
DvbtFrontendCapabilities
-
Isdbs3FrontendCapabilities
-
IsdbsFrontendCapabilities
-
IsdbtFrontendCapabilities
Начиная с Android 12 с Tuner HAL 1.1 или выше поддерживается следующий стандарт DTV.
-
DtmbFrontendCapabilities
FrontendInfo
получает информацию о фронтенде. FrontendStatus
получает текущее состояние фронтенда. OnTuneEventListener
прослушивает события на фронтенде. Приложение TIS использует ScanCallback
для обработки сообщений сканирования от фронтенда.
Сканирование каналов
Для настройки телевизора приложение сканирует возможные частоты и формирует список каналов, к которому пользователи могут получить доступ. Для завершения сканирования каналов TIS может использовать Tuner.tune
, Tuner.scan(BLIND_SCAN)
или Tuner.scan(AUTO_SCAN)
.
Если у TIS есть точная информация о доставке сигнала, такая как частота, стандарт (например, T/T2, S/S2) и дополнительная необходимая информация (например, идентификатор PLD), то рекомендуется использовать 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 выдаёт сообщения о блокировке сканирования (scan
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()
чтобы приостановить или завершить сканирование.
Рисунок 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
Начиная с Android 12 с Tuner HAL 1.1 или выше поддерживаются следующие события.
-
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) один или несколько раз.Данные копируются из MQ HAL в клиентский буфер. | Один собранный пакет сеанса заполняется в FMQ другим пакетом сеанса. |
isRaw: | Обязательный:DemuxFilterEvent::DemuxFilterSectionEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Необязательный: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ Данные копируются из MQ HAL в клиентский буфер. | ||
TS.PES | isRaw: | Обязательный:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Рекомендуется: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | Согласно мероприятию и внутреннему расписанию, запуститеFilter.read(buffer, offset, adjustedSize) один или несколько раз.Данные копируются из MQ HAL в клиентский буфер. | Один собранный пакет PES заполняется в FMQ другим пакетом PES. |
isRaw: | Обязательный:DemuxFilterEvent::DemuxFilterPesEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Необязательный: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ Данные копируются из MQ HAL в клиентский буфер. | ||
MMTP.PES | isRaw: | Обязательный:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Рекомендуется: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | Согласно мероприятию и внутреннему расписанию, запуститеFilter.read(buffer, offset, adjustedSize) один или несколько раз.Данные копируются из MQ HAL в клиентский буфер. | Один собранный пакет MFU заполняется в FMQ другим пакетом MFU. |
isRaw: | Обязательный:DemuxFilterEvent::DemuxFilterPesEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Необязательный: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ Данные копируются из MQ HAL в клиентский буфер. | ||
TS.TS | Н/Д | Обязательный:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Рекомендуется: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | Согласно мероприятию и внутреннему расписанию, запуститеFilter.read(buffer, offset, adjustedSize) один или несколько раз.Данные копируются из MQ HAL в клиентский буфер. | Отфильтровано ts с заголовком ts заполнено в FMQ. |
TS.Audio TS.Video MMTP.Audio MMTP.Video | isPassthrough: | Необязательный:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW | Клиент может запустить MediaCodec после получения DemuxFilterStatus::DATA_READY .Клиент может вызвать Filter.flush после получения DemuxFilterStatus::DATA_OVERFLOW . | Н/Д |
isPassthrough: | Обязательный:DemuxFilterEvent::DemuxFilterMediaEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Необязательный: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | Чтобы использовать MediaCodec :for i=0; i<n; i++ Чтобы использовать Direct Audio из AudioTrack :for i=0; i<n; i++ | Данные ES или частичные данные ES в памяти ION. | |
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++ Для записанного контента , согласно RecordStatus::* и внутреннему расписанию, выполните одно из следующих действий:
| Для индексных данных: Переносится в полезной нагрузке события. Для записанного контента: мультиплексированный поток 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++ | Н/Д |
MMTP.MMTP | Н/Д | Обязательный:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Рекомендуется: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | Согласно мероприятию и внутреннему расписанию, запуститеFilter.read(buffer, offset, adjustedSize) один или несколько раз.Данные копируются из MQ HAL в клиентский буфер. | Отфильтровано 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. Если источником фильтра для записи является 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) Данные копируются из MQ HAL в клиентский буфер. | Пакет загрузки заполняется в FMQ другим пакетом загрузки IP. |
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) Данные копируются из MQ HAL в клиентский буфер. | Пакет полезной нагрузки IP заполняется в FMQ другим пакетом полезной нагрузки IP. |
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) один или несколько раз.Данные копируются из MQ HAL в клиентский буфер. | Отфильтрованный подпоток протокола с заголовком протокола заполняется в 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); } } };
Тюнер HAL
Tuner HAL соответствует стандарту HIDL и определяет интерфейс между фреймворком и оборудованием поставщика. Поставщики используют этот интерфейс для реализации Tuner HAL, а фреймворк — для взаимодействия с реализацией Tuner 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 | 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. Схема взаимодействия модулей тюнера HAL
Фильтр-связь
Тюнер HAL поддерживает связывание фильтров, что позволяет объединять фильтры с другими фильтрами для создания нескольких слоёв. Фильтры следуют приведенным ниже правилам.
- Фильтры связаны в виде дерева, замкнутые пути не допускаются.
- Корневой узел — демультиплексор.
- Фильтры работают независимо.
- Все фильтры начинают получать данные.
- Фильтрующее соединение промывается на последнем фильтре.
Блок кода ниже и рисунок 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) для переключения между двумя приложениями требовалось одно и то же аппаратное обеспечение тюнера. В TV Input Framework (TIF) использовался механизм «первый получил победитель», который означал, что приложение, первым получившее ресурс, сохраняет его. Однако этот механизм может быть неидеальным для некоторых сложных сценариев использования.
TRM работает как системная служба, управляя аппаратными ресурсами тюнера, TVInput
и CAS для приложений. TRM использует механизм «выигрыша переднего плана», который вычисляет приоритет приложения на основе его текущего состояния (в активном или фоновом режиме) и типа сценария использования. TRM предоставляет или отзывает ресурс в зависимости от приоритета. TRM централизует управление ресурсами ATV для вещания, OTT и DVR.
Интерфейс ТРМ
TRM предоставляет интерфейсы AIDL в ITunerResourceManager.aidl
для фреймворка Tuner, MediaCas
и TvInputHardwareManager
для регистрации, запроса или освобождения ресурсов.
Интерфейсы для управления клиентами перечислены ниже.
-
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
, чтобы определить, является ли приложение активным или фоновым. Для создания 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
.
Произвольное значение приоритета и значение nice
TRM предоставляет updateClientPriority
позволяющую клиенту обновлять произвольное значение приоритета и значение nice. Произвольное значение приоритета перезаписывает значение приоритета, рассчитанное на основе типа варианта использования и идентификатора сеанса.
Значение «доброжелательности» показывает, насколько снисходительно клиент ведёт себя в конфликте с другим клиентом. Значение «доброжелательности» снижает значение приоритета клиента перед сравнением его значения с приоритетом проблемного клиента.
Механизм возврата
На диаграмме ниже показано, как ресурсы возвращаются и распределяются при возникновении конфликта ресурсов.
Рисунок 15. Схема механизма восстановления при конфликте между ресурсами тюнера