For Android 11 or higher, you can use the Android Tuner framework to deliver A/V content. The framework uses the hardware pipeline from vendors, making it suitable for both low-end and high-end SoC. The framework provides a secure way to deliver A/V content protected by a trusted execution environment (TEE) and secure media path (SMP), allowing it to be used in a highly restricted, content protection environment.
The standardized interface between Tuner and Android CAS results in a faster
integration between Tuner vendors and CAS vendors. The Tuner interface works
with MediaCodec
and AudioTrack
to build a one world solution for Android TV.
The Tuner interface supports both digital TV and analog TV based on major
broadcast standards.
Components
For Android 11, three components are specifically designed for the TV platform.
- Tuner HAL: An interface between the framework and vendors
- Tuner SDK API: An interface between the framework and apps
- Tuner Resource Manager (TRM): Coordinates Tuner HW resources
For Android 11, the following components have been enhanced.
- CAS V2
TvInputService
or TV Input Service (TIS)TvInputManagerService
or TV Input Manager Service (TIMS)MediaCodec
or media codecAudioTrack
or audio trackMediaResourceManager
or media resource manager (MRM)
Figure 1. Interactions between Android TV components
Features
Frontend supports the DTV standards below.
- ATSC
- ATSC3
- DVB C/S/T
- ISDB S/S3/T
- Analog
The frontend in Android 12 with Tuner HAL 1.1 or higher supports the DTV standard below.
- DTMB
Demux supports the stream protocols below.
- Transport stream (TS)
- MPEG media transport protocol (MMTP)
- Internet protocol (IP)
- Type length value (TLV)
- ATSC link-layer protocol (ALP)
Descrambler supports the content protections below.
- Secure media path
- Clear media path
- Secure local record
- Secure local playback
Tuner APIs support the use cases below.
- Scan
- Live
- Playback
- Record
Tuner, MediaCodec
, and AudioTrack
support the data flow modes below.
- ES payload with clear memory buffer
- ES payload with secure memory handle
- Passthrough
Overall design
The Tuner HAL is defined between the Android framework and the vendor's hardware.
- Describes what the framework expects from the vendor and how the vendor might do it.
- Exports the functionalities of frontend, demux and descrambler to the
framework through
IFrontend
,IDemux
,IDescrambler
,IFilter
,IDvr
, andILnb
interfaces. - Includes the functions to integrate the Tuner HAL with other framework
components, such as
MediaCodec
andAudioTrack
.
A Tuner Java class and native class are created.
- The Tuner Java API allows apps to access the Tuner HAL through public APIs.
- Native class allows permission control and handling of large amounts of recording or playback data with the Tuner HAL.
- Native Tuner module is a bridge between the Tuner Java class and the Tuner HAL.
A TRM class is created.
- Manages limited Tuner resources, such as Frontend, LNB, CAS sessions, and a TV input device from the TV input HAL.
- Applies rules to reclaim insufficient resources from apps. The default rule is the foreground win.
Media CAS and the CAS HAL are enhanced with the features below.
- Opens CAS sessions for different usages and algorithms.
- Supports dynamic CAS systems, such as CICAM removal and insertion.
- Integrates with the Tuner HAL by providing key tokens.
MediaCodec
and AudioTrack
are enhanced with the features below.
- Takes secure A/V memory as content input.
- Configured to do hardware A/V sync in tunneled playback.
- Configured support for
ES_payload
and passthrough mode.
Figure 2. Diagram of the components within the Tuner HAL
Overall workflow
The diagrams below illustrate call sequences for live broadcast playback.
Setup
Figure 3. Setup sequence for live broadcast playback
Handling A/V
Figure 4. Handling A/V for live broadcast playback
Handling scrambled content
Figure 5. Handling scrambled content for live broadcast playback
Processing A/V data
Figure 6. Processing A/V for live broadcast playback
Tuner SDK API
The Tuner SDK API handles the interactions with the Tuner JNI, the Tuner HAL,
and TunerResourceManager
. The TIS app uses the Tuner SDK API to access Tuner
resources and subcomponents such as the filter and descrambler. Frontend and
demux are internal components.
Figure 7. Interactions with the Tuner SDK API
Versions
From Android 12, the Tuner SDK API supports new feature in Tuner HAL 1.1, which is a backward-compatible version upgrade of Tuner 1.0.
Use the following API to check the running HAL version.
android.media.tv.tuner.TunerVersionChecker.getTunerVersion()
The minimum required HAL version can be found in the documentation of the new Android 12 APIs.
Packages
The Tuner SDK API provides the four packages below.
android.media.tv.tuner
android.media.tv.tuner.frontend
android.media.tv.tuner.filter
android.media.tv.tuner.dvr
Figure 8. Tuner SDK API packages
Android.media.tv.tuner
The Tuner package is an entry point to use the Tuner framework. The TIS app uses the package to initialize and acquire resource instances by specifying the initial setting and callback.
tuner()
: Initializes a Tuner instance by specifying theuseCase
andsessionId
parameters.tune()
: Acquires a frontend resource and tune by specifying theFrontendSetting
parameter.openFilter()
: Acquires a filter instance by specifying the filter type.openDvrRecorder()
: Acquires a recording instance by specifying the buffer size.openDvrPlayback()
: Acquires a playback instance by specifying the buffer size.openDescrambler()
: Acquires a descrambler instance.openLnb()
: Acquires an internal LNB instance.openLnbByName()
: Acquires an external LNB instance.openTimeFilter()
: Acquires a time filter instance.
The Tuner package provides functionalities that aren't covered under the filter, DVR, and frontend packages. The functionalities are listed below.
cancelTuning
scan
/cancelScanning
getAvSyncHwId
getAvSyncTime
connectCiCam1
/disconnectCiCam
shareFrontendFromTuner
updateResourcePriority
setOnTuneEventListener
setResourceLostListener
Android.media.tv.tuner.frontend
The frontend package includes collections of frontend-related settings, information, statuses, events, and capabilities.
Classes
FrontendSettings
is derived for different DTV standards by the classes below.
AnalogFrontendSettings
Atsc3FrontendSettings
AtscFrontendSettings
DvbcFrontendSettings
DvbsFrontendSettings
DvbtFrontendSettings
Isdbs3FrontendSettings
IsdbsFrontendSettings
IsdbtFrontendSettings
From Android 12 with Tuner HAL 1.1 or higher, the following DTV standard is supported.
DtmbFrontendSettings
FrontendCapabilities
is derived for different DTV standards by the classes
below.
AnalogFrontendCapabilities
Atsc3FrontendCapabilities
AtscFrontendCapabilities
DvbcFrontendCapabilities
DvbsFrontendCapabilities
DvbtFrontendCapabilities
Isdbs3FrontendCapabilities
IsdbsFrontendCapabilities
IsdbtFrontendCapabilities
From Android 12 with Tuner HAL 1.1 or higher, the following DTV standard is supported.
DtmbFrontendCapabilities
FrontendInfo
retrieves the frontend's information.
FrontendStatus
retrieves the current status of the frontend.
OnTuneEventListener
listens to the events on the frontend.
The TIS app uses ScanCallback
to process scan messages from the frontend.
Channel scan
To set up a TV, the app scans possible frequencies and builds up a channel
lineup for users to access. TIS might use Tuner.tune
,
Tuner.scan(BLIND_SCAN)
, or Tuner.scan(AUTO_SCAN)
to complete channel
scanning.
If TIS has accurate delivery information for the signal, such as frequency,
standard (for example, T/T2, S/S2), and additional necessary information
(for example, PLD ID), then
Tuner.tune
is recommended as the faster option.
When the user calls Tuner.tune
, the following actions happen:
- TIS populates
FrontendSettings
with required information usingTuner.tune
. - The HAL reports tune
LOCKED
messages if the signal is locked. - TIS uses
Frontend.getStatus
to collect the necessary information. - TIS moves to the next available frequency in its frequency list.
TIS calls Tuner.tune
again until all frequencies are exhausted.
During tuning, you can call stopTune()
or close()
to pause or end the
Tuner.tune
call.
Tuner.scan(AUTO_SCAN)
If TIS doesn't have enough information to use Tuner.tune
, but has a frequency
list and standard type (for example, DVB T/C/S),
then Tuner.scan(AUTO_SCAN)
is recommended.
When the user calls Tuner.scan(AUTO_SCAN)
, the following actions happen:
TIS uses
Tuner.scan(AUTO_SCAN)
withFrontendSettings
filled with frequency.The HAL reports scan
LOCKED
messages if the signal is locked. The HAL might also report other scan messages to provide additional information about the signal.TIS uses
Frontend.getStatus
to collect necessary information.TIS calls
Tuner.scan
for the HAL to continue to the next setting on the same frequency. If theFrontendSettings
structure is empty, the HAL uses the next available setting. Otherwise, HAL usesFrontendSettings
for a one-time scan and sendsEND
to indicate that the scan operation is finished.TIS repeats the actions above until all settings on the frequency are exhausted.
The HAL sends
END
to indicate that the scan operation is finished.TIS moves to the next available frequency in its frequency list.
TIS calls Tuner.scan(AUTO_SCAN)
again until all frequencies are exhausted.
During scanning, you can call stopScan()
or close()
to pause or end the
scan.
Tuner.scan(BLIND_SCAN)
If TIS doesn't have a frequency list and the Vendor HAL can search for
the frequency of the user-specified frontend to get the frontend resource, then
Tuner.scan(BLIND_SCAN)
is recommended.
- TIS uses
Tuner.scan(BLIND_SCAN)
. A frequency can be specified inFrontendSettings
for start frequency, but TIS ignores other settings inFrontendSettings
. - The HAL reports a scan
LOCKED
message if signal is locked. - TIS uses
Frontend.getStatus
to collect necessary information. - TIS calls
Tuner.scan
again to continue scanning. (FrontendSettings
is ignored.) - TIS repeats the actions above until all settings on the frequency are
exhausted. The HAL increments frequency with no action needed from TIS.
The HAL reports
PROGRESS
.
TIS calls Tuner.scan(AUTO_SCAN)
again until all frequencies are exhausted.
The HAL reports END
to indicate that the scan operation is finished.
During scanning, you can call stopScan()
or close()
to pause or end the scan.
Figure 9. Flow diagram of a TIS scan
Android.media.tv.tuner.filter
The filter package is a collection of filter operations along with configuration, settings, callbacks, and events. The package includes the operations below. Refer to the Android source code for the complete list of operations.
configure()
start()
stop()
flush()
read()
Refer to the Android source code for the complete list.
FilterConfiguration
is derived from the classes below. The configurations are
for the main filter type and they specify which protocol the filter uses to
extract data.
AlpFilterConfiguration
IpFilterConfiguration
MmtpFilterConfiguration
TlvFilterConfiguration
TsFilterConfiguration
The settings are derived from the classes below. The settings are for the filter subtype and they specify what kinds of data the filter can exclude.
SectionSettings
AvSettings
PesSettings
RecordSettings
DownloadSettings
FilterEvent
is derived from the classes below to report events for different
kinds of data.
SectionEvent
MediaEvent
PesEvent
TsRecordEvent
MmtpRecordEvent
TemiEvent
DownloadEvent
IpPayloadEvent
From Android 12 with Tuner HAL 1.1 or higher, the following events are supported.
IpCidChangeEvent
RestartEvent
ScramblingStatusEvent
Events and data format from filter
Filter type | Flags | Events | Data operation | Data format |
---|---|---|---|---|
TS.SECTION MMTP.SECTION IP.SECTION TLV.SECTION ALP.SECTION |
isRaw: |
Mandatory:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recommended: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
According to the event and internal schedule, runFilter.read(buffer, offset, adjustedSize) one or more
times.Data is copied from HAL's MQ to the client buffer. |
One assembled session package is filled in FMQ by another session package. |
isRaw: |
Mandatory:DemuxFilterEvent::DemuxFilterSectionEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Optional: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i Data is copied from HAL's MQ to the client buffer. |
||
TS.PES |
isRaw: |
Mandatory:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recommended: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
According to the event and internal schedule, runFilter.read(buffer, offset, adjustedSize) one or more
times.Data is copied from the HAL's MQ to the client buffer. |
One assembled PES package is filled in FMQ by another PES package. |
isRaw: |
Mandatory:DemuxFilterEvent::DemuxFilterPesEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Optional: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i Data is copied from HAL's MQ to the client buffer. |
||
MMTP.PES |
isRaw: |
Mandatory:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recommended: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
According to the event and internal schedule, runFilter.read(buffer, offset, adjustedSize) one or more
times.Data is copied from the HAL's MQ to the client buffer. |
One assembled MFU package is filled in FMQ by another MFU package. |
isRaw: |
Mandatory:DemuxFilterEvent::DemuxFilterPesEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Optional: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i Data is copied from the HAL's MQ to the client buffer. |
||
TS.TS |
N/A | Mandatory:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recommended: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
According to the event and internal schedule, runFilter.read(buffer, offset, adjustedSize) one or more
times.Data is copied from the HAL's MQ to the client buffer. |
Filtered out ts with ts headeris filled in FMQ. |
TS.Audio TS.Video MMTP.Audio MMTP.Video |
isPassthrough: |
Optional:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW |
The client can start MediaCodec after receiving DemuxFilterStatus::DATA_READY .The client can call Filter.flush after receiving DemuxFilterStatus::DATA_OVERFLOW . |
N/A |
isPassthrough: |
Mandatory:DemuxFilterEvent::DemuxFilterMediaEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Optional: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
To use MediaCodec :for i=0; i<n; i To use Direct Audio of AudioTrack :for i=0; i<n; i |
ES or partial ES data in ION memory. | |
TS.PCR IP.NTP ALP.PTP |
N/A | Mandatory: N/A
Optional: N/A |
N/A | N/A |
TS.RECORD |
N/A | Mandatory: DemuxFilterEvent::DemuxFilterTsRecordEvent[n] RecordStatus::DATA_READY RecordStatus::DATA_OVERFLOW RecordStatus::LOW_WATER RecordStatus::HIGH_WATER Optional: DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
For index data:for i=0; i<n; i For recorded content, according to RecordStatus::* and internal schedule, do
one of the following:
|
For index data: Carried in event payload. For recorded content: Muxed TS stream filled in FMQ. |
TS.TEMI |
N/A | Mandatory:DemuxFilterEvent::DemuxFilterTemiEvent[n] Optional: DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i |
N/A |
MMTP.MMTP |
N/A | Mandatory:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recommended: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
According to the event and internal schedule, runFilter.read(buffer, offset, adjustedSize) one or more
times.Data is copied from the HAL's MQ to the client buffer. |
Filtered out mmtp with mmtp headeris filled in FMQ. |
MMTP.RECORD |
N/A | Mandatory:DemuxFilterEvent::DemuxFilterMmtpRecordEvent[n] RecordStatus::DATA_READY RecordStatus::DATA_OVERFLOW RecordStatus::LOW_WATER RecordStatus::HIGH_WATER Optional: DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
For index data: for i=0; i<n; i For recorded content, according to RecordStatus::* and internal schedule, do one of the
following:
|
For index data: Carried in event payload. For recorded content: Muxed recorded stream filled in FMQ. If the filter source for recording is TLV.TLV to
IP.IP with passthrough, the recorded stream has a
TLV and IP header. |
MMTP.DOWNLOAD |
N/A | Mandatory:DemuxFilterEvent::DemuxFilterDownloadEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Optional: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i
Filter.read(buffer, offset, DemuxFilterDownloadEvent[i].size) Data is copied from HAL's MQ to the client buffer. |
Download package is filled in FMQ by another IP download package. |
IP.IP_PAYLOAD |
N/A | Mandatory:DemuxFilterEvent::DemuxFilterIpPayloadEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Optional: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i
Filter.read(buffer, offset, DemuxFilterIpPayloadEvent[i].size) Data is copied from HAL's MQ to the client buffer. |
IP payload package is filled in FMQ by another IP payload package. |
IP.IP TLV.TLV ALP.ALP |
isPassthrough: |
Optional:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW |
Filtered out protocol sub stream feeds the next filter in filter chain. | N/A |
isPassthrough: |
Mandatory:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recommended: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
According to the event and internal schedule, runFilter.read(buffer, offset, adjustedSize) one or more
times.Data is copied from the HAL's MQ to the client buffer. |
Filtered out protocol sub stream with protocol header is filled in FMQ. | |
IP.PAYLOAD_THROUGH TLV.PAYLOAD_THROUGH ALP.PAYLOAD_THROUGH |
N/A | Optional:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW |
Filtered out protocol payload feeds the next filter in filter chain. | N/A |
Example flow to use filter to build PSI/SI
Figure 10. Flow to build PSI/SI
Open a filter.
Filter filter = tuner.openFilter( Filter.TYPE_TS, Filter.SUBTYPE_SECTION, /* bufferSize */1000, executor, filterCallback );
Configure and start the filter.
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();
Process
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); } } } };
Example flow to use MediaEvent from filter
Figure 11. Flow to use MediaEvent from filter
- Open, configure, and start the A/V filters.
- Process
MediaEvent
. - Receive
MediaEvent
. - Queue the linear block to
codec
. - Release the A/V handle when the data has been consumed.
Android.media.tv.tuner.dvr
DvrRecorder
provides these methods for recording.
configure
attachFilter
detachFilter
start
flush
stop
setFileDescriptor
write
DvrPlayback
provides these methods for playback.
configure
start
flush
stop
setFileDescriptor
read
DvrSettings
is used to configure DvrRecorder
and DvrPlayback
.
OnPlaybackStatusChangedListener
and OnRecordStatusChangedListener
are used
to report the status of a DVR instance.
Example flow to start a record
Figure 12. Flow to start a record
Open, configure, and start
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();
Receive
RecordEvent
and retrieve the index information.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. } } } };
Initialize
OnRecordStatusChangedListener
and store the record data.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
The Tuner HAL follows HIDL and defines the interface between the framework and vendor hardware. Vendors use the interface to implement the Tuner HAL and the framework uses it to communicate with the Tuner HAL implementation.
Modules
Tuner HAL 1.0
Modules | Basic controls | Module-specific controls | HAL files |
---|---|---|---|
ITuner |
N/A | 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 |
Tuner HAL 1.1 (derived from Tuner HAL 1.0)
Modules | Basic controls | Module-specific controls | HAL files |
---|---|---|---|
ITuner |
N/A | 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 |
Figure 13. Diagram of the interactions between the Tuner HAL modules
Filter linkage
The Tuner HAL supports filter linkage such that filters can be linked to other filters for multiple layers. The filters follow the rules below.
- Filters are linked as a tree, close path is not allowed.
- The root node is demux.
- Filters operate independently.
- All filters start to get data.
- The filter linkage flushes on the last filter.
The code block below and Figure 14 illustrate an example of filtering multiple layers.
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>)
}
Figure 14. Flow diagram of a filter linkage for multiple layers
Tuner Resource Manager
Before Tuner Resource Manager (TRM), switching between two apps required the same Tuner hardware. TV Input Framework (TIF) used a "first-to-acquire win" mechanism, which means whichever app gets the resource first keeps the resource. However, this mechanism might not be ideal for some complicated use cases.
TRM runs as a system service to manage the Tuner, TVInput
, and CAS hardware
resources for apps. TRM uses a "foreground win" mechanism, which
calculates the app's priority based on the app's foreground or background
status and use case type. TRM grants or revokes the resource based on
the priority. TRM centralizes ATV resource management for broadcast, OTT,
and DVR.
TRM interface
TRM exposes AIDL interfaces in ITunerResourceManager.aidl
for the Tuner
framework, MediaCas
, and TvInputHardwareManager
to register, request, or
release resources.
Interfaces for client management are listed below.
registerClientProfile(in ResourceClientProfile profile, IResourcesReclaimListener listener, out int[] clientId)
unregisterClientProfile(in int clientId)
The interfaces to request and release resources are listed below.
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
Client and request classes are listed below.
ResourceClientProfile
ResourcesReclaimListener
TunerFrontendRequest
TunerDemuxRequest
TunerDescramblerRequest
CasSessionRequest
TunerLnbRequest
Client priority
TRM calculates the client's priority by using parameters from the client's profile and the priority value from the configuration file. The priority might also be updated by an arbitrary priority value from the client.
Parameters in client's profile
TRM retrieves the process ID from mTvInputSessionId
to decide whether an app
is a foreground or background app. To create mTvInputSessionId
,
TvInputService.onCreateSession
, or TvInputService.onCreateRecordingSession
initializes a TIS session.
mUseCase
indicates the session's use case. The predefined use cases are
listed below.
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
}
Configuration file
Default configuration file
The default configuration file below provides priority values for predefined use cases. Users can change the values using a customized configuration file.
Use case | Foreground | Background |
---|---|---|
LIVE |
490 | 400 |
PLAYBACK |
480 | 300 |
RECORD |
600 | 500 |
SCAN |
450 | 200 |
BACKGROUND |
180 | 100 |
Customized configuration file
Vendors can customize the configuration file
/vendor/etc/tunerResourceManagerUseCaseConfig.xml
. This file is used
to add, remove, or update the use case types and the use case priority values.
The customized file can use
platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml
as a template.
For example, a new vendor use case is VENDOR_USE_CASE__[A-Z0-9] , [0 - 1000]
.
The format should follow
platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd
.
Arbitrary priority value and nice value
TRM provides updateClientPriority
for the client to update the arbitrary
priority value and nice value.
The arbitrary priority value overwrites the priority value calculated
from use case type and session ID.
The nice value indicates how lenient the client's behavior is when it's in conflict with another client. The nice value decreases the client's priority value before its priority value is compared to the challenging client.
Reclaim mechanism
The diagram below shows how resources are reclaimed and assigned when a resource conflict happens.
Figure 15. Diagram of the reclaim mechanism for a conflict between Tuner resources