Фреймворк тюнера

В Android 11 или более поздней версии вы можете использовать платформу Android Tuner для доставки аудио/видео контента. Платформа использует аппаратный конвейер от поставщиков, что делает ее подходящей как для SoC начального, так и для начального уровня. Эта платформа обеспечивает безопасный способ доставки аудио/видео контента, защищенного доверенной средой выполнения (TEE) и безопасным путем передачи данных (SMP), что позволяет использовать его в строго ограниченной среде защиты контента.

Стандартизированный интерфейс между Tuner и Android CAS обеспечивает более быструю интеграцию между поставщиками тюнеров и поставщиками CAS. Интерфейс Tuner работает с MediaCodec и AudioTrack создавая единое мировое решение для Android TV. Интерфейс тюнера поддерживает как цифровое, так и аналоговое телевидение на основе основных стандартов вещания.

Компоненты

Для Android 11 три компонента специально разработаны для телевизионной платформы.

  • Тюнер HAL: интерфейс между платформой и поставщиками.
  • API Tuner SDK: интерфейс между платформой и приложениями.
  • Менеджер ресурсов тюнера (TRM): координирует аппаратные ресурсы тюнера.

В Android 11 были улучшены следующие компоненты.

  • КАС В2
  • TvInputService или Служба ТВ-входа (TIS)
  • TvInputManagerService или служба диспетчера ТВ-входа (TIMS)
  • MediaCodec или медиакодек
  • AudioTrack или звуковая дорожка
  • MediaResourceManager или менеджер медиаресурсов (MRM)

Блок-схема компонентов платформы Tuner.

Рисунок 1. Взаимодействие между компонентами Android TV

Функции

Интерфейс поддерживает указанные ниже стандарты DTV.

  • АТСК
  • АТСК3
  • ДВБ С/С/Т
  • ИСДБ С/С3/Т
  • Аналоговый

Интерфейс Android 12 с тюнером HAL 1.1 или более поздней версии поддерживает указанный ниже стандарт DTV.

  • ДТМБ

Demux поддерживает протоколы потоков, указанные ниже.

  • Транспортный поток (ТС)
  • Транспортный протокол мультимедиа MPEG (MMTP)
  • Интернет-протокол (IP)
  • Введите значение длины (TLV)
  • Протокол канального уровня ATSC (ALP)

Дескремблер поддерживает указанные ниже средства защиты контента.

  • Безопасный путь к медиафайлам
  • Очистить путь мультимедиа
  • Безопасная локальная запись
  • Безопасное локальное воспроизведение

API-интерфейсы тюнера поддерживают приведенные ниже варианты использования.

  • Сканировать
  • Жить
  • Воспроизведение
  • Записывать

Tuner, MediaCodec и AudioTrack поддерживают указанные ниже режимы потока данных.

  • Полезная нагрузка ES с очисткой буфера памяти
  • Полезная нагрузка ES с безопасным дескриптором памяти
  • Сквозное прохождение

Общий дизайн

Тюнер HAL определяется между платформой Android и оборудованием поставщика.

  • Описывает, что платформа ожидает от поставщика и как поставщик может это сделать.
  • Экспортирует функциональные возможности внешнего интерфейса, демультиплексора и дескремблера в платформу через интерфейсы IFrontend , IDemux , IDescrambler , IFilter , IDvr и ILnb .
  • Включает функции для интеграции Tuner HAL с другими компонентами платформы, такими как MediaCodec и AudioTrack .

Создаются Java-класс Tuner и собственный класс.

  • API Tuner Java позволяет приложениям получать доступ к Tuner HAL через общедоступные API.
  • Класс Native позволяет управлять разрешениями и обрабатывать большие объемы данных записи или воспроизведения с помощью Tuner HAL.
  • Модуль Native Tuner является мостом между Java-классом Tuner и Tuner HAL.

Создается класс TRM.

  • Управляет ограниченными ресурсами тюнера, такими как Frontend, LNB, сеансы CAS и устройство ТВ-входа из ТВ-входа HAL.
  • Применяет правила для возврата недостаточных ресурсов из приложений. Правило по умолчанию — победа на переднем плане.

Media CAS и CAS HAL дополнены приведенными ниже функциями.

  • Открывает сеансы CAS для различных вариантов использования и алгоритмов.
  • Поддерживает динамические системы CAS, такие как удаление и вставка CICAM.
  • Интегрируется с Tuner HAL, предоставляя токены ключей.

MediaCodec и AudioTrack дополнены приведенными ниже функциями.

  • В качестве входного контента используется безопасная память A/V.
  • Настроен для аппаратной синхронизации A/V при туннельном воспроизведении.
  • Настроена поддержка ES_payload и режима passthrough.

Общий дизайн тюнера HAL.

Рисунок 2. Схема компонентов Tuner HAL.

Общий рабочий процесс

На диаграммах ниже показаны последовательности вызовов для воспроизведения в прямом эфире.

Настраивать

Последовательность настройки схемы воспроизведения прямой трансляции.

Рисунок 3. Последовательность настройки для воспроизведения прямой трансляции

Обработка аудио/видео

Обработка A/V для диаграммы воспроизведения в прямом эфире.

Рисунок 4. Обработка A/V для воспроизведения в прямом эфире

Обработка зашифрованного контента

Обработка зашифрованного контента для диаграммы воспроизведения в прямом эфире.

Рисунок 5. Обработка зашифрованного контента для воспроизведения в прямом эфире

Обработка аудио/видео данных

Обработка аудио/видео данных для диаграммы воспроизведения в прямом эфире.

Рисунок 6. Обработка A/V для воспроизведения в прямом эфире

API SDK тюнера

API Tuner SDK обрабатывает взаимодействие с Tuner JNI, Tuner HAL и TunerResourceManager . Приложение TIS использует API Tuner SDK для доступа к ресурсам и подкомпонентам Tuner, таким как фильтр и дешифратор. Фронтенд и демультиплексор являются внутренними компонентами.

Блок-схема API Tuner SDK.

Рисунок 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

Блок-схема пакетов API Tuner SDK.

Рисунок 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 предоставляет функции, которые не входят в пакеты фильтров, DVR и внешнего интерфейса. Функциональные возможности перечислены ниже.

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

Android.media.tv.tuner.frontend

Пакет внешнего интерфейса включает в себя наборы настроек, информации, статусов, событий и возможностей, связанных с внешним интерфейсом.

Классы

FrontendSettings создается для различных стандартов цифрового телевидения с помощью приведенных ниже классов.

  • AnalogFrontendSettings
  • Atsc3FrontendSettings
  • AtscFrontendSettings
  • DvbcFrontendSettings
  • DvbsFrontendSettings
  • DvbtFrontendSettings
  • Isdbs3FrontendSettings
  • IsdbsFrontendSettings
  • IsdbtFrontendSettings

Начиная с Android 12 с тюнером HAL 1.1 или выше, поддерживается следующий стандарт DTV.

  • DtmbFrontendSettings

FrontendCapabilities создается для различных стандартов цифрового телевидения с помощью приведенных ниже классов.

  • AnalogFrontendCapabilities
  • Atsc3FrontendCapabilities
  • AtscFrontendCapabilities
  • DvbcFrontendCapabilities
  • DvbsFrontendCapabilities
  • DvbtFrontendCapabilities
  • Isdbs3FrontendCapabilities
  • IsdbsFrontendCapabilities
  • IsdbtFrontendCapabilities

Начиная с Android 12 с тюнером 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 сканируют сообщения LOCKED если сигнал заблокирован. HAL может также сообщать о других сообщениях сканирования, чтобы предоставить дополнительную информацию о сигнале.

  • TIS использует Frontend.getStatus для сбора необходимой информации.

  • TIS вызывает Tuner.scan для HAL, чтобы перейти к следующей настройке на той же частоте. Если структура FrontendSettings пуста, HAL использует следующий доступный параметр. В противном случае HAL использует FrontendSettings для однократного сканирования и отправляет END , чтобы указать, что операция сканирования завершена.

  • ТИС повторяет вышеописанные действия до тех пор, пока не будут исчерпаны все настройки по частоте.

  • 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 игнорируется.)
  • ТИС повторяет вышеописанные действия до тех пор, пока не будут исчерпаны все настройки по частоте. HAL увеличивает частоту без каких-либо действий со стороны TIS. PROGRESS сообщает HAL.

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

Начиная с Android 12 с Tuner HAL 1.1 или выше поддерживаются следующие события.

  • 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) один или несколько раз.

Данные копируются из MQ HAL в клиентский буфер.
Один собранный пакет сеанса заполняется в 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)


Данные копируются из MQ HAL в клиентский буфер.
TS.PES isRaw:
true
Обязательный:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Рекомендуется:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Согласно мероприятию и внутреннему расписанию запускать
Filter.read(buffer, offset, adjustedSize) один или несколько раз.

Данные копируются из MQ HAL в клиентский буфер.
Один собранный пакет PES заполняется в FMQ другим пакетом PES.
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)


Данные копируются из MQ HAL в клиентский буфер.
MMTP.PES isRaw:
true
Обязательный:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Рекомендуется:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Согласно мероприятию и внутреннему расписанию запускать
Filter.read(buffer, offset, adjustedSize) один или несколько раз.

Данные копируются из MQ HAL в клиентский буфер.
Один собранный пакет MFU заполняется в FMQ другим пакетом MFU.
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)


Данные копируются из 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:
true
Необязательный:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
Клиент может запустить MediaCodec после получения DemuxFilterStatus::DATA_READY .
Клиент может вызвать Filter.flush после получения DemuxFilterStatus::DATA_OVERFLOW .
Н/Д
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))
Данные 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++
DemuxFilterTsRecordEvent[i];


Для записанного контента в соответствии с RecordStatus::* и внутренним расписанием выполните одно из следующих действий:
  • Запустите DvrRecord.write(adustedSize) один или несколько раз в хранилище.
    Данные передаются из MQ HAL в хранилище.
  • Запустите DvrRecord.write(buffer, adustedSize) один или несколько раз для буферизации.
    Данные копируются из MQ HAL в клиентский буфер.
Для индексных данных: Переносится в полезные данные события.

Для записанного контента: мультиплексированный поток 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++
DemuxFilterTemiEvent[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++
DemuxFilterMmtpRecordEvent[i];


Для записанного контента в соответствии с RecordStatus::* и внутренним расписанием выполните одно из следующих действий:
  • Запустите DvrRecord.write(adjustedSize) один или несколько раз в хранилище.
    Данные передаются из MQ HAL в хранилище.
  • Запустите DvrRecord.write(buffer, adjustedSize) один или несколько раз для буферизации.
    Данные копируются из MQ HAL в клиентский буфер.
Для индексных данных: Переносится в полезные данные события.

Для записанного контента: мультиплексированный записанный поток, заполненный в 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:
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) один или несколько раз.

Данные копируются из MQ HAL в клиентский буфер.
Отфильтрованный подпоток протокола с заголовком протокола заполняется в FMQ.
IP.PAYLOAD_THROUGH
TLV.PAYLOAD_THROUGH
ALP.PAYLOAD_THROUGH
Н/Д Необязательный:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
Отфильтрованная полезная нагрузка протокола передается следующему фильтру в цепочке фильтров. Н/Д
Пример использования фильтра для построения PSI/SI

Пример алгоритма использования фильтра для построения PSI/SI.

Рисунок 10. Процесс построения PSI/SI

  1. Откройте фильтр.

    Filter filter = tuner.openFilter(
      Filter.TYPE_TS,
      Filter.SUBTYPE_SECTION,
      /* bufferSize */1000,
      executor,
      filterCallback
    );
    
  2. Настройте и запустите фильтр.

    Settings settings = SectionSettingsWithTableInfo
        .builder(Filter.TYPE_TS)
        .setTableId(2)
        .setVersion(1)
        .setCrcEnabled(true)
        .setRaw(false)
        .setRepeat(false)
        .build();
      FilterConfiguration config = TsFilterConfiguration
        .builder()
        .setTpid(10)
        .setSettings(settings)
        .build();
      filter.configure(config);
      filter.start();
    
  3. Обработать SectionEvent .

    FilterCallback filterCallback = new FilterCallback() {
      @Override
      public void onFilterEvent(Filter filter, FilterEvent[] events) {
        for (FilterEvent event : events) {
          if (event instanceof SectionEvent) {
            SectionEvent sectionEvent = (SectionEvent) event;
            int tableId = sectionEvent.getTableId();
            int version = sectionEvent.getVersion();
            int dataLength = sectionEvent.getDataLength();
            int sectionNumber = sectionEvent.getSectionNumber();
            filter.read(buffer, 0, dataLength); }
          }
        }
    };
    
Пример потока использования MediaEvent из фильтра

Пример потока использования MediaEvent из фильтра.

Рисунок 11. Порядок использования MediaEvent из фильтра

  1. Откройте, настройте и запустите A/V-фильтры.
  2. Обработать MediaEvent .
  3. Получите MediaEvent .
  4. Поставьте линейный блок в очередь codec .
  5. Отпустите дескриптор A/V, когда данные будут использованы.

Android.media.tv.tuner.dvr

DvrRecorder предоставляет эти методы записи.

  • configure
  • attachFilter
  • detachFilter
  • start
  • flush
  • stop
  • setFileDescriptor
  • write

DvrPlayback предоставляет эти методы для воспроизведения.

  • configure
  • start
  • flush
  • stop
  • setFileDescriptor
  • read

DvrSettings используется для настройки DvrRecorder и DvrPlayback . OnPlaybackStatusChangedListener и OnRecordStatusChangedListener используются для сообщения о состоянии экземпляра 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);
          }
        }
      };
    

Тюнер HAL

Тюнер 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

Блок-схема взаимодействия модулей тюнера HAL.

Рисунок 13. Схема взаимодействия модулей Tuner HAL

Связь с фильтром

Tuner 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. Блок-схема подключения фильтра для нескольких уровней.

Менеджер ресурсов тюнера

До появления Tuner Resource Manager (TRM) для переключения между двумя приложениями требовалось одно и то же оборудование Tuner. TV Input Framework (TIF) использовал механизм «первым получил выигрыш», что означает, что какое бы приложение ни получило ресурс первым, оно сохранит его. Однако этот механизм может быть не идеальным для некоторых сложных случаев использования.

TRM работает как системная служба для управления аппаратными ресурсами Tuner, 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 .

Произвольное значение приоритета и приятное значение

TRM предоставляет клиенту updateClientPriority для обновления произвольного значения приоритета и приятного значения. Произвольное значение приоритета перезаписывает значение приоритета, рассчитанное на основе типа варианта использования и идентификатора сеанса.

Значение nice указывает, насколько снисходительно поведение клиента в случае конфликта с другим клиентом. Значение «приятно» уменьшает значение приоритета клиента до того, как его значение приоритета сравнивается со значением приоритета «сложного» клиента.

Механизм возврата

На диаграмме ниже показано, как ресурсы освобождаются и назначаются при возникновении конфликта ресурсов.

Схема процесса механизма возврата.

Рисунок 15. Схема механизма восстановления при конфликте ресурсов тюнера

,

В Android 11 или более поздней версии вы можете использовать платформу Android Tuner для доставки аудио- и видеоконтента. Платформа использует аппаратный конвейер от поставщиков, что делает ее подходящей как для SoC начального, так и для начального уровня. Эта платформа обеспечивает безопасный способ доставки аудио/видео контента, защищенного доверенной средой выполнения (TEE) и безопасным путем передачи данных (SMP), что позволяет использовать его в строго ограниченной среде защиты контента.

Стандартизированный интерфейс между Tuner и Android CAS обеспечивает более быструю интеграцию между поставщиками тюнеров и поставщиками CAS. Интерфейс Tuner работает с MediaCodec и AudioTrack создавая единое мировое решение для Android TV. Интерфейс тюнера поддерживает как цифровое, так и аналоговое телевидение на основе основных стандартов вещания.

Компоненты

Для Android 11 три компонента специально разработаны для телевизионной платформы.

  • Тюнер HAL: интерфейс между платформой и поставщиками.
  • API Tuner SDK: интерфейс между платформой и приложениями.
  • Менеджер ресурсов тюнера (TRM): координирует аппаратные ресурсы тюнера.

В Android 11 были улучшены следующие компоненты.

  • КАС В2
  • TvInputService или Служба ТВ-входа (TIS)
  • TvInputManagerService или служба диспетчера ТВ-входа (TIMS).
  • MediaCodec или медиакодек
  • AudioTrack или звуковая дорожка
  • MediaResourceManager или менеджер медиаресурсов (MRM)

Блок-схема компонентов платформы Tuner.

Рисунок 1. Взаимодействие между компонентами Android TV

Функции

Интерфейс поддерживает указанные ниже стандарты DTV.

  • АТСК
  • АТСК3
  • ДВБ С/С/Т
  • ИСДБ С/С3/Т
  • Аналоговый

Интерфейс Android 12 с тюнером HAL 1.1 или более поздней версии поддерживает указанный ниже стандарт DTV.

  • ДТМБ

Demux поддерживает протоколы потоков, указанные ниже.

  • Транспортный поток (ТС)
  • Транспортный протокол мультимедиа MPEG (MMTP)
  • Интернет-протокол (IP)
  • Введите значение длины (TLV)
  • Протокол канального уровня ATSC (ALP)

Дескремблер поддерживает указанные ниже средства защиты контента.

  • Безопасный путь к медиафайлам
  • Очистить путь мультимедиа
  • Безопасная локальная запись
  • Безопасное локальное воспроизведение

API-интерфейсы тюнера поддерживают приведенные ниже варианты использования.

  • Сканировать
  • Жить
  • Воспроизведение
  • Записывать

Tuner, MediaCodec и AudioTrack поддерживают указанные ниже режимы потока данных.

  • Полезная нагрузка ES с очисткой буфера памяти
  • Полезная нагрузка ES с безопасным дескриптором памяти
  • Сквозное прохождение

Общий дизайн

Тюнер HAL определяется между платформой Android и оборудованием поставщика.

  • Описывает, что платформа ожидает от поставщика и как поставщик может это сделать.
  • Экспортирует функциональные возможности внешнего интерфейса, демультиплексора и дескремблера в платформу через интерфейсы IFrontend , IDemux , IDescrambler , IFilter , IDvr и ILnb .
  • Включает функции для интеграции Tuner HAL с другими компонентами платформы, такими как MediaCodec и AudioTrack .

Создаются Java-класс Tuner и собственный класс.

  • API Tuner Java позволяет приложениям получать доступ к Tuner HAL через общедоступные API.
  • Класс Native позволяет управлять разрешениями и обрабатывать большие объемы данных записи или воспроизведения с помощью Tuner HAL.
  • Модуль Native Tuner является мостом между Java-классом Tuner и Tuner HAL.

Создается класс TRM.

  • Управляет ограниченными ресурсами тюнера, такими как Frontend, LNB, сеансы CAS и устройство ТВ-входа из ТВ-входа HAL.
  • Применяет правила для возврата недостаточных ресурсов из приложений. Правило по умолчанию — победа на переднем плане.

Media CAS и CAS HAL дополнены приведенными ниже функциями.

  • Открывает сеансы CAS для различных вариантов использования и алгоритмов.
  • Поддерживает динамические системы CAS, такие как удаление и вставка CICAM.
  • Интегрируется с Tuner HAL, предоставляя токены ключей.

MediaCodec и AudioTrack дополнены приведенными ниже функциями.

  • В качестве входного контента используется безопасная память A/V.
  • Настроен для аппаратной синхронизации A/V при туннельном воспроизведении.
  • Настроена поддержка ES_payload и режима passthrough.

Общий дизайн тюнера HAL.

Рисунок 2. Схема компонентов Tuner HAL.

Общий рабочий процесс

На диаграммах ниже показаны последовательности вызовов для воспроизведения в прямом эфире.

Настраивать

Последовательность настройки схемы воспроизведения прямой трансляции.

Рисунок 3. Последовательность настройки для воспроизведения прямой трансляции

Обработка аудио/видео

Обработка A/V для диаграммы воспроизведения в прямом эфире.

Рисунок 4. Обработка A/V для воспроизведения в прямом эфире

Обработка зашифрованного контента

Обработка зашифрованного контента для диаграммы воспроизведения в прямом эфире.

Рисунок 5. Обработка зашифрованного контента для воспроизведения в прямом эфире

Обработка аудио/видео данных

Обработка аудио/видео данных для диаграммы воспроизведения в прямом эфире.

Рисунок 6. Обработка A/V для воспроизведения в прямом эфире

API SDK тюнера

API Tuner SDK обрабатывает взаимодействие с Tuner JNI, Tuner HAL и TunerResourceManager . Приложение TIS использует API Tuner SDK для доступа к ресурсам и подкомпонентам Tuner, таким как фильтр и дешифратор. Фронтенд и демультиплексор являются внутренними компонентами.

Блок-схема API Tuner SDK.

Рисунок 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

Блок-схема пакетов API Tuner SDK.

Рисунок 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 предоставляет функции, которые не входят в пакеты фильтров, DVR и внешнего интерфейса. Функциональные возможности перечислены ниже.

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

Android.media.tv.tuner.frontend

Пакет внешнего интерфейса включает в себя наборы настроек, информации, статусов, событий и возможностей, связанных с внешним интерфейсом.

Классы

FrontendSettings создается для различных стандартов цифрового телевидения с помощью приведенных ниже классов.

  • AnalogFrontendSettings
  • Atsc3FrontendSettings
  • AtscFrontendSettings
  • DvbcFrontendSettings
  • DvbsFrontendSettings
  • DvbtFrontendSettings
  • Isdbs3FrontendSettings
  • IsdbsFrontendSettings
  • IsdbtFrontendSettings

Начиная с Android 12 с тюнером HAL 1.1 или более поздней версии поддерживается следующий стандарт DTV.

  • DtmbFrontendSettings

FrontendCapabilities создается для различных стандартов цифрового телевидения с помощью приведенных ниже классов.

  • AnalogFrontendCapabilities
  • Atsc3FrontendCapabilities
  • AtscFrontendCapabilities
  • DvbcFrontendCapabilities
  • DvbsFrontendCapabilities
  • DvbtFrontendCapabilities
  • Isdbs3FrontendCapabilities
  • IsdbsFrontendCapabilities
  • IsdbtFrontendCapabilities

Начиная с Android 12 с тюнером 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 сканируют сообщения LOCKED , если сигнал заблокирован. HAL может также сообщать о других сообщениях сканирования, чтобы предоставить дополнительную информацию о сигнале.

  • TIS использует Frontend.getStatus для сбора необходимой информации.

  • TIS вызывает Tuner.scan для HAL, чтобы перейти к следующей настройке на той же частоте. Если структура FrontendSettings пуста, HAL использует следующий доступный параметр. В противном случае HAL использует FrontendSettings для однократного сканирования и отправляет END , чтобы указать, что операция сканирования завершена.

  • ТИС повторяет вышеописанные действия до тех пор, пока не будут исчерпаны все настройки по частоте.

  • 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 игнорируется.)
  • ТИС повторяет вышеописанные действия до тех пор, пока не будут исчерпаны все настройки по частоте. HAL увеличивает частоту без каких-либо действий со стороны TIS. PROGRESS сообщает HAL.

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

От Android 12 с тюнером HAL 1.1 или выше поддерживается следующие события.

  • 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's 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's MQ в клиентский буфер.
TS.PES isRaw:
true
Обязательный:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Рекомендуется:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Согласно событию и внутреннему графику, запустите
Filter.read(buffer, offset, adjustedSize) один или несколько раз.

Данные копируются из MQ HAL в клиентский буфер.
Один собранный пакет PES заполняется в FMQ другим пакетом PES.
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's MQ в клиентский буфер.
MMTP.PES isRaw:
true
Обязательный:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Рекомендуется:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Согласно событию и внутреннему графику, запустите
Filter.read(buffer, offset, adjustedSize) один или несколько раз.

Данные копируются из MQ HAL в клиентский буфер.
Один собранный пакет MFU заполняется в FMQ другим пакетом MFU.
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)


Данные копируются из 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:
true
Необязательный:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
Клиент может запустить MediaCodec после получения DemuxFilterStatus::DATA_READY .
Клиент может вызвать Filter.flush после получения DemuxFilterStatus::DATA_OVERFLOW .
Н/Д
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))
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) один или несколько раз для хранения.
    Данные передаются с MQ HAL в хранилище.
  • Запустите DvrRecord.write(buffer, adustedSize) один или несколько раз для буфера.
    Данные копируются из MQ HAL в клиентский буфер.
Для данных индекса: переносится в полезной нагрузке.

Для записанного контента: муксированный поток 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++
DemuxFilterTemiEvent[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++
DemuxFilterMmtpRecordEvent[i];


Для записанного контента , согласно RecordStatus::* и внутреннее расписание, сделайте одно из следующих:
  • Запустите DvrRecord.write(adjustedSize) один или несколько раз для хранения.
    Данные передаются с MQ HAL в хранилище.
  • Запустите DvrRecord.write(buffer, adjustedSize) один или несколько раз для буфера.
    Данные копируются из MQ HAL в клиентский буфер.
Для данных индекса: переносится в полезной нагрузке.

Для записанного контента: MUXED Записанный поток, заполненный в FMQ.

Если источник фильтра для записи равен TLV.TLV to IP.IP с PassThrough, записанный поток имеет заголовок 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's MQ в клиентский буфер.
Скачать пакет заполнен в 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)

Данные копируются из HAL's MQ в клиентский буфер.
Пакет IP -полевой нагрузки заполняется в FMQ другим пакетом IP -полевой нагрузки.
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) один или несколько раз.

Данные копируются из MQ HAL в клиентский буфер.
Отфильтрованный подтокол протокола с заголовком протокола заполняется в 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); }
          }
        }
    };
    
Пример потока для использования среднеэвер из фильтра

Пример потока для использования среднеэвер из фильтра.

Рисунок 11. Поток для использования среднеэверных из фильтра

  1. Откройте, настройте и запустите фильтры A/V.
  2. Процесс MediaEvent .
  3. Получить MediaEvent .
  4. Очередь линейный блок до codec .
  5. Отпустите ручку A/V, когда данные были использованы.

Android.media.tv.tuner.dvr

DvrRecorder предоставляет эти методы для записи.

  • configure
  • attachFilter
  • detachFilter
  • start
  • flush
  • stop
  • setFileDescriptor
  • write

DvrPlayback предоставляет эти методы для воспроизведения.

  • configure
  • start
  • flush
  • stop
  • setFileDescriptor
  • read

DvrSettings используется для настройки DvrRecorder и DvrPlayback . OnPlaybackStatusChangedListener и OnRecordStatusChangedListener используются для сообщения о статусе экземпляра 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 и определяет интерфейс между оборудованием Framework и поставщика. Поставщики используют интерфейс для реализации Tuner HAL, и Framework использует его для связи с реализацией 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

Диаграмма потока взаимодействий между модулями тюнера HAL.

Рисунок 13. Диаграмма взаимодействий между модулями тюнера 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

Перед Tuner Resource Manager (TRM) переключение между двумя приложениями требовало одного и того же оборудования тюнера. Входной фреймворк (TIF) использовал механизм «первого к приобретению», что означает, какое приложение получит ресурс в первую очередь сохраняет ресурс. Тем не менее, этот механизм не может быть идеальным для некоторых сложных случаев использования.

TRM работает как системная служба для управления тюнером, TVInput и CAS -аппаратными ресурсами для приложений. TRM использует механизм «победа переднего плана», который вычисляет приоритет приложения на основе переднего плана приложения или статуса фонового и типа использования. TRM предоставляет или отменяет ресурс на основе приоритета. TRM централизует управление ресурсами ATV для вещания, OTT и DVR.

Интерфейс TRM

TRM разоблачает интерфейсы AIDL в ITunerResourceManager.aidl для фреймворта, 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 .

Произвольная ценность приоритета и хорошая ценность

TRM предоставляет для клиента updateClientPriority для обновления произвольного значения приоритета и хорошего значения. Произвольное значение приоритета перезаписывает значение приоритета, рассчитанное по типу использования и идентификатором сеанса.

Хорошая ценность указывает, насколько снисходительным является поведение клиента, когда оно вступает в конфликт с другим клиентом. Хорошая стоимость уменьшается, что значение приоритета клиента до того, как его приоритетная стоимость сравнивается с сложным клиентом.

Исправление механизма

Приведенная ниже диаграмма показывает, как ресурсы восстанавливаются и назначены, когда происходит конфликт ресурсов.

Диаграмма процесса механизма Reclaim.

Рисунок 15. Диаграмма механизма Reclaim для конфликта между ресурсами тюнера