From 865220991aed181ca924f1ca97f268a7eeef7875 Mon Sep 17 00:00:00 2001 From: Henry Fang Date: Mon, 14 Oct 2019 13:49:21 -0700 Subject: [PATCH 1/3] Add Filter linkage and seperate interface Test: Manual bug: 135708935 Change-Id: I5782a183936ffca4f345d14c353ad34210f12df7 (cherry picked from commit e5125a89abc277b4f408966c8659878a123feff5) Merged-In: I5782a183936ffca4f345d14c353ad34210f12df7 --- tv/tuner/1.0/Android.bp | 8 +- tv/tuner/1.0/IDemux.hal | 332 +-- tv/tuner/1.0/IDescrambler.hal | 10 +- tv/tuner/1.0/IDvr.hal | 133 ++ tv/tuner/1.0/IDvrCallback.hal | 33 + tv/tuner/1.0/IFilter.hal | 143 ++ ...IDemuxCallback.hal => IFilterCallback.hal} | 26 +- tv/tuner/1.0/IFrontend.hal | 4 +- tv/tuner/1.0/IFrontendCallback.hal | 10 - tv/tuner/1.0/ILnb.hal | 26 +- tv/tuner/1.0/ILnbCallback.hal | 36 + tv/tuner/1.0/ITimeFilter.hal | 88 + tv/tuner/1.0/ITuner.hal | 16 +- tv/tuner/1.0/types.hal | 1930 +++++++++++++---- 14 files changed, 1988 insertions(+), 807 deletions(-) create mode 100644 tv/tuner/1.0/IDvr.hal create mode 100644 tv/tuner/1.0/IDvrCallback.hal create mode 100644 tv/tuner/1.0/IFilter.hal rename tv/tuner/1.0/{IDemuxCallback.hal => IFilterCallback.hal} (54%) create mode 100644 tv/tuner/1.0/ILnbCallback.hal create mode 100644 tv/tuner/1.0/ITimeFilter.hal diff --git a/tv/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp index 09265f7fce..d78f3f2f5c 100644 --- a/tv/tuner/1.0/Android.bp +++ b/tv/tuner/1.0/Android.bp @@ -9,15 +9,21 @@ hidl_interface { srcs: [ "types.hal", "IDemux.hal", - "IDemuxCallback.hal", "IDescrambler.hal", + "IDvr.hal", + "IDvrCallback.hal", + "IFilter.hal", + "IFilterCallback.hal", "IFrontend.hal", "IFrontendCallback.hal", "ILnb.hal", + "ILnbCallback.hal", + "ITimeFilter.hal", "ITuner.hal", ], interfaces: [ "android.hidl.base@1.0", + "android.hidl.safe_union@1.0", ], gen_java: false, gen_java_constants: true, diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal index 7ead34b00e..9e799b43f7 100644 --- a/tv/tuner/1.0/IDemux.hal +++ b/tv/tuner/1.0/IDemux.hal @@ -16,7 +16,11 @@ package android.hardware.tv.tuner@1.0; -import IDemuxCallback; +import IDvr; +import IDvrCallback; +import IFilter; +import IFilterCallback; +import ITimeFilter; /** * Demultiplexer(Demux) takes a single multiplexed input and splits it into @@ -24,7 +28,6 @@ import IDemuxCallback; * */ interface IDemux { - /** * Set a frontend resource as data input of the demux * @@ -39,134 +42,51 @@ interface IDemux { setFrontendDataSource(FrontendId frontendId) generates (Result result); /** - * Add a filter to the demux + * Open a new filter in the demux * - * It is used by the client to add a filter to the demux. + * It is used by the client to open a filter in the demux. * * @param type the type of the filter to be added. - * @param bufferSize the buffer size of the filter to be added. It's used to - * create a FMQ(Fast Message Queue) to hold data output from the filter. + * @param bufferSize the buffer size of the filter to be opened. It's used + * to create a FMQ(Fast Message Queue) to hold data output from the filter. * @param cb the callback for the filter to be used to send notifications * back to the client. * @return result Result status of the operation. * SUCCESS if successful, * INVALID_STATE if failed for wrong state. * UNKNOWN_ERROR if failed for other reasons. - * @return filterId the ID of the newly added filter. + * @return filter the filter instance of the newly added. */ - addFilter(DemuxFilterType type, uint32_t bufferSize, IDemuxCallback cb) - generates (Result result, DemuxFilterId filterId); + openFilter(DemuxFilterType type, uint32_t bufferSize, IFilterCallback cb) + generates (Result result, IFilter filter); /** - * Get the descriptor of the filter's FMQ + * Open time filter of the demux * - * It is used by the client to get the descriptor of the filter's Fast - * Message Queue. The data in FMQ is filtered out from MPEG transport - * stream. The data is origanized to data blocks which may have - * different length. The length's information of one or multiple data blocks - * is sent to client throught DemuxFilterEvent. + * It is used by the client to open time filter of the demux. * - * @param filterId the ID of the filter. * @return result Result status of the operation. * SUCCESS if successful, - * INVALID_ARGUMENT if failed for wrong filter ID. + * UNAVAILABLE if time filter is not supported. * INVALID_STATE if failed for wrong state. * UNKNOWN_ERROR if failed for other reasons. - * @return queue the descriptor of the filter's FMQ + * @return timeFilter the time filter instance of the newly added. */ - getFilterQueueDesc(DemuxFilterId filterId) - generates (Result result, fmq_sync queue); - - /** - * Configure the filter. - * - * It is used by the client to configure the filter so that it can filter out - * intended data. - * - * @param filterId the ID of the filter. - * @param settings the settings of the filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_ARGUMENT if failed for wrong filter ID. - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - configureFilter(DemuxFilterId filterId, DemuxFilterSettings settings) - generates(Result result); - - /** - * Start the filter. - * - * It is used by the client to ask the filter to start filterring data. - * - * @param filterId the ID of the filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_ARGUMENT if failed for wrong filter ID. - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - startFilter(DemuxFilterId filterId) generates (Result result); - - /** - * Stop the filter. - * - * It is used by the client to ask the filter to stop filterring data. - * It won't discard the data already filtered out by the filter. The filter - * will be stopped and removed automatically if the demux is closed. - * - * @param filterId the ID of the filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_ARGUMENT if failed for wrong filter ID. - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - stopFilter(DemuxFilterId filterId) generates (Result result); - - /** - * Flush the filter. - * - * It is used by the client to ask the filter to flush the data which is - * already produced but not consumed yet. - * - * @param filterId the ID of the filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_ARGUMENT if failed for wrong filter ID. - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - flushFilter(DemuxFilterId filterId) generates (Result result); - - /** - * Remove a filter from the demux - * - * It is used by the client to remove a filter from the demux. - * - * @param filterId the ID of the removed filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_ARGUMENT if failed for wrong filter ID. - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - removeFilter(DemuxFilterId filterId) generates (Result result); + openTimeFilter() generates (Result result, ITimeFilter timeFilter); /** * Get hardware sync ID for audio and video. * * It is used by the client to get the hardware sync ID for audio and video. * - * @param filterId the ID of the filter. + * @param filter the filter instance. * @return result Result status of the operation. * SUCCESS if successful, * INVALID_ARGUMENT if failed for a wrong filter ID. * UNKNOWN_ERROR if failed for other reasons. * @return avSyncHwId the id of hardware A/V sync. */ - getAvSyncHwId(DemuxFilterId filterId) - generates (Result result, AvSyncHwId avSyncHwId); + getAvSyncHwId(IFilter filter) generates (Result result, AvSyncHwId avSyncHwId); /** * Get current time stamp to use for A/V sync @@ -182,8 +102,7 @@ interface IDemux { * @return time the current time stamp of hardware A/V sync. The time stamp * based on 90KHz has the same format as PTS (Presentation Time Stamp). */ - getAvSyncTime(AvSyncHwId avSyncHwId) - generates (Result result, uint64_t time); + getAvSyncTime(AvSyncHwId avSyncHwId) generates (Result result, uint64_t time); /** * Close the Demux instance @@ -198,218 +117,21 @@ interface IDemux { close() generates (Result result); /** - * Add output to the demux + * Open a DVR (Digital Video Record) instance in the demux * - * It is used by the client to record output data from selected filters. + * It is used by the client to record and playback. * + * @param type specify which kind of DVR to open. * @param bufferSize the buffer size of the output to be added. It's used to * create a FMQ(Fast Message Queue) to hold data from selected filters. - * @param cb the callback for the demux to be used to send notifications + * @param cb the callback for the DVR to be used to send notifications * back to the client. * @return result Result status of the operation. * SUCCESS if successful, * OUT_OF_MEMORY if failed for not enough memory. * UNKNOWN_ERROR if failed for other reasons. + * @return dvr a DVR instance. */ - addOutput(uint32_t bufferSize, IDemuxCallback cb) generates (Result result); - - /** - * Get the descriptor of the output's FMQ - * - * It is used by the client to get the descriptor of the output's Fast - * Message Queue. The data in FMQ is muxed packets output from selected - * filters. The packet's format is specifed by DemuxDataFormat in - * DemuxOutputSettings. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * UNKNOWN_ERROR if failed for other reasons. - * @return queue the descriptor of the output's FMQ - */ - getOutputQueueDesc() generates (Result result, fmq_sync queue); - - /** - * Configure the demux's output. - * - * It is used by the client to configure the demux's output for recording. - * - * @param settings the settings of the demux's output. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - configureOutput(DemuxOutputSettings settings) generates (Result result); - - /** - * Attach one filter to the demux's output. - * - * It is used by the client to mux one filter's output to demux's output. - * - * @param filterId the ID of the attached filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - attachOutputFilter(DemuxFilterId filterId) generates (Result result); - - /** - * Detach one filter from the demux's output. - * - * It is used by the client to remove one filter's output from demux's - * output. - * - * @param filterId the ID of the detached filter. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - detachOutputFilter(DemuxFilterId filterId) generates (Result result); - - /** - * Start to take data to the demux's output. - * - * It is used by the client to ask the output to start to take data from - * attached filters. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - startOutput() generates (Result result); - - /** - * Stop to take data to the demux's output. - * - * It is used by the client to ask the output to stop to take data from - * attached filters. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - stopOutput() generates (Result result); - - /** - * Flush unconsumed data in the demux's output. - * - * It is used by the client to ask the demux to flush the data which is - * already produced but not consumed yet in the demux's output. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - flushOutput() generates (Result result); - - /** - * Remove the demux's output. - * - * It is used by the client to remove the demux's output. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - removeOutput() generates (Result result); - - /** - * Add input to the demux - * - * It is used by the client to add the demux's input for playback content. - * - * @param bufferSize the buffer size of the demux's input to be added. - * It's used to create a FMQ(Fast Message Queue) to hold input data. - * @param cb the callback for the demux to be used to send notifications - * back to the client. - * @return result Result status of the operation. - * SUCCESS if successful, - * OUT_OF_MEMORY if failed for not enough memory. - * UNKNOWN_ERROR if failed for other reasons. - */ - addInput(uint32_t bufferSize, IDemuxCallback cb) generates (Result result); - - /** - * Get the descriptor of the input's FMQ - * - * It is used by the client to get the descriptor of the input's Fast - * Message Queue. The data in FMQ is fed by client. Data format is specifed - * by DemuxDataFormat in DemuxInputSettings. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * UNKNOWN_ERROR if failed for other reasons. - * @return queue the descriptor of the output's FMQ - */ - getInputQueueDesc() generates (Result result, fmq_sync queue); - - /** - * Configure the demux's input. - * - * It is used by the client to configure the demux's input for playback. - * - * @param settings the settings of the demux's input. - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - configureInput(DemuxInputSettings settings) generates (Result result); - - /** - * Start to consume the data from the demux's input. - * - * It is used by the client to ask the demux to start to consume data from - * the demux's input. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - startInput() generates (Result result); - - /** - * Stop to consume the data from the demux's input. - * - * It is used by the client to ask the demux to stop to consume data from - * the demux's input. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - stopInput() generates (Result result); - - /** - * Flush unconsumed data in the demux's input. - * - * It is used by the client to ask the demux to flush the data which is - * already produced but not consumed yet in the demux's input. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - flushInput() generates (Result result); - - /** - * Remove the demux's input. - * - * It is used by the client to remove the demux's input. - * - * @return result Result status of the operation. - * SUCCESS if successful, - * INVALID_STATE if failed for wrong state. - * UNKNOWN_ERROR if failed for other reasons. - */ - removeInput() generates (Result result); + openDvr(DvrType type, uint32_t bufferSize, IDvrCallback cb) + generates (Result result, IDvr dvr); }; diff --git a/tv/tuner/1.0/IDescrambler.hal b/tv/tuner/1.0/IDescrambler.hal index 61ff1df4bd..7f98865c19 100644 --- a/tv/tuner/1.0/IDescrambler.hal +++ b/tv/tuner/1.0/IDescrambler.hal @@ -15,6 +15,9 @@ */ package android.hardware.tv.tuner@1.0; + +import IFilter; + /** * Descrambler is used to descramble input data. * @@ -59,12 +62,13 @@ interface IDescrambler { * packets from different PIDs. * * @param pid the PID of packets to start to be descrambled. + * @param filter an optional filter instance to identify upper stream. * @return result Result status of the operation. * SUCCESS if successful, * INVALID_STATE if failed for wrong state. * UNKNOWN_ERROR if failed for other reasons. */ - addPid(DemuxTpid pid) generates (Result result); + addPid(DemuxPid pid, IFilter optionalSourceFilter) generates (Result result); /** * Remove packets' PID from the descrambler @@ -73,12 +77,13 @@ interface IDescrambler { * descrambler stop to descramble. * * @param pid the PID of packets to stop to be descrambled. + * @param filter an optional filter instance to identify upper stream. * @return result Result status of the operation. * SUCCESS if successful, * INVALID_STATE if failed for wrong state. * UNKNOWN_ERROR if failed for other reasons. */ - removePid(DemuxTpid pid) generates (Result result); + removePid(DemuxPid pid, IFilter optionalSourceFilter) generates (Result result); /** * Release the descrambler instance @@ -92,4 +97,3 @@ interface IDescrambler { */ close() generates (Result result); }; - diff --git a/tv/tuner/1.0/IDvr.hal b/tv/tuner/1.0/IDvr.hal new file mode 100644 index 0000000000..f57e4b6768 --- /dev/null +++ b/tv/tuner/1.0/IDvr.hal @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.tv.tuner@1.0; + +import IFilter; + +/** + * Digtal Video Record (DVR) interface provides record control on Demux's + * output buffer and playback control on Demux's input buffer. + */ +interface IDvr { + /** + * Get the descriptor of the DVR's FMQ + * + * It is used by the client to get the descriptor of the DVR's Fast + * Message Queue. The FMQ is used to transfer record or playback data + * between the client and the HAL. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + * @return queue the descriptor of the DVR's FMQ + */ + getQueueDesc() generates (Result result, fmq_sync queue); + + /** + * Configure the DVR. + * + * It is used by the client to configure the DVR interface. + * + * @param settings the settings of the DVR interface. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + configure(DvrSettings settings) generates (Result result); + + /** + * Attach one filter to DVR interface for recording. + * + * It is used by the client to add the data filtered out from the filter + * to record. + * + * @param filter the instance of the attached filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + attachFilter(IFilter filter) generates (Result result); + + /** + * Detach one filter from the DVR's recording. + * + * It is used by the client to remove the data of the filter from DVR's + * recording. + * + * @param filter the instance of the detached filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + detachFilter(IFilter filter) generates (Result result); + + /** + * Start DVR. + * + * It is used by the client to ask the DVR to start consuming playback data + * or producing data for record. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + start() generates (Result result); + + /** + * Stop DVR. + * + * It is used by the client to ask the DVR to stop consuming playback data + * or producing data for record. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + stop() generates (Result result); + + /** + * Flush DVR data. + * + * It is used by the client to ask the DVR to flush the data which is + * not consumed by HAL for playback or the client for record yet. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + flush() generates (Result result); + + /** + * close the DVR instance to release resource for DVR. + * + * It is used by the client to close the DVR instance, and HAL clears + * underneath resource for this DVR instance. Client mustn't access the + * instance any more and all methods should return a failure. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + close() generates (Result result); +}; diff --git a/tv/tuner/1.0/IDvrCallback.hal b/tv/tuner/1.0/IDvrCallback.hal new file mode 100644 index 0000000000..337eddcede --- /dev/null +++ b/tv/tuner/1.0/IDvrCallback.hal @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.tv.tuner@1.0; + +interface IDvrCallback { + /** + * Notify the client a new status of the demux's record. + * + * @param status a new status of the demux's record. + */ + oneway onRecordStatus(RecordStatus status); + + /** + * Notify the client a new status of the demux's playback. + * + * @param status a new status of the demux's playback. + */ + oneway onPlaybackStatus(PlaybackStatus status); +}; diff --git a/tv/tuner/1.0/IFilter.hal b/tv/tuner/1.0/IFilter.hal new file mode 100644 index 0000000000..deaf3d473e --- /dev/null +++ b/tv/tuner/1.0/IFilter.hal @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.tv.tuner@1.0; + +import IFilterCallback; + +/** + * The Filter is used to filter wanted data according to the filter's + * configuration. + */ +interface IFilter { + /** + * Get the descriptor of the filter's FMQ + * + * It is used by the client to get the descriptor of the filter's Fast + * Message Queue. The data in FMQ is filtered out from demux input or upper + * stream's filter. The data is origanized to data blocks which may have + * different length. The length's information of one or multiple data blocks + * is sent to client through DemuxFilterEvent. The data in each block + * follows the stardard specified by filter's type. + * E.X. one data block from the filter with Main_Type==TS and Sub_Type==PES + * is Packetized Elementary Stream from Transport Stream according to + * ISO/IEC 13818-1. + * + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNAVAILABLE if the filter doesn't have FMQ. + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + * @return queue the descriptor of the filter's FMQ + */ + getQueueDesc() generates (Result result, fmq_sync queue); + + /** + * Configure the filter. + * + * It is used by the client to configure the filter so that it can filter out + * intended data. + * + * @param settings the settings of the filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + configure(DemuxFilterSettings settings) generates (Result result); + + /** + * Start the filter. + * + * It is used by the client to ask the filter to start filterring data. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + start() generates (Result result); + + /** + * Stop the filter. + * + * It is used by the client to ask the filter to stop filterring data. + * It won't discard the data already filtered out by the filter. The filter + * will be stopped and removed automatically if the demux is closed. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + stop() generates (Result result); + + /** + * Flush the filter. + * + * It is used by the client to ask the filter to flush the data which is + * already produced but not consumed yet. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + flush() generates (Result result); + + /** + * Get the filter Id. + * + * It is used by the client to ask the hardware resource id for the filter. + * + * @param filterId the hardware resource Id for the filter. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + getId() generates (Result result, uint32_t filterId); + + /** + * Set the filter's data source. + * + * A filter uses demux as data source by default. If the data was packetized + * by multiple protocols, multiple filters may need to work together to + * extract all protocols' header. Then a filter's data source can be output + * from another filter. + * + * @param filter the filter instance which provides data input. Switch to + * use demux as data source if the filter instance is NULL. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + */ + setDataSource(IFilter filter) generates (Result result); + + /** + * Release the Filter instance + * + * It is used by the client to release the Filter instance. HAL clear + * underneath resource. client mustn't access the instance any more. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + close() generates (Result result); +}; diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IFilterCallback.hal similarity index 54% rename from tv/tuner/1.0/IDemuxCallback.hal rename to tv/tuner/1.0/IFilterCallback.hal index 7bce9efeb1..a0ff62ead4 100644 --- a/tv/tuner/1.0/IDemuxCallback.hal +++ b/tv/tuner/1.0/IFilterCallback.hal @@ -16,34 +16,18 @@ package android.hardware.tv.tuner@1.0; -interface IDemuxCallback { +interface IFilterCallback { /** * Notify the client that a new filter event happened. * - * @param filterEvent a demux filter event. + * @param filterEvent a filter event. */ oneway onFilterEvent(DemuxFilterEvent filterEvent); /** - * Notify the client a new status of a demux filter. + * Notify the client a new status of a filter. * - * @param filterId the demux filter ID. - * @param status a new status of the demux filter. + * @param status a new status of the filter. */ - oneway onFilterStatus(DemuxFilterId filterId, DemuxFilterStatus status); - - /** - * Notify the client a new status of the demux's output. - * - * @param status a new status of the demux's output. - */ - oneway onOutputStatus(DemuxOutputStatus status); - - /** - * Notify the client a new status of the demux's input. - * - * @param status a new status of the demux's input. - */ - oneway onInputStatus(DemuxInputStatus status); + oneway onFilterStatus(DemuxFilterStatus status); }; - diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal index 962e4ba086..ceda2b32ee 100644 --- a/tv/tuner/1.0/IFrontend.hal +++ b/tv/tuner/1.0/IFrontend.hal @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package android.hardware.tv.tuner@1.0; import IFrontendCallback; @@ -126,7 +127,8 @@ interface IFrontend { * @return statuses an array of statuses which response the caller's * request. */ - getStatus(vec statusTypes) generates (Result result, vec statuses); + getStatus(vec statusTypes) + generates (Result result, vec statuses); /** * Sets Low-Noise Block downconverter (LNB) for satellite frontend. diff --git a/tv/tuner/1.0/IFrontendCallback.hal b/tv/tuner/1.0/IFrontendCallback.hal index 8896a09b62..88b96c474c 100644 --- a/tv/tuner/1.0/IFrontendCallback.hal +++ b/tv/tuner/1.0/IFrontendCallback.hal @@ -24,16 +24,6 @@ interface IFrontendCallback { */ oneway onEvent(FrontendEventType frontendEventType); - /** - * The callback function that must be called by HAL implementation to notify - * the client of new DiSEqC message. - * - * @param diseqcMessage a byte array of data for DiSEqC (Digital Satellite - * Equipment Control) message which is specified by EUTELSAT Bus Functional - * Specification Version 4.2. - */ - oneway onDiseqcMessage(vec diseqcMessage); - /** * The callback function that must be called by HAL implementation to notify * the client of scan messages. diff --git a/tv/tuner/1.0/ILnb.hal b/tv/tuner/1.0/ILnb.hal index 6b7119e046..5070519dcb 100644 --- a/tv/tuner/1.0/ILnb.hal +++ b/tv/tuner/1.0/ILnb.hal @@ -13,14 +13,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package android.hardware.tv.tuner@1.0; +import ILnbCallback; + /** * A Tuner LNB (low-noise block downconverter) is used by satellite frontend * to receive the microwave signal from the satellite, amplify it, and * downconvert the frequency to a lower frequency. */ interface ILnb { + /** + * Set the lnb callback. + * + * ILnbCallback is used by the client to receive events from the Lnb. + * Only one callback per ILnb instance is supported. The callback + * will be replaced if it's set again. + * + * @param callback Callback object to pass Lnb events to the system. + * The previously registered callback must be replaced with this one. + * It can be null. + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if callback can't be set at current stage, + * UNKNOWN_ERROR if callback setting failed for other reasons. + */ + setCallback(ILnbCallback callback) generates (Result result); + /** * Set the lnb's power voltage. * @@ -30,7 +50,7 @@ interface ILnb { * INVALID_ARGUMENT if the selected voltage isn't allowed, * UNKNOWN_ERROR if failed for other reasons. */ - setVoltage(FrontendLnbVoltage voltage) generates (Result result); + setVoltage(LnbVoltage voltage) generates (Result result); /** * Set the lnb's tone mode. @@ -41,7 +61,7 @@ interface ILnb { * INVALID_ARGUMENT if the selected tone mode isn't allowed, * UNKNOWN_ERROR if failed for other reasons. */ - setTone(FrontendLnbTone tone) generates (Result result); + setTone(LnbTone tone) generates (Result result); /** * Select the lnb's position. @@ -52,7 +72,7 @@ interface ILnb { * INVALID_ARGUMENT if the selected position isn't allowed, * UNKNOWN_ERROR if failed for other reasons. */ - setSatellitePosition(FrontendLnbPosition position) generates (Result result); + setSatellitePosition(LnbPosition position) generates (Result result); /** * Sends DiSEqC (Digital Satellite Equipment Control) message. diff --git a/tv/tuner/1.0/ILnbCallback.hal b/tv/tuner/1.0/ILnbCallback.hal new file mode 100644 index 0000000000..68e9c356f2 --- /dev/null +++ b/tv/tuner/1.0/ILnbCallback.hal @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.tv.tuner@1.0; + +interface ILnbCallback { + /** + * Notify the client that a new event happened on the Lnb. + * + * @param LnbEventType the event type. + */ + oneway onEvent(LnbEventType lnbEventType); + + /** + * The callback function that must be called by HAL implementation to notify + * the client of new DiSEqC message. + * + * @param diseqcMessage a byte array of data for DiSEqC (Digital Satellite + * Equipment Control) message which is specified by EUTELSAT Bus Functional + * Specification Version 4.2. + */ + oneway onDiseqcMessage(vec diseqcMessage); +}; diff --git a/tv/tuner/1.0/ITimeFilter.hal b/tv/tuner/1.0/ITimeFilter.hal new file mode 100644 index 0000000000..ce285dbb24 --- /dev/null +++ b/tv/tuner/1.0/ITimeFilter.hal @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.tv.tuner@1.0; + +/** + * Timer Filter is used by Demux to filter data based on time stamp. + */ +interface ITimeFilter { + /** + * Set time stamp for time based filter. + * + * It is used by the client to set initial time stamp and enable time + * filtering. The time will be incremented locally. The demux discards + * the content which time stamp is older than the time in the time filter. + * + * @param timeStamp initial time stamp for the time filter. It based on + * 90KHz has the same format as PTS (Presentation Time Stamp). + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + setTimeStamp(uint64_t timeStamp) generates (Result result); + + /** + * Clear the time stamp in the time filter. + * + * It is used by the client to clear the time value of the time filter, + * then disable time filter. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + clearTimeStamp() generates (Result result); + + /** + * Get the current time in the time filter. + * + * It is used by the client to inquiry current time in the time filter. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + * @return timeStamp current time stamp in the time filter. + */ + getTimeStamp() generates (Result result, uint64_t timeStamp); + + /** + * Get the time from the beginning of current data source. + * + * It is used by the client to inquiry the time stamp from the beginning + * of current data source. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * INVALID_STATE if failed for wrong state. + * UNKNOWN_ERROR if failed for other reasons. + * @return timeStamp time stamp from the beginning of current data source. + */ + getSourceTime() generates (Result result, uint64_t timeStamp); + + /** + * Close the Time Filter instance + * + * It is used by the client to release the demux instance. HAL clear + * underneath resource. client mustn't access the instance any more. + * + * @return result Result status of the operation. + * SUCCESS if successful, + * UNKNOWN_ERROR if failed for other reasons. + */ + close() generates (Result result); +}; diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal index 0d63442d07..2712c13708 100644 --- a/tv/tuner/1.0/ITuner.hal +++ b/tv/tuner/1.0/ITuner.hal @@ -50,8 +50,7 @@ interface ITuner { * UNKNOWN_ERROR if creation failed for other reasons. * @return frontend the newly created frontend interface. */ - openFrontendById(FrontendId frontendId) - generates (Result result, IFrontend frontend); + openFrontendById(FrontendId frontendId) generates (Result result, IFrontend frontend); /** * Create a new instance of Demux. @@ -64,8 +63,7 @@ interface ITuner { * @return demuxId newly created demux id. * @return demux the newly created demux interface. */ - openDemux() - generates (Result result, DemuxId demuxId, IDemux demux); + openDemux() generates (Result result, DemuxId demuxId, IDemux demux); /** * Retrieve the Demux's Capabilities. @@ -87,8 +85,7 @@ interface ITuner { * UNKNOWN_ERROR if creation failed for other reasons. * @return descrambler the newly created descrambler interface. */ - openDescrambler() - generates (Result result, IDescrambler descrambler); + openDescrambler() generates (Result result, IDescrambler descrambler); /** * Retrieve the frontend's information. @@ -99,8 +96,7 @@ interface ITuner { * UNKNOWN_ERROR if the inquiry failed for other reasons. * @return info the frontend's information. */ - getFrontendInfo(FrontendId frontendId) - generates (Result result, FrontendInfo info); + getFrontendInfo(FrontendId frontendId) generates (Result result, FrontendInfo info); /** * Get low-noise block downconverter (LNB) IDs. @@ -126,7 +122,5 @@ interface ITuner { * UNKNOWN_ERROR if creation failed for other reasons. * @return lnb the newly created Lnb interface. */ - openLnbById(LnbId lnbId) - generates (Result result, ILnb lnb); + openLnbById(LnbId lnbId) generates (Result result, ILnb lnb); }; - diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal index 897818b3df..a0cf0d9e6e 100644 --- a/tv/tuner/1.0/types.hal +++ b/tv/tuner/1.0/types.hal @@ -17,6 +17,7 @@ package android.hardware.tv.tuner@1.0; import android.hidl.safe_union@1.0; +import android.hidl.safe_union@1.0::Monostate; @export enum Result : int32_t { @@ -41,9 +42,13 @@ typedef uint32_t FrontendId; enum FrontendType : uint32_t { UNDEFINED = 0, ANALOG, - /* Advanced Television Systems Committee (ATSC) Standard A/72. */ + /** + * Advanced Television Systems Committee (ATSC) Standard A/72. + */ ATSC, - /* Advanced Television Systems Committee (ATSC 3.0) Standard A/300. */ + /** + * Advanced Television Systems Committee (ATSC 3.0) Standard A/300. + */ ATSC3, /** * Digital Video Broadcasting - Cable @@ -62,15 +67,18 @@ enum FrontendType : uint32_t { * ETSI EN 302 755 V1.4.1. */ DVBT, - /* Integrated Services Digital Broadcasting-Satellite (ISDB-S) + /** + * Integrated Services Digital Broadcasting-Satellite (ISDB-S) * ARIB STD-B20 is technical document of ISDB-S. */ ISDBS, - /* Integrated Services Digital Broadcasting-Satellite (ISDB-S) + /** + * Integrated Services Digital Broadcasting-Satellite (ISDB-S) * ARIB STD-B44 is technical document of ISDB-S3. */ ISDBS3, - /* Integrated Services Digital Broadcasting-Terrestrial (ISDB-T or SBTVD) + /** + * Integrated Services Digital Broadcasting-Terrestrial (ISDB-T or SBTVD) * ABNT NBR 15603 is technical document of ISDB-T. */ ISDBT, @@ -82,79 +90,153 @@ enum FrontendType : uint32_t { */ @export enum FrontendInnerFec : uint64_t { - /* Not defined */ + /** + * Not defined + */ FEC_UNDEFINED = 0, - /* hardware is able to detect and set FEC automatically */ + /** + * hardware is able to detect and set FEC automatically + */ AUTO = 1 << 0, - /* 1/2 conv. code rate */ + /** + * 1/2 conv. code rate + */ FEC_1_2 = 1 << 1, - /* 1/3 conv. code rate */ + /** + * 1/3 conv. code rate + */ FEC_1_3 = 1 << 2, - /* 1/4 conv. code rate */ + /** + * 1/4 conv. code rate + */ FEC_1_4 = 1 << 3, - /* 1/5 conv. code rate */ + /** + * 1/5 conv. code rate + */ FEC_1_5 = 1 << 4, - /* 2/3 conv. code rate */ + /** + * 2/3 conv. code rate + */ FEC_2_3 = 1 << 5, - /* 2/5 conv. code rate */ + /** + * 2/5 conv. code rate + */ FEC_2_5 = 1 << 6, - /* 2/9 conv. code rate */ + /** + * 2/9 conv. code rate + */ FEC_2_9 = 1 << 7, - /* 3/4 conv. code rate */ + /** + * 3/4 conv. code rate + */ FEC_3_4 = 1 << 8, - /* 3/5 conv. code rate */ + /** + * 3/5 conv. code rate + */ FEC_3_5 = 1 << 9, - /* 4/5 conv. code rate */ + /** + * 4/5 conv. code rate + */ FEC_4_5 = 1 << 10, - /* 4/15 conv. code rate */ + /** + * 4/15 conv. code rate + */ FEC_4_15 = 1 << 11, - /* 5/6 conv. code rate */ + /** + * 5/6 conv. code rate + */ FEC_5_6 = 1 << 12, - /* 5/9 conv. code rate */ + /** + * 5/9 conv. code rate + */ FEC_5_9 = 1 << 13, - /* 6/7 conv. code rate */ + /** + * 6/7 conv. code rate + */ FEC_6_7 = 1 << 14, - /* 7/8 conv. code rate */ + /** + * 7/8 conv. code rate + */ FEC_7_8 = 1 << 15, - /* 7/9 conv. code rate */ + /** + * 7/9 conv. code rate + */ FEC_7_9 = 1 << 16, - /* 7/15 conv. code rate */ + /** + * 7/15 conv. code rate + */ FEC_7_15 = 1 << 17, - /* 8/9 conv. code rate */ + /** + * 8/9 conv. code rate + */ FEC_8_9 = 1 << 18, - /* 8/15 conv. code rate */ + /** + * 8/15 conv. code rate + */ FEC_8_15 = 1 << 19, - /* 9/10 conv. code rate */ + /** + * 9/10 conv. code rate + */ FEC_9_10 = 1 << 20, - /* 9/20 conv. code rate */ + /** + * 9/20 conv. code rate + */ FEC_9_20 = 1 << 21, - /* 11/15 conv. code rate */ + /** + * 11/15 conv. code rate + */ FEC_11_15 = 1 << 22, - /* 11/20 conv. code rate */ + /** + * 11/20 conv. code rate + */ FEC_11_20 = 1 << 23, - /* 11/45 conv. code rate */ + /** + * 11/45 conv. code rate + */ FEC_11_45 = 1 << 24, - /* 13/18 conv. code rate */ + /** + * 13/18 conv. code rate + */ FEC_13_18 = 1 << 25, - /* 13/45 conv. code rate */ + /** + * 13/45 conv. code rate + */ FEC_13_45 = 1 << 26, - /* 14/45 conv. code rate */ + /** + * 14/45 conv. code rate + */ FEC_14_45 = 1 << 27, - /* 23/36 conv. code rate */ + /** + * 23/36 conv. code rate + */ FEC_23_36 = 1 << 28, - /* 25/36 conv. code rate */ + /** + * 25/36 conv. code rate + */ FEC_25_36 = 1 << 29, - /* 26/45 conv. code rate */ + /** + * 26/45 conv. code rate + */ FEC_26_45 = 1 << 30, - /* 28/45 conv. code rate */ + /** + * 28/45 conv. code rate + */ FEC_28_45 = 1 << 31, - /* 29/45 conv. code rate */ + /** + * 29/45 conv. code rate + */ FEC_29_45 = 1 << 32, - /* 31/45 conv. code rate */ + /** + * 31/45 conv. code rate + */ FEC_31_45 = 1 << 33, - /* 32/45 conv. code rate */ + /** + * 32/45 conv. code rate + */ FEC_32_45 = 1 << 34, - /* 77/90 conv. code rate */ + /** + * 77/90 conv. code rate + */ FEC_77_90 = 1 << 35, }; @@ -164,9 +246,11 @@ enum FrontendInnerFec : uint64_t { @export enum FrontendAtscModulation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set modulation automatically */ - AUTO = 1 << 0, - MOD_8VSB = 1 << 2, + /** + * hardware is able to detect and set modulation automatically + */ + AUTO = 1 << 0, + MOD_8VSB = 1 << 2, MOD_16VSB = 1 << 3, }; @@ -174,8 +258,11 @@ enum FrontendAtscModulation : uint32_t { * Signal Setting for ATSC Frontend. */ struct FrontendAtscSettings { - /** Signal frequencey in Herhz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + FrontendAtscModulation modulation; }; @@ -183,7 +270,9 @@ struct FrontendAtscSettings { * Capabilities for ATSC Frontend. */ struct FrontendAtscCapabilities { - /** Modulation capability */ + /** + * Modulation capability + */ bitfield modulationCap; }; @@ -193,12 +282,14 @@ struct FrontendAtscCapabilities { @export enum FrontendAtsc3Modulation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set modulation automatically */ - AUTO = 1 << 0, - MOD_QPSK = 1 << 1, - MOD_16QAM = 1 << 2, - MOD_64QAM = 1 << 3, - MOD_256QAM = 1 << 4, + /** + * hardware is able to detect and set modulation automatically + */ + AUTO = 1 << 0, + MOD_QPSK = 1 << 1, + MOD_16QAM = 1 << 2, + MOD_64QAM = 1 << 3, + MOD_256QAM = 1 << 4, MOD_1024QAM = 1 << 5, MOD_4096QAM = 1 << 6, }; @@ -209,7 +300,9 @@ enum FrontendAtsc3Modulation : uint32_t { @export enum FrontendAtsc3Bandwidth : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set bandwidth automatically */ + /** + * hardware is able to detect and set bandwidth automatically + */ AUTO = 1 << 0, BANDWIDTH_6MHZ = 1 << 1, BANDWIDTH_7MHZ = 1 << 2, @@ -222,10 +315,12 @@ enum FrontendAtsc3Bandwidth : uint32_t { @export enum FrontendAtsc3TimeInterleaveMode : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set TimeInterleaveMode automatically */ + /** + * hardware is able to detect and set TimeInterleaveMode automatically + */ AUTO = 1 << 0, - CTI = 1 << 1, - HTI = 1 << 2, + CTI = 1 << 1, + HTI = 1 << 2, }; /** @@ -234,20 +329,22 @@ enum FrontendAtsc3TimeInterleaveMode : uint32_t { @export enum FrontendAtsc3CodeRate : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Coderate automatically */ - AUTO = 1 << 0, - CODERATE_2_15 = 1 << 1, - CODERATE_3_15 = 1 << 2, - CODERATE_4_15 = 1 << 3, - CODERATE_5_15 = 1 << 4, - CODERATE_6_15 = 1 << 5, - CODERATE_7_15 = 1 << 6, - CODERATE_8_15 = 1 << 7, - CODERATE_9_15 = 1 << 8, - CODERATE_10_15 = 1 << 9, - CODERATE_11_15 = 1 << 10, - CODERATE_12_15 = 1 << 11, - CODERATE_13_15 = 1 << 12, + /** + * hardware is able to detect and set Coderate automatically + */ + AUTO = 1 << 0, + CODERATE_2_15 = 1 << 1, + CODERATE_3_15 = 1 << 2, + CODERATE_4_15 = 1 << 3, + CODERATE_5_15 = 1 << 4, + CODERATE_6_15 = 1 << 5, + CODERATE_7_15 = 1 << 6, + CODERATE_8_15 = 1 << 7, + CODERATE_9_15 = 1 << 8, + CODERATE_10_15 = 1 << 9, + CODERATE_11_15 = 1 << 10, + CODERATE_12_15 = 1 << 11, + CODERATE_13_15 = 1 << 12, }; /** @@ -256,14 +353,16 @@ enum FrontendAtsc3CodeRate : uint32_t { @export enum FrontendAtsc3Fec : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set FEC automatically */ - AUTO = 1 << 0, + /** + * hardware is able to detect and set FEC automatically + */ + AUTO = 1 << 0, BCH_LDPC_16K = 1 << 1, BCH_LDPC_64K = 1 << 2, CRC_LDPC_16K = 1 << 3, CRC_LDPC_64K = 1 << 4, - LDPC_16K = 1 << 5, - LDPC_64K = 1 << 6, + LDPC_16K = 1 << 5, + LDPC_64K = 1 << 6, }; /** @@ -271,12 +370,18 @@ enum FrontendAtsc3Fec : uint32_t { */ @export enum FrontendAtsc3DemodOutputFormat : uint8_t { - /** Dummy. Scan uses this. */ + /** + * Dummy. Scan uses this. + */ UNDEFINED = 0, - /** ALP format. Typically used in US region. */ + /** + * ALP format. Typically used in US region. + */ ATSC3_LINKLAYER_PACKET = 1 << 0, - /** BaseBand packet format. Typically used in Korea region. */ - BASEBAND_PACKET = 1 << 1, + /** + * BaseBand packet format. Typically used in Korea region. + */ + BASEBAND_PACKET = 1 << 1, }; /** @@ -284,9 +389,13 @@ enum FrontendAtsc3DemodOutputFormat : uint8_t { */ struct FrontendAtsc3PlpSettings { uint8_t plpId; + FrontendAtsc3Modulation modulation; + FrontendAtsc3TimeInterleaveMode interleaveMode; + FrontendAtsc3CodeRate codeRate; + FrontendAtsc3Fec fec; }; @@ -294,11 +403,18 @@ struct FrontendAtsc3PlpSettings { * Signal Settings for an ATSC3 Frontend. */ struct FrontendAtsc3Settings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; - /** Bandwidth of tuning band. */ + + /** + * Bandwidth of tuning band. + */ FrontendAtsc3Bandwidth bandwidth; + FrontendAtsc3DemodOutputFormat demodOutputFormat; + vec plpSettings; }; @@ -306,17 +422,34 @@ struct FrontendAtsc3Settings { * Capabilities for ATSC3 Frontend. */ struct FrontendAtsc3Capabilities { - /** Bandwidth capability */ + /** + * Bandwidth capability + */ bitfield bandwidthCap; - /** Modulation capability */ + + /** + * Modulation capability + */ bitfield modulationCap; - /** TimeInterleaveMode capability */ + + /** + * TimeInterleaveMode capability + */ bitfield timeInterleaveModeCap; - /** CodeRate capability */ + + /** + * CodeRate capability + */ bitfield codeRateCap; - /** FEC capability */ + + /** + * FEC capability + */ bitfield fecCap; - /** Demodulator Output Format capability */ + + /** + * Demodulator Output Format capability + */ bitfield demodOutputFormatCap; }; @@ -326,7 +459,9 @@ struct FrontendAtsc3Capabilities { @export enum FrontendDvbsModulation : int32_t { UNDEFINED = 0, - /** hardware is able to detect and set Modulation automatically */ + /** + * hardware is able to detect and set Modulation automatically + */ AUTO = 1 << 0, MOD_QPSK = 1 << 1, MOD_8PSK = 1 << 2, @@ -340,7 +475,9 @@ enum FrontendDvbsModulation : int32_t { MOD_64APSK = 1 << 10, MOD_128APSK = 1 << 11, MOD_256APSK = 1 << 12, - /** Reserved for Proprietary modulation */ + /** + * Reserved for Proprietary modulation + */ MOD_RESERVED = 1 << 13, }; @@ -374,10 +511,17 @@ enum FrontendDvbsPilot : uint32_t { */ struct FrontendDvbsCodeRate { FrontendInnerFec fec; + bool isLinear; - /* true if enable short frame */ + + /** + * true if enable short frame + */ bool isShortFrames; - /* bits number in 1000 symbol. 0 if use the default. */ + + /** + * bits number in 1000 symbol. 0 if use the default. + */ uint32_t bitsPer1000Symbol; }; @@ -396,15 +540,26 @@ enum FrontendDvbsStandard : uint8_t { * Signal Settings for an DVBS Frontend. */ struct FrontendDvbsSettings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + FrontendDvbsModulation modulation; + FrontendDvbsCodeRate coderate; - /** Symbols per second */ + + /** + * Symbols per second + */ uint32_t symbolRate; + FrontendDvbsRolloff rolloff; + FrontendDvbsPilot pilot; + uint32_t inputStreamId; + FrontendDvbsStandard standard; }; @@ -413,8 +568,10 @@ struct FrontendDvbsSettings { */ struct FrontendDvbsCapabilities { bitfield modulationCap; + bitfield innerfecCap; - bitfield standard; + + bitfield standard; }; /** @@ -423,7 +580,9 @@ struct FrontendDvbsCapabilities { @export enum FrontendDvbcModulation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Modulation automatically */ + /** + * hardware is able to detect and set Modulation automatically + */ AUTO = 1 << 0, MOD_16QAM = 1 << 1, MOD_32QAM = 1 << 2, @@ -467,14 +626,24 @@ enum FrontendDvbcSpectralInversion : uint32_t { * Signal Settings for an DVBC Frontend. */ struct FrontendDvbcSettings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + FrontendDvbcModulation modulation; + FrontendInnerFec fec; - /** Symbols per second */ + + /** + * Symbols per second + */ uint32_t symbolRate; + FrontendDvbcOuterFec outerFec; + FrontendDvbcAnnex annex; + FrontendDvbcSpectralInversion spectralInversion; }; @@ -483,7 +652,9 @@ struct FrontendDvbcSettings { */ struct FrontendDvbcCapabilities { bitfield modulationCap; + bitfield fecCap; + bitfield annexCap; }; @@ -493,7 +664,9 @@ struct FrontendDvbcCapabilities { @export enum FrontendDvbtBandwidth : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Bandwidth automatically */ + /** + * hardware is able to detect and set Bandwidth automatically + */ AUTO = 1 << 0, BANDWIDTH_8MHZ = 1 << 1, BANDWIDTH_7MHZ = 1 << 2, @@ -509,7 +682,9 @@ enum FrontendDvbtBandwidth : uint32_t { @export enum FrontendDvbtConstellation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Constellation automatically */ + /** + * hardware is able to detect and set Constellation automatically + */ AUTO = 1 << 0, CONSTELLATION_QPSK = 1 << 1, CONSTELLATION_16QAM = 1 << 2, @@ -523,7 +698,9 @@ enum FrontendDvbtConstellation : uint32_t { @export enum FrontendDvbtHierarchy : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Hierarchy automatically */ + /** + * hardware is able to detect and set Hierarchy automatically + */ AUTO = 1 << 0, HIERARCHY_NON_NATIVE = 1 << 1, HIERARCHY_1_NATIVE = 1 << 2, @@ -541,7 +718,9 @@ enum FrontendDvbtHierarchy : uint32_t { @export enum FrontendDvbtCoderate : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Hierarchy automatically */ + /** + * hardware is able to detect and set Hierarchy automatically + */ AUTO = 1 << 0, CODERATE_1_2 = 1 << 1, CODERATE_2_3 = 1 << 2, @@ -560,7 +739,9 @@ enum FrontendDvbtCoderate : uint32_t { @export enum FrontendDvbtGuardInterval : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Guard Interval automatically */ + /** + * hardware is able to detect and set Guard Interval automatically + */ AUTO = 1 << 0, INTERVAL_1_32 = 1 << 1, INTERVAL_1_16 = 1 << 2, @@ -577,7 +758,9 @@ enum FrontendDvbtGuardInterval : uint32_t { @export enum FrontendDvbtTransmissionMode : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Transmission Mode automatically */ + /** + * hardware is able to detect and set Transmission Mode automatically + */ AUTO = 1 << 0, MODE_2K = 1 << 1, MODE_8K = 1 << 2, @@ -607,27 +790,50 @@ enum FrontendDvbtStandard : uint8_t { }; /** - * Signal Setting for DVBT Frontend. + * Signal Settings for DVBT Frontend. */ struct FrontendDvbtSettings { - /** Signal frequencey in Herhz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + FrontendDvbtTransmissionMode transmissionMode; + FrontendDvbtBandwidth bandwidth; + FrontendDvbtConstellation constellation; + FrontendDvbtHierarchy hierarchy; - /** Code Rate for High Priority level */ + + /** + * Code Rate for High Priority level + */ FrontendDvbtCoderate hpCoderate; - /** Code Rate for Low Priority level */ + + /** + * Code Rate for Low Priority level + */ FrontendDvbtCoderate lpCoderate; + FrontendDvbtGuardInterval guardInterval; + bool isHighPriority; + FrontendDvbtStandard standard; + bool isMiso; + FrontendDvbtPlpMode plpMode; - /** Physical Layer Pipe (PLP) Id */ + + /** + * Physical Layer Pipe (PLP) Id + */ uint8_t plpId; - /** Group Id for Physical Layer Pipe (PLP) */ + + /** + * Group Id for Physical Layer Pipe (PLP) + */ uint8_t plpGroupId; }; @@ -636,12 +842,19 @@ struct FrontendDvbtSettings { */ struct FrontendDvbtCapabilities { bitfield transmissionModeCap; + bitfield bandwidthCap; + bitfield constellationCap; + bitfield coderateCap; + bitfield hierarchyCap; + bitfield guardIntervalCap; + bool isT2Supported; + bool isMisoSupported; }; @@ -660,11 +873,13 @@ enum FrontendIsdbsRolloff : uint32_t { @export enum FrontendIsdbsModulation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Modulation automatically */ - AUTO = 1 << 0, - MOD_BPSK = 1 << 1, - MOD_QPSK = 1 << 2, - MOD_TC8PSK = 1 << 3, + /** + * hardware is able to detect and set Modulation automatically + */ + AUTO = 1 << 0, + MOD_BPSK = 1 << 1, + MOD_QPSK = 1 << 2, + MOD_TC8PSK = 1 << 3, }; /** @@ -673,13 +888,15 @@ enum FrontendIsdbsModulation : uint32_t { @export enum FrontendIsdbsCoderate : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Code Rate automatically */ - AUTO = 1 << 0, - CODERATE_1_2 = 1 << 1, - CODERATE_2_3 = 1 << 2, - CODERATE_3_4 = 1 << 3, - CODERATE_5_6 = 1 << 4, - CODERATE_7_8 = 1 << 5, + /** + * hardware is able to detect and set Code Rate automatically + */ + AUTO = 1 << 0, + CODERATE_1_2 = 1 << 1, + CODERATE_2_3 = 1 << 2, + CODERATE_3_4 = 1 << 3, + CODERATE_5_6 = 1 << 4, + CODERATE_7_8 = 1 << 5, }; /** @@ -692,17 +909,27 @@ enum FrontendIsdbsStreamIdType : uint32_t { }; /** - * Signal Setting for ISDBS Frontend. + * Signal Settings for ISDBS Frontend. */ struct FrontendIsdbsSettings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + uint16_t streamId; + FrontendIsdbsStreamIdType streamIdType; + FrontendIsdbsModulation modulation; + FrontendIsdbsCoderate coderate; - /** Symbols per second */ + + /** + * Symbols per second + */ uint32_t symbolRate; + FrontendIsdbsRolloff rolloff; }; @@ -711,6 +938,7 @@ struct FrontendIsdbsSettings { */ struct FrontendIsdbsCapabilities { bitfield modulationCap; + bitfield coderateCap; }; @@ -729,13 +957,15 @@ enum FrontendIsdbs3Rolloff : uint32_t { @export enum FrontendIsdbs3Modulation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Modulation automatically */ - AUTO = 1 << 5, - MOD_BPSK = 1 << 1, - MOD_QPSK = 1 << 2, - MOD_8PSK = 1 << 3, - MOD_16APSK = 1 << 4, - MOD_32APSK = 1 << 5, + /** + * hardware is able to detect and set Modulation automatically + */ + AUTO = 1 << 5, + MOD_BPSK = 1 << 1, + MOD_QPSK = 1 << 2, + MOD_8PSK = 1 << 3, + MOD_16APSK = 1 << 4, + MOD_32APSK = 1 << 5, }; /** @@ -744,33 +974,45 @@ enum FrontendIsdbs3Modulation : uint32_t { @export enum FrontendIsdbs3Coderate : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Code Rate automatically */ - AUTO = 1 << 0, - CODERATE_1_3 = 1 << 1, - CODERATE_2_5 = 1 << 2, - CODERATE_1_2 = 1 << 3, - CODERATE_3_5 = 1 << 4, - CODERATE_2_3 = 1 << 5, - CODERATE_3_4 = 1 << 6, - CODERATE_7_9 = 1 << 7, - CODERATE_4_5 = 1 << 8, - CODERATE_5_6 = 1 << 9, - CODERATE_7_8 = 1 << 10, - CODERATE_9_10 = 1 << 11, + /** + * hardware is able to detect and set Code Rate automatically + */ + AUTO = 1 << 0, + CODERATE_1_3 = 1 << 1, + CODERATE_2_5 = 1 << 2, + CODERATE_1_2 = 1 << 3, + CODERATE_3_5 = 1 << 4, + CODERATE_2_3 = 1 << 5, + CODERATE_3_4 = 1 << 6, + CODERATE_7_9 = 1 << 7, + CODERATE_4_5 = 1 << 8, + CODERATE_5_6 = 1 << 9, + CODERATE_7_8 = 1 << 10, + CODERATE_9_10 = 1 << 11, }; /** - * Signal Setting for ISDBS3 Frontend. + * Signal Settings for ISDBS3 Frontend. */ struct FrontendIsdbs3Settings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + uint16_t streamId; + FrontendIsdbsStreamIdType streamIdType; + FrontendIsdbs3Modulation modulation; + FrontendIsdbs3Coderate coderate; - /** Symbols per second */ + + /** + * Symbols per second + */ uint32_t symbolRate; + FrontendIsdbs3Rolloff rolloff; }; @@ -779,6 +1021,7 @@ struct FrontendIsdbs3Settings { */ struct FrontendIsdbs3Capabilities { bitfield modulationCap; + bitfield coderateCap; }; @@ -788,7 +1031,9 @@ struct FrontendIsdbs3Capabilities { @export enum FrontendIsdbtMode : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Mode automatically */ + /** + * hardware is able to detect and set Mode automatically + */ AUTO = 1 << 0, MODE_1 = 1 << 1, MODE_2 = 1 << 2, @@ -801,7 +1046,9 @@ enum FrontendIsdbtMode : uint32_t { @export enum FrontendIsdbtBandwidth : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Bandwidth automatically */ + /** + * hardware is able to detect and set Bandwidth automatically + */ AUTO = 1 << 0, BANDWIDTH_8MHZ = 1 << 1, BANDWIDTH_7MHZ = 1 << 2, @@ -814,7 +1061,9 @@ enum FrontendIsdbtBandwidth : uint32_t { @export enum FrontendIsdbtModulation : uint32_t { UNDEFINED = 0, - /** hardware is able to detect and set Modulation automatically */ + /** + * hardware is able to detect and set Modulation automatically + */ AUTO = 1 << 0, MOD_DQPSK = 1 << 1, MOD_QPSK = 1 << 2, @@ -822,23 +1071,29 @@ enum FrontendIsdbtModulation : uint32_t { MOD_64QAM = 1 << 4, }; -/** Code Rate for ISDBT. */ typedef FrontendDvbtCoderate FrontendIsdbtCoderate; -/** Guard Interval for ISDBT. */ typedef FrontendDvbtGuardInterval FrontendIsdbtGuardInterval; /** - * Signal Setting for ISDBT Frontend. + * Signal Settings for ISDBT Frontend. */ struct FrontendIsdbtSettings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + FrontendIsdbtModulation modulation; + FrontendIsdbtBandwidth bandwidth; + FrontendIsdbtMode mode; + FrontendIsdbtCoderate coderate; + FrontendIsdbtGuardInterval guardInterval; + uint32_t serviceAreaId; }; @@ -847,9 +1102,13 @@ struct FrontendIsdbtSettings { */ struct FrontendIsdbtCapabilities { bitfield modeCap; + bitfield bandwidthCap; + bitfield constellationCap; + bitfield coderateCap; + bitfield guardIntervalCap; }; @@ -872,7 +1131,7 @@ enum FrontendAnalogSifStandard : uint32_t { UNDEFINED = 0, BG = 1 << 0, BG_A2 = 1 << 1, - BG_NICAM = 1 << 2, + BG_NICAM = 1 << 2, I = 1 << 3, DK = 1 << 4, DK1 = 1 << 5, @@ -890,12 +1149,16 @@ enum FrontendAnalogSifStandard : uint32_t { }; /** - * Signal Setting for Analog Frontend. + * Signal Settings for Analog Frontend. */ struct FrontendAnalogSettings { - /** Signal frequency in Hertz */ + /** + * Signal frequency in Hertz + */ uint32_t frequency; + FrontendAnalogType type; + FrontendAnalogSifStandard sifStandard; }; @@ -904,21 +1167,30 @@ struct FrontendAnalogSettings { */ struct FrontendAnalogCapabilities { bitfield typeCap; + bitfield sifStandardCap; }; /** - * Signal Setting for Frontend. + * Signal Settings for Frontend. */ safe_union FrontendSettings { FrontendAnalogSettings analog; + FrontendAtscSettings atsc; + FrontendAtsc3Settings atsc3; + FrontendDvbsSettings dvbs; + FrontendDvbcSettings dvbc; + FrontendDvbtSettings dvbt; + FrontendIsdbsSettings isdbs; + FrontendIsdbs3Settings isdbs3; + FrontendIsdbtSettings isdbt; }; @@ -935,25 +1207,45 @@ enum FrontendScanType : uint32_t { * Scan Message Type for Frontend. */ enum FrontendScanMessageType : uint32_t { - /** Scan locked the signal. */ + /** + * Scan locked the signal. + */ LOCKED, - /** Scan stopped. */ + /** + * Scan stopped. + */ END, - /** Scan progress report. */ + /** + * Scan progress report. + */ PROGRESS_PERCENT, - /** Locked frequency report. */ + /** + * Locked frequency report. + */ FREQUENCY, - /** Locked symbol rate. */ + /** + * Locked symbol rate. + */ SYMBOL_RATE, - /** Locked Plp Ids for DVBT2 frontend. */ + /** + * Locked Plp Ids for DVBT2 frontend. + */ PLP_IDS, - /** Locked group Ids for DVBT2 frontend. */ + /** + * Locked group Ids for DVBT2 frontend. + */ GROUP_IDS, - /** Stream Ids. */ + /** + * Stream Ids. + */ INPUT_STREAM_IDS, - /** Locked signal stardard. */ + /** + * Locked signal standard. + */ STANDARD, - /** PLP status in a tuned frequency band for ATSC3 frontend. */ + /** + * PLP status in a tuned frequency band for ATSC3 frontend. + */ ATSC3_PLP_INFO, }; @@ -962,6 +1254,7 @@ enum FrontendScanMessageType : uint32_t { */ struct FrontendScanAtsc3PlpInfo { uint8_t plpId; + bool bLlsFlag; }; @@ -969,22 +1262,40 @@ struct FrontendScanAtsc3PlpInfo { * Scan Message for Frontend. */ safe_union FrontendScanMessage { - bool islocked; + bool isLocked; + bool isEnd; - /** scan progress percent (0..100) */ + + /** + * scan progress percent (0..100) + */ uint8_t progressPercent; - /** Signal frequency in Hertz */ + + /** + * Signal frequency in Hertz + */ uint32_t frequency; - /** Symbols per second */ + + /** + * Symbols per second + */ uint32_t symbolRate; + vec plpIds; + vec groupIds; + vec inputStreamIds; + safe_union standard { FrontendDvbsStandard sStd; + FrontendDvbtStandard tStd; } std; - /** A list of PLP status in a tuned frequency band for ATSC3 frontend. */ + + /** + * A list of PLP status in a tuned frequency band for ATSC3 frontend. + */ vec atsc3PlpInfos; }; @@ -1008,22 +1319,6 @@ enum FrontendEventType : uint32_t { * event. */ LOST_LOCK, - /** - * If frontend detect that incoming Diseqc message is overflow. - */ - DISEQC_RX_OVERFLOW, - /** - * If frontend detect that outgoing Diseqc message isn't delivered on time. - */ - DISEQC_RX_TIMEOUT, - /** - * If frontend detect that the incoming Diseqc message has parity error. - */ - DISEQC_RX_PARITY_ERROR, - /** - * If frontend detect that the LNB is overload. - */ - LNB_OVERLOAD, }; /** @@ -1031,60 +1326,106 @@ enum FrontendEventType : uint32_t { */ @export enum FrontendStatusType : uint32_t { - /** Lock status for Demod. */ + /** + * Lock status for Demod. + */ DEMOD_LOCK, - /** Signal to Noise Ratio. */ + /** + * Signal to Noise Ratio. + */ SNR, - /** Bit Error Ratio. */ + /** + * Bit Error Ratio. + */ BER, - /** Packages Error Ratio. */ + /** + * Packages Error Ratio. + */ PER, - /** Bit Error Ratio before FEC. */ + /** + * Bit Error Ratio before FEC. + */ PRE_BER, - /* + /** * Signal Quality (0..100). Good data over total data in percent can be * used as a way to present Signal Quality. */ SIGNAL_QUALITY, - /** Signal Strength. */ + /** + * Signal Strength. + */ SIGNAL_STRENGTH, - /** Symbol Rate. */ + /** + * Symbol Rate. + */ SYMBOL_RATE, - /** Forward Error Correction Type. */ + /** + * Forward Error Correction Type. + */ FEC, - /** Modulation Type. */ + /** + * Modulation Type. + */ MODULATION, - /** Spectral Inversion Type. */ + /** + * Spectral Inversion Type. + */ SPECTRAL, - /** LNB Voltage. */ + /** + * LNB Voltage. + */ LNB_VOLTAGE, - /** Physical Layer Pipe ID. */ + /** + * Physical Layer Pipe ID. + */ PLP_ID, - /** Status for Emergency Warning Broadcasting System. */ + /** + * Status for Emergency Warning Broadcasting System. + */ EWBS, - /** Automatic Gain Control. */ + /** + * Automatic Gain Control. + */ AGC, - /** Low Noise Amplifier. */ + /** + * Low Noise Amplifier. + */ LNA, - /** Lock status for stream. */ - STREAM_LOCK, - /** Error status by layer. */ + /** + * Error status by layer. + */ LAYER_ERROR, - /** CN value by VBER. */ + /** + * CN value by VBER. + */ VBER_CN, - /** CN value by LBER. */ + /** + * CN value by LBER. + */ LBER_CN, - /** CN value by XER. */ + /** + * CN value by XER. + */ XER_CN, - /** Moduration Error Ratio. */ + /** + * Moduration Error Ratio. + */ MER, - /** Difference between tuning frequency and actual locked frequency. */ + /** + * Difference between tuning frequency and actual locked frequency. + */ FREQ_OFFSET, - /* Hierarchy for DVBT. */ + /** + * Hierarchy for DVBT. + */ HIERARCHY, - /** Lock status for RF. */ + /** + * Lock status for RF. + */ RF_LOCK, - /** PLP information in a frequency band for ATSC3.0 frontend. */ + /** + * PLP information in a frequency band for ATSC3.0 frontend. + */ ATSC3_PLP_INFO, }; @@ -1092,23 +1433,34 @@ enum FrontendStatusType : uint32_t { * Status for each tuning PLPs */ struct FrontendStatusAtsc3PlpInfo { - /** PLP Id value. */ + /** + * PLP Id value. + */ uint8_t plpId; - /** Demod Lock/Unlock status of this particular PLP. */ + + /** + * Demod Lock/Unlock status of this particular PLP. + */ bool isLocked; - /** Uncorrectable Error Counts (UEC) of this particular PLP since last tune operation. */ + + /** + * Uncorrectable Error Counts (UEC) of this particular PLP since last tune operation. + */ uint32_t uec; }; - /** * Modulation Type for Frontend's status. */ safe_union FrontendModulationStatus { FrontendDvbcModulation dvbc; + FrontendDvbsModulation dvbs; + FrontendIsdbsModulation isdbs; + FrontendIsdbs3Modulation isdbs3; + FrontendIsdbtModulation isdbt; }; @@ -1116,46 +1468,99 @@ safe_union FrontendModulationStatus { * The status for Frontend. */ safe_union FrontendStatus { - /** Lock status for Demod in True/False. */ + /** + * Lock status for Demod in True/False. + */ bool isDemodLocked; - /** SNR value measured by 0.001 dB. */ + + /** + * SNR value measured by 0.001 dB. + */ int32_t snr; - /** The number of error bit per 1 billion bits. */ + + /** + * The number of error bit per 1 billion bits. + */ uint32_t ber; - /** The number of error package per 1 billion packages. */ + + /** + * The number of error package per 1 billion packages. + */ uint32_t per; - /** The number of error bit per 1 billion bits before FEC. */ + + /** + * The number of error bit per 1 billion bits before FEC. + */ uint32_t preBer; - /** Signal Quality in percent. */ + + /** + * Signal Quality in percent. + */ uint32_t signalQuality; - /** Signal Strength measured by 0.001 dBm. */ + + /** + * Signal Strength measured by 0.001 dBm. + */ int32_t signalStrength; - /** Symbols per second */ + + /** + * Symbols per second + */ uint32_t symbolRate; + FrontendInnerFec innerFec; + FrontendModulationStatus modulation; + FrontendDvbcSpectralInversion inversion; - FrontendLnbVoltage lnbVoltage; + + LnbVoltage lnbVoltage; + uint8_t plpId; + bool isEWBS; - /** AGC value is normalized from 0 to 255. */ + + /** + * AGC value is normalized from 0 to 255. + */ uint8_t agc; + bool isLnaOn; - bool isStreamLock; + vec isLayerError; - /** CN value by VBER measured by 0.001 dB */ + + /** + * CN value by VBER measured by 0.001 dB + */ int32_t vberCn; - /** CN value by LBER measured by 0.001 dB */ + + /** + * CN value by LBER measured by 0.001 dB + */ int32_t lberCn; - /** CN value by XER measured by 0.001 dB */ + + /** + * CN value by XER measured by 0.001 dB + */ int32_t xerCn; - /** MER value measured by 0.001 dB */ + + /** + * MER value measured by 0.001 dB + */ int32_t mer; - /** Frequency difference in Hertz. */ + + /** + * Frequency difference in Hertz. + */ int32_t freqOffset; + FrontendDvbtHierarchy hierarchy; + bool isRfLocked; - /** A list of PLP status for tuned PLPs for ATSC3 frontend. */ + + /** + * A list of PLP status for tuned PLPs for ATSC3 frontend. + */ vec plpInfo; }; @@ -1164,32 +1569,60 @@ safe_union FrontendStatus { */ struct FrontendInfo { FrontendType type; - /** Frequency in Hertz */ + + /** + * Frequency in Hertz + */ uint32_t minFrequency; - /** Frequency in Hertz */ + + /** + * Frequency in Hertz + */ uint32_t maxFrequency; - /** Minimum symbols per second */ + + /** + * Minimum symbols per second + */ uint32_t minSymbolRate; - /** Maximum symbols per second */ + + /** + * Maximum symbols per second + */ uint32_t maxSymbolRate; - /** Range in Hertz */ + + /** + * Range in Hertz + */ uint32_t acquireRange; - /* + + /** * Frontends are assigned with the same exclusiveGroupId if they can't * function at same time. For instance, they share same hardware module. */ uint32_t exclusiveGroupId; - /** A list of supported status types which client can inquiry */ + + /** + * A list of supported status types which client can inquiry + */ vec statusCaps; + safe_union FrontendCapabilities { FrontendAnalogCapabilities analogCaps; + FrontendAtscCapabilities atscCaps; + FrontendAtsc3Capabilities atsc3Caps; + FrontendDvbsCapabilities dvbsCaps; + FrontendDvbcCapabilities dvbcCaps; + FrontendDvbtCapabilities dvbtCaps; + FrontendIsdbsCapabilities isdbsCaps; + FrontendIsdbs3Capabilities isdbs3Caps; + FrontendIsdbtCapabilities isdbtCaps; } frontendCaps; }; @@ -1204,7 +1637,7 @@ typedef uint32_t LnbId; * Power Voltage Type for LNB. */ @export -enum FrontendLnbVoltage : uint32_t { +enum LnbVoltage : uint32_t { NONE, VOLTAGE_5V, VOLTAGE_11V, @@ -1220,7 +1653,7 @@ enum FrontendLnbVoltage : uint32_t { * Tone Type for LNB. */ @export -enum FrontendLnbTone : int32_t { +enum LnbTone : int32_t { NONE, CONTINUOUS, }; @@ -1229,41 +1662,92 @@ enum FrontendLnbTone : int32_t { * The Position of LNB. */ @export -enum FrontendLnbPosition : int32_t { +enum LnbPosition : int32_t { UNDEFINED, POSITION_A, POSITION_B, }; +/** + * Lnb Event Type. + */ +@export +enum LnbEventType : uint32_t { + DISEQC_RX_OVERFLOW, + /** + * If LNB detect that outgoing Diseqc message isn't delivered on time. + */ + DISEQC_RX_TIMEOUT, + /** + * If LNB detect that the incoming Diseqc message has parity error. + */ + DISEQC_RX_PARITY_ERROR, + /** + * If LNB detect that the LNB is overload. + */ + LNB_OVERLOAD, +}; + /* Demux ID is used to associate with a hardware demux resource. */ typedef uint32_t DemuxId; -/* Filter ID is used to associate with a hardware filter resource. */ -typedef uint32_t DemuxFilterId; - /** - * Filter Type according to ISO/IEC 13818-1 + * Filter Main Type specifies the protocol that the filter use to extract data + * from input stream. */ @export -enum DemuxFilterType : uint32_t { +enum DemuxFilterMainType : uint32_t { /** - * A filter to filter section data out from input stream. + * Transport Stream according to ISO/IEC 13818-1. + */ + TS = 1 << 0, + /** + * MPEG Media Transport Protocol according to ISO/IEC 23008-1. + */ + MMTP = 1 << 1, + /** + * Internet Protocol. + */ + IP = 1 << 2, + /** + * Type Length Value according to ITU-R BT.1869. + */ + TLV = 1 << 3, + /** + * ATSC Link-Layer Protocol according to A/330 ATSC3.0. + */ + ALP = 1 << 4, +}; + +/** + * TS Filter Type according to ISO/IEC 13818-1 + */ +@export +enum DemuxTsFilterType : uint32_t { + UNDEFINED, + /** + * A filter to filter Section data out from input stream, and queue the + * data to the filter's FMQ (Fast Message Queue). */ SECTION, /** - * A filter to filter PES data out from input stream. + * A filter to filter Packetized Elementary Stream data out from input + * stream, and queue the data to the filter's FMQ. */ PES, /** - * A filter to filter TS payload out from input stream. + * A filter to filter a Transport Stream out from input stream, and queue + * the data to the filter's FMQ. */ TS, /** - * A filter to filter Audio Metadata out from input stream. + * A filter to filter Audio data out from input stream, and send Audio's + * Metadata to client through onFilterEvent. */ AUDIO, /** - * A filter to filter Video Metadata out from input stream. + * A filter to filter Video data out from input stream, and send Video's + * Metadata to client through onFilterEvent. */ VIDEO, /** @@ -1271,20 +1755,172 @@ enum DemuxFilterType : uint32_t { */ PCR, /** - * A filter to filter data directly to output buffer for record. + * A filter to filter data out from input stream, and queue the data to the + * buffer of the record. */ RECORD, }; +/** + * MMTP Filter Type according to ISO/IEC 23008-1 + */ +@export +enum DemuxMmtpFilterType : uint32_t { + UNDEFINED, + /** + * A filter to filter signaling data out from input stream, and queue the + * data to the filter's FMQ (Fast Message Queue). + */ + SECTION, + /** + * A filter to filter MFU (Media fragment unit) out from input stream, and + * queue the data to the filter's FMQ. + */ + PES, + /** + * A filter to filter a MMTP stream out from input stream, and queue the + * data to the filter's FMQ. + */ + MMTP, + /** + * A filter to filter Audio data out from input stream, and send Audio's + * Metadata to client through onFilterEvent. + */ + AUDIO, + /** + * A filter to filter Video data out from input stream, and send Video's + * Metadata to client through onFilterEvent. + */ + VIDEO, + /** + * A filter to filter data out from input stream, and queue the data to the + * buffer of the record. + */ + RECORD, + /** + * A filter to filter application data out from input stream, and queue the + * data to the filter's FMQ. + */ + DOWNLOAD, +}; + +/** + * IP Filter Type. + */ +@export +enum DemuxIpFilterType : uint32_t { + UNDEFINED, + /** + * A filter to filter section data out from input stream, and queue the + * data to the filter's FMQ (Fast Message Queue). + */ + SECTION, + /** + * A filter to set NTP (Network Time Procotol) channel from input stream. + */ + NTP, + /** + * A filter to strip out IP message header and queue the data to the + * filter's FMQ. + */ + IP_PAYLOAD, + /** + * A filter to filter a IP stream out from input stream. The output can be + * either upper stream of another filter or queued to the filter's FMQ. + */ + IP, + /** + * A filter to strip out IP message header and be a data source of another + * filter. + */ + PAYLOAD_THROUGH, +}; + +/** + * TLV Filter Type according to ITU-R BT.1869. + */ +@export +enum DemuxTlvFilterType : uint32_t { + UNDEFINED, + /** + * A filter to filter signaling data out from input stream, and queue the + * data to the filter's FMQ (Fast Message Queue). + */ + SECTION, + /** + * A filter to filter a TLV stream out from input stream. The output can be + * either upper stream of another filter or queued to the filter's FMQ. + */ + TLV, + /** + * A filter to strip out TLV message header and be a data source of another + * filter. + */ + PAYLOAD_THROUGH, +}; + +/** + * ALP Filter Type according to A/330 ATSC3.0. + */ +@export +enum DemuxAlpFilterType : uint32_t { + UNDEFINED, + /** + * A filter to filter signaling data out from input stream, and queue the + * data to the filter's FMQ (Fast Message Queue). + */ + SECTION, + /** + * A filter to set PTP (Precision Time Protocol) channel from input stream. + */ + PTP, + /** + * A filter to strip out ALP message header and be a data source of another + * filter. + */ + PAYLOAD_THROUGH, +}; + +/** + * Demux Filter Type. + */ +struct DemuxFilterType { + DemuxFilterMainType mainType; + + safe_union DemuxFilterSubType { + DemuxTsFilterType tsFilterType; + + DemuxMmtpFilterType mmtpFilterType; + + DemuxIpFilterType ipFilterType; + + DemuxTlvFilterType tlvFilterType; + + DemuxAlpFilterType alpFilterType; + } subType; +}; + /* Packet ID is used to specify packets in transport stream. */ typedef uint16_t DemuxTpid; +/* Packet ID is used to specify packets in MMTP */ +typedef uint16_t DemuxMmtpPid; + +/** + * Demux Packet ID. + */ +safe_union DemuxPid { + DemuxTpid tPid; + + DemuxMmtpPid mmtpPid; +}; + @export enum Constant : uint16_t { /** * An invalid packet ID in transport stream according to ISO/IEC 13818-1. */ - INVALID_TPID = 0xFFFF, + INVALID_TS_PID = 0xFFFF, /** * An invalid Stream ID. */ @@ -1304,7 +1940,7 @@ enum DemuxFilterStatus : uint8_t { * The available data amount in the filter buffer is at low level which is * set to 25 percent by default. */ - LOW_WATER = 1 << 1, + LOW_WATER = 1 << 1, /** * The available data amount in the filter buffer is at high level which is * set to 75 percent by default. @@ -1314,18 +1950,122 @@ enum DemuxFilterStatus : uint8_t { * The data in the filter buffer is full and newly filtered data is being * discarded. */ - OVERFLOW = 1 << 3, + OVERFLOW = 1 << 3, }; /** - * Bits Setting for Section Filter. + * Indexes can be tagged through TS (Transport Stream) header. + */ +@export +enum DemuxTsIndex : uint32_t { + FIRST_PACKET = 1 << 0, + PAYLOAD_UNIT_START_INDICATOR = 1 << 1, + CHANGE_TO_NOT_SCRAMBLED = 1 << 2, + CHANGE_TO_EVEN_SCRAMBLED = 1 << 3, + CHANGE_TO_ODD_SCRAMBLED = 1 << 4, + DISCONTINUITY_INDICATOR = 1 << 5, + RANDOM_ACCESS_INDICATOR = 1 << 6, + PRIORITY_INDICATOR = 1 << 7, + PCR_FLAG = 1 << 8, + OPCR_FLAG = 1 << 9, + SPLICING_POINT_FLAG = 1 << 10, + PRIVATE_DATA = 1 << 11, + ADAPTATION_EXTENSION_FLAG = 1 << 12, +}; + +/** + * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream) + * according to ISO/IEC 13818-1. + */ +@export +enum DemuxScIndex : uint32_t { + /** + * Start Code is for a new I Frame + */ + I_FRAME = 1 << 0, + /** + * Start Code is for a new P Frame + */ + P_FRAME = 1 << 1, + /** + * Start Code is for a new B Frame + */ + B_FRAME = 1 << 2, + /** + * Start Code is for a new Sequence + */ + SEQUENCE = 1 << 3, +}; + +/** + * Indexes can be tagged by NAL unit group in HEVC + * according to ISO/IEC 23008-2. + */ +@export +enum DemuxScHevcIndex : uint32_t { + SPS = 1 << 0, + AUD = 1 << 1, + SLICE_CE_BLA_W_LP = 1 << 2, + SLICE_BLA_W_RADL = 1 << 3, + SLICE_BLA_N_LP = 1 << 4, + SLICE_IDR_W_RADL = 1 << 5, + SLICE_IDR_N_LP = 1 << 6, + SLICE_TRAIL_CRA = 1 << 7, +}; + +/** + * Index type to be used in the filter for record + */ +@export +enum DemuxRecordIndexType : uint32_t { + /** + * Don't use index + */ + NONE, + /** + * Use TS index + */ + TS, + /** + * Use Start Code index + */ + SC, + /** + * Use Start Code index for HEVC + */ + SC_HEVC, +}; + +/** + * Filter Settings for Record data. + */ +struct DemuxFilterRecordSettings { + DemuxRecordIndexType indexType; + + safe_union IndexMask { + bitfield tsIndexMask; + + bitfield scIndexMask; + + bitfield scHevcIndexMask; + } indexMask; +}; + +/** + * Bits Settings for Section Filter. */ struct DemuxFilterSectionBits { - /* The bytes are configured for Section Filter */ + /** + * The bytes are configured for Section Filter + */ vec filter; - /* Active bits in the configured bytes to be used for filtering */ + + /** + * Active bits in the configured bytes to be used for filtering + */ vec mask; - /* + + /** * Do positive match at the bit position of the configured bytes when the * bit at same position of the mode is 0. * Do negative match at the bit position of the configured bytes when the @@ -1338,45 +2078,56 @@ struct DemuxFilterSectionBits { * Filter Settings for Section data according to ISO/IEC 13818-1. */ struct DemuxFilterSectionSettings { - DemuxTpid tpid; - DemuxFilterSectionBits bits; - /* Table ID for Section Filter */ - uint16_t tableId; - /* Version number for Section Filter */ - uint16_t version; - /* true if the filter checks CRC and discards data with wrong CRC */ + safe_union Condition { + DemuxFilterSectionBits sectionBits; + + struct TableInfo { + /** + * Table ID for Section Filter + */ + uint16_t tableId; + + /** + * Version number for Section Filter + */ + uint16_t version; + } tableInfo; + } condition; + + /** + * true if the filter checks CRC and discards data with wrong CRC + */ bool isCheckCrc; - /* true if the filter repeats the data with the same version */ + + /** + * true if the filter repeats the data with the same version + */ bool isRepeat; - /* true if the filter output raw data */ + + /** + * true if the filter send onFilterStatus instead of onFilterEvent. + */ bool isRaw; }; -/* Stream ID is used to specify one elementary stream */ typedef uint16_t DemuxStreamId; /** * Filter Settings for a PES Data. */ struct DemuxFilterPesDataSettings { - DemuxTpid tpid; DemuxStreamId streamId; - /* true if the filter output raw data */ + + /** + * true if the filter send onFilterStatus instead of onFilterEvent. + */ bool isRaw; }; /** - * Filter Settings for a TS Data. + * Filter Settings for a Video and Audio. */ -struct DemuxFilterTsSettings { - DemuxTpid tpid; -}; - -/** - * Filter Settings for a Audio. - */ -struct DemuxFilterAudioSettings { - DemuxTpid tpid; +struct DemuxFilterAvSettings { /** * true if the filter output goes to decoder directly in pass through mode. */ @@ -1384,107 +2135,181 @@ struct DemuxFilterAudioSettings { }; /** - * Filter Settings for a Video. + * Filter Settings for a Download. */ -struct DemuxFilterVideoSettings { +struct DemuxFilterDownloadSettings { + uint32_t downloadId; +}; + +/** + * IP Settings for a IP filter. + */ +struct DemuxIpAddress { + safe_union SrcIpAddress { + uint8_t[4] v4; + + uint8_t[16] v6; + } srcIpAddress; + + safe_union DstIpAddress { + uint8_t[4] v4; + + uint8_t[16] v6; + } dstIpAddress; + + uint16_t srcPort; + + uint16_t dstPort; +}; + +/** + * Filter Settings for a TS filter. + */ +struct DemuxTsFilterSettings { DemuxTpid tpid; + + safe_union FilterSettings { + /** + * Not additional parameters. it's used by PCR, TS subtype filters. + */ + Monostate noinit; + + DemuxFilterSectionSettings section; + + DemuxFilterAvSettings av; + + DemuxFilterPesDataSettings pesData; + + DemuxFilterRecordSettings record; + } filterSettings; +}; + +/** + * Filter Settings for a MMTP filter. + */ +struct DemuxMmtpFilterSettings { + DemuxMmtpPid mmtpPid; + + safe_union FilterSettings { + /** + * Not additional parameters. it's used by MMTP subtype filters. + */ + Monostate noinit; + + DemuxFilterSectionSettings section; + + DemuxFilterAvSettings av; + + DemuxFilterPesDataSettings pesData; + + DemuxFilterRecordSettings record; + + DemuxFilterDownloadSettings download; + } filterSettings; +}; + +/** + * Filter Settings for a IP filter. + */ +struct DemuxIpFilterSettings { + DemuxIpAddress ipAddr; + + safe_union FilterSettings { + /** + * Not additional parameters. it's used by NTP, IP_PAYLOAD, + * PAYLOAD_THROUGH subtype filters. + */ + Monostate noinit; + + DemuxFilterSectionSettings section; + + DemuxFilterPesDataSettings pesData; + + /** + * true if the data from IP subtype go to next filter directly + */ + bool bPassthrough; + } filterSettings; +}; + +/** + * Filter Settings for a TLV filter. + */ +struct DemuxTlvFilterSettings { + uint8_t packetType; + /** - * true if the filter output goes to decoder directly in pass through mode. + * true if the filtered data is commpressed ip packet */ - bool isPassthrough; + bool bIsCompressedIpPacket; + + safe_union FilterSettings { + /** + * Not additional parameters. it's used by PAYLOAD_THROUGH subtype + * filters. + */ + Monostate noinit; + + DemuxFilterSectionSettings section; + + /** + * true if the data from TLV subtype go to next filter directly + */ + bool bPassthrough; + } filterSettings; }; /** - * Filter Settings for a PCR (Program Clock Reference). - */ -struct DemuxFilterPcrSettings { - DemuxTpid tpid; -}; - -/** - * Indexes can be tagged through TS (Transport Stream) header. + * ALP Length Type */ @export -enum DemuxTsIndex : uint32_t { - FIRST_PACKET = 1 << 0, - PAYLOAD_UNIT_START_INDICATOR = 1 << 1, - CHANGE_TO_NOT_SCRAMBLED = 1 << 2, - CHANGE_TO_EVEN_SCRAMBLED = 1 << 3, - CHANGE_TO_ODD_SCRAMBLED = 1 << 4, - DISCONTINUITY_INDICATOR = 1 << 5, - RANDOM_ACCESS_INDICATOR = 1 << 6, - PRIORITY_INDICATOR = 1 << 7, - PCR_FLAG = 1 << 8, - OPCR_FLAG = 1 << 9, - SPLICING_POINT_FLAG = 1 << 10, - PRIVATE_DATA = 1 << 11, - ADAPTATION_EXTENSION_FLAG = 1 << 12, +enum DemuxAlpLengthType : uint8_t { + UNDEFINED = 0, + /** + * Length does NOT include additional header. Used in US region. + */ + WITHOUT_ADDITIONAL_HEADER, + /** + * Length includes additional header. Used in Korea region. + */ + WITH_ADDITIONAL_HEADER, }; /** - * A mask of TS indexes - * - * It's a combination of TS indexes. + * Filter Settings for a ALP filter. */ -typedef bitfield DemuxTsIndexMask; +struct DemuxAlpFilterSettings { + /** + * 0: IpV4, 2:Compressed Ip, 4:Signaling. + */ + uint8_t packetType; -/** - * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream) - * according to ISO/IEC 13818-1. - */ -@export -enum DemuxScIndex : uint32_t { - /* Start Code is for a new I Frame */ - I_FRAME = 1 << 0, - /* Start Code is for a new P Frame */ - P_FRAME = 1 << 1, - /* Start Code is for a new B Frame */ - B_FRAME = 1 << 2, - /* Start Code is for a new Sequence */ - SEQUENCE = 1 << 3, -}; + DemuxAlpLengthType lengthType; -/** - * A mask of Start Code Indexes - * - * It's a combination of Start Code Indexes. - */ -typedef bitfield DemuxScIndexMask; + safe_union FilterSettings { + /** + * Not additional parameters. it's used by PTP, PAYLOAD_THROUGH subtype + * filters. + */ + Monostate noinit; -/* Index type to be used in the filter for record */ -@export -enum DemuxRecordIndexType : uint32_t { - /* Don't use index */ - NONE, - /* Use TS index */ - TS, - /* Use Start Code index */ - SC, -}; - -/** - * Filter Settings for Record data. - */ -struct DemuxFilterRecordSettings { - DemuxTpid tpid; - DemuxRecordIndexType indexType; - safe_union IndexMask { - DemuxTsIndexMask tsIndexMask; - DemuxScIndexMask scIndexMask; - } indexMask; + DemuxFilterSectionSettings section; + } filterSettings; }; /** * Filter Settings. */ safe_union DemuxFilterSettings { - DemuxFilterSectionSettings section; - DemuxFilterPesDataSettings pesData; - DemuxFilterTsSettings ts; - DemuxFilterAudioSettings audio; - DemuxFilterVideoSettings video; - DemuxFilterPcrSettings pcr; - DemuxFilterRecordSettings record; + DemuxTsFilterSettings ts; + + DemuxMmtpFilterSettings mmtp; + + DemuxIpFilterSettings ip; + + DemuxTlvFilterSettings tlv; + + DemuxAlpFilterSettings alp; }; /** @@ -1493,38 +2318,106 @@ safe_union DemuxFilterSettings { */ @export enum DemuxQueueNotifyBits : uint32_t { - /* client writes data and notify HAL the data is ready. */ + /** + * client writes data and notify HAL the data is ready. + */ DATA_READY = 1 << 0, - /* client reads data and notify HAL the data is consumed. */ - DATA_CONSUMED = 1 << 1 + /** + * client reads data and notify HAL the data is consumed. + */ + DATA_CONSUMED = 1 << 1, }; /** * Filter Event for Section Filter. */ struct DemuxFilterSectionEvent { - /* Table ID of filtered data */ + /** + * Table ID of filtered data + */ uint16_t tableId; - /* Version number of filtered data */ + + /** + * Version number of filtered data + */ uint16_t version; - /* Section number of filtered data */ + + /** + * Section number of filtered data + */ uint16_t sectionNum; - /* Data size in bytes of filtered data */ + + /** + * Data size in bytes of filtered data + */ uint16_t dataLength; }; +/** + * Extra Meta Data from AD (Audio Descriptor) according to + * ETSI TS 101 154 V2.1.1. + */ +struct AudioExtraMetaData { + uint8_t adFade; + + uint8_t adPan; + + uint8_t versionTextTag; + + uint8_t adGainCenter; + + uint8_t adGainFront; + + uint8_t adGainSurround; +}; + /** * Filter Event for Audio or Video Filter. */ struct DemuxFilterMediaEvent { - /* Presentation Time Stamp for audio or video frame. It based on 90KHz has + DemuxStreamId streamId; + + /** + * true if PTS is present in PES header. + */ + bool isPtsPresent; + + /** + * Presentation Time Stamp for audio or video frame. It based on 90KHz has * the same format as PTS (Presentation Time Stamp). */ uint64_t pts; - /* Data size in bytes of audio or video frame */ - uint16_t dataLength; - /* A handle associated to the memory where audio or video data stays. */ - handle secureMemory; + + /** + * Data size in bytes of audio or video frame + */ + uint32_t dataLength; + + /** + * A handle associated to the memory where audio or video data stays. + */ + handle avMemory; + + /** + * True if the avMemory is in secure area, and isn't mappable. + */ + bool isSecureMemory; + + /** + * MPU sequence number of filtered data (only for MMTP) + */ + uint32_t mpuSequenceNumber; + + bool isPesPrivateData; + + safe_union ExtraMetaData { + /** + * Not additional parameters. it's used for video. + */ + Monostate noinit; + + AudioExtraMetaData audio; + } extraMetaData; }; /** @@ -1532,176 +2425,309 @@ struct DemuxFilterMediaEvent { */ struct DemuxFilterPesEvent { DemuxStreamId streamId; - /* Data size in bytes of PES data */ + + /** + * Data size in bytes of PES data + */ + uint16_t dataLength; + + /** + * MPU sequence number of filtered data (only for MMTP) + */ + uint32_t mpuSequenceNumber; +}; + +/** + * Filter Event for TS Record data. + */ +struct DemuxFilterTsRecordEvent { + DemuxPid pid; + + /** + * Indexes of record output + */ + safe_union IndexMask { + bitfield tsIndexMask; + + bitfield scIndexMask; + + bitfield scHevcIndexMask; + } indexMask; + + /** + * Byte number from beginning of the filter's output + */ + uint64_t byteNumber; +}; + +/** + * Filter Event for MMTP Record data. + */ +struct DemuxFilterMmtpRecordEvent { + bitfield scHevcIndexMask; + + /** + * Byte number from beginning of the filter's output + */ + uint64_t byteNumber; +}; + +/** + * Filter Event for Download data. + */ +struct DemuxFilterDownloadEvent { + uint32_t itemId; + + /** + * MPU sequence number of filtered data (only for MMTP) + */ + uint32_t mpuSequenceNumber; + + uint32_t itemFragmentIndex; + + uint32_t lastItemFragmentIndex; + + /** + * Data size in bytes of filtered data + */ uint16_t dataLength; }; /** - * Filter Event for Record data. + * Filter Event for IP payload data. */ -struct DemuxFilterRecordEvent { - DemuxTpid tpid; - /* Indexes of record output */ - safe_union IndexMask { - DemuxTsIndexMask tsIndexMask; - DemuxScIndexMask scIndexMask; - } indexMask; - /* Packet number from beginning of the filter's output */ - uint64_t packetNum; +struct DemuxFilterIpPayloadEvent { + /** + * Data size in bytes of IP data + */ + uint16_t dataLength; }; /** * Filter Event. */ struct DemuxFilterEvent { - DemuxFilterId filterId; - DemuxFilterType filterType; safe_union Event { DemuxFilterSectionEvent section; + DemuxFilterMediaEvent media; + DemuxFilterPesEvent pes; - DemuxFilterRecordEvent ts; + + DemuxFilterTsRecordEvent tsRecord; + + DemuxFilterMmtpRecordEvent mmtpRecord; + + DemuxFilterDownloadEvent download; + + DemuxFilterIpPayloadEvent ipPayload; }; - /* An array of events */ + + /** + * An array of events + */ vec events; }; -/** - * A hardware resource ID to be used for audio and video hardware sync. - */ typedef uint32_t AvSyncHwId; -/** - * A token to be used to link descrambler and key slot. It's opaque to - * framework and apps. - */ typedef vec TunerKeyToken; /** * A data format in demux's output or input according to ISO/IEC 13818-1. */ @export -enum DemuxDataFormat : uint32_t { - /* Data is Transport Stream. */ +enum DataFormat : uint32_t { + /** + * Data is Transport Stream. + */ TS, - /* Data is Packetized Elementary Stream. */ + /** + * Data is Packetized Elementary Stream. + */ PES, - /* Data is Elementary Stream. */ + /** + * Data is Elementary Stream. + */ ES, - /* Data is TLV (type-length-value) Stream for JP SHV */ + /** + * Data is TLV (type-length-value) Stream for JP SHV + */ SHV_TLV, }; -/** - * A status of the demux's output. - */ -typedef DemuxFilterStatus DemuxOutputStatus; +typedef DemuxFilterStatus RecordStatus; /** - * The Settings for the demux's output. + * The Settings for the record in DVR. */ -struct DemuxOutputSettings { +struct RecordSettings { /** * Register for interested status events so that the HAL can send these * status events back to client. */ - bitfield statusMask; + bitfield statusMask; + /** - * Unconsumed data size in bytes in the output. The HAL uses it to trigger - * DemuxOutputStatus::LOW_WATER. + * Unconsumed data size in bytes in the record. The HAL uses it to trigger + * OutputStatus::LOW_WATER. */ uint32_t lowThreshold; + /** - * Unconsumed data size in bytes in the output. The HAL uses it to trigger - * DemuxOutputStatus::High_WATER. + * Unconsumed data size in bytes in the record. The HAL uses it to trigger + * OutputStatus::High_WATER. */ uint32_t highThreshold; + /** - * The data format in the output. + * The data format in the record. */ - DemuxDataFormat dataFormat; + DataFormat dataFormat; + /** - * The packet size in bytes in the output. + * The packet size in bytes in the record. */ uint8_t packetSize; }; /** - * A status of the demux's input. + * A status of the playback in DVR. */ @export -enum DemuxInputStatus : uint32_t { +enum PlaybackStatus : uint32_t { /** - * The space of the demux's input is empty. + * The space of the demux's playback is empty. */ - SPACE_EMPTY = 1 << 0, + SPACE_EMPTY = 1 << 0, /** - * The spece of the demux's input is almost empty. + * The spece of the demux's playback is almost empty. */ SPACE_ALMOST_EMPTY = 1 << 1, /** - * The space of the demux's input is almost full. + * The space of the demux's playback is almost full. */ - SPACE_ALMOST_FULL = 1 << 2, + SPACE_ALMOST_FULL = 1 << 2, /** - * The space of the demux's input is full. + * The space of the demux's playback is full. */ - SPACE_FULL = 1 << 3, + SPACE_FULL = 1 << 3, }; /** - * The Settings for the demux's input. + * The Setting for the playback in DVR. */ -@export -struct DemuxInputSettings { +struct PlaybackSettings { /** * Register for interested status events so that the HAL can send these * status events back to client. */ - bitfield statusMask; + bitfield statusMask; + /** - * Unused space size in bytes in the input. The HAL uses it to trigger - * DemuxInputStatus::SPACE_ALMOST_EMPTY. + * Unused space size in bytes in the playback. The HAL uses it to trigger + * InputStatus::SPACE_ALMOST_EMPTY. */ uint32_t lowThreshold; + /** - * Unused space size in bytes in the input. The HAL uses it to trigger - * DemuxInputStatus::SPACE_ALMOST_FULL. + * Unused space size in bytes in the playback. The HAL uses it to trigger + * InputStatus::SPACE_ALMOST_FULL. */ uint32_t highThreshold; + /** - * The data format in the input. + * The data format in the playback. */ - DemuxDataFormat dataFormat; + DataFormat dataFormat; + /** - * The packet size in bytes in the input. + * The packet size in bytes in the playback. */ uint8_t packetSize; }; +/** + * The type of DVR. + */ +@export +enum DvrType : uint8_t { + RECORD, + PLAYBACK, +}; + +/** + * The Setting for DVR. + */ +safe_union DvrSettings { + RecordSettings record; + + PlaybackSettings playback; +}; + /** * Capabilities for Demux. */ -@export struct DemuxCapabilities { - /* The number of Demux to be supported. */ + /** + * The number of Demux to be supported. + */ uint32_t numDemux; - /* The number of Input to be supported. */ - uint32_t numInput; - /* The number of Output to be supported. */ - uint32_t numOutput; - /* The number of TS Filter to be supported. */ + + /** + * The number of record to be supported. + */ + uint32_t numRecord; + + /** + * The number of playback to be supported. + */ + uint32_t numPlayback; + + /** + * The number of TS Filter to be supported. + */ uint32_t numTsFilter; - /* The number of Section Filter to be supported. */ + + /** + * The number of Section Filter to be supported. + */ uint32_t numSectionFilter; - /* The number of Audio Filter to be supported. */ + + /** + * The number of Audio Filter to be supported. + */ uint32_t numAudioFilter; - /* The number of Video Filter to be supported. */ + + /** + * The number of Video Filter to be supported. + */ uint32_t numVideoFilter; - /* The number of PES Filter to be supported. */ + + /** + * The number of PES Filter to be supported. + */ uint32_t numPesFilter; - /* The number of PCR Filter to be supported. */ + + /** + * The number of PCR Filter to be supported. + */ uint32_t numPcrFilter; - /* The maximum number of bytes is supported in the mask of Section Filter. */ + + /** + * The maximum number of bytes is supported in the mask of Section Filter. + */ uint32_t numBytesInSectionFilter; + + bitfield filterCaps; + + /** + * The array has same elements as DemuxFilterMainType. linkCaps[i] presents + * filter's capability as soource for the ith type in DemuxFilterMainType. + * The jth bit of linkCaps[i] is 1 if the output of ith type filter can be + * data source for the filter type j. + */ + vec> linkCaps; + + bool bTimeFilter; }; From 33963aa37b1e32aec590bca1634942e61f1ae5b7 Mon Sep 17 00:00:00 2001 From: Amy Date: Tue, 15 Oct 2019 17:38:19 -0700 Subject: [PATCH 2/3] Refactor Tuner HAL Default Impl for Filter and Dvr separation Test: manual Bug: 135709325 Change-Id: I130f555315683fa02272f40d1e6209c5695c884a (cherry picked from commit b4b680167cea86095c141273ba4f9be7f2d25b7d) Merged-In: I130f555315683fa02272f40d1e6209c5695c884a --- tv/tuner/1.0/default/Android.bp | 3 + tv/tuner/1.0/default/Demux.cpp | 732 ++------------------------- tv/tuner/1.0/default/Demux.h | 150 +----- tv/tuner/1.0/default/Descrambler.cpp | 6 +- tv/tuner/1.0/default/Descrambler.h | 6 +- tv/tuner/1.0/default/Dvr.cpp | 280 ++++++++++ tv/tuner/1.0/default/Dvr.h | 151 ++++++ tv/tuner/1.0/default/Filter.cpp | 456 +++++++++++++++++ tv/tuner/1.0/default/Filter.h | 179 +++++++ tv/tuner/1.0/default/Frontend.h | 2 +- tv/tuner/1.0/default/Lnb.cpp | 12 +- tv/tuner/1.0/default/Lnb.h | 15 +- tv/tuner/1.0/default/TimeFilter.cpp | 78 +++ tv/tuner/1.0/default/TimeFilter.h | 69 +++ 14 files changed, 1315 insertions(+), 824 deletions(-) create mode 100644 tv/tuner/1.0/default/Dvr.cpp create mode 100644 tv/tuner/1.0/default/Dvr.h create mode 100644 tv/tuner/1.0/default/Filter.cpp create mode 100644 tv/tuner/1.0/default/Filter.h create mode 100644 tv/tuner/1.0/default/TimeFilter.cpp create mode 100644 tv/tuner/1.0/default/TimeFilter.h diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp index 0ae8bcdac8..989e25c6e3 100644 --- a/tv/tuner/1.0/default/Android.bp +++ b/tv/tuner/1.0/default/Android.bp @@ -4,9 +4,12 @@ cc_defaults { vendor: true, relative_install_path: "hw", srcs: [ + "Filter.cpp", "Frontend.cpp", "Descrambler.cpp", "Demux.cpp", + "Dvr.cpp", + "TimeFilter.cpp", "Tuner.cpp", "Lnb.cpp", "service.cpp", diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index 3a750c2218..c5921f74a9 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -28,45 +28,6 @@ namespace implementation { #define WAIT_TIMEOUT 3000000000 -const std::vector fakeDataInputBuffer{ - 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb, - 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03, - 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06, - 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, - 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, - 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, - 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, - 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, - 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, - 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, - 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, - 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d, - 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65, - 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31, - 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e, - 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20, - 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, - 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, - 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71, - 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, - 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d, - 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, - 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, - 0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68, - 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f, - 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, - 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79, - 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, - 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20, - 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, - 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, - 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20, - 0x73, 0x63, 0x65, 0x6e, 0x65, -}; - Demux::Demux(uint32_t demuxId, sp tuner) { mDemuxId = demuxId; mTunerService = tuner; @@ -93,8 +54,8 @@ Return Demux::setFrontendDataSource(uint32_t frontendId) { return startBroadcastInputLoop(); } -Return Demux::addFilter(DemuxFilterType type, uint32_t bufferSize, - const sp& cb, addFilter_cb _hidl_cb) { +Return Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize, + const sp& cb, openFilter_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); uint32_t filterId; @@ -105,137 +66,39 @@ Return Demux::addFilter(DemuxFilterType type, uint32_t bufferSize, mUnusedFilterIds.erase(filterId); } else { filterId = ++mLastUsedFilterId; - - mFilterCallbacks.resize(filterId + 1); - mFilterMQs.resize(filterId + 1); - mFilterEvents.resize(filterId + 1); - mFilterEventFlags.resize(filterId + 1); - mFilterThreadRunning.resize(filterId + 1); - mFilterThreads.resize(filterId + 1); - mFilterPids.resize(filterId + 1); - mFilterOutputs.resize(filterId + 1); - mFilterStatus.resize(filterId + 1); } mUsedFilterIds.insert(filterId); - if ((type != DemuxFilterType::PCR || type != DemuxFilterType::TS) && cb == nullptr) { + if (cb == nullptr) { ALOGW("callback can't be null"); - _hidl_cb(Result::INVALID_ARGUMENT, filterId); + _hidl_cb(Result::INVALID_ARGUMENT, new Filter()); return Void(); } - // Add callback - mFilterCallbacks[filterId] = cb; + sp filter = new Filter(type, filterId, bufferSize, cb, this); - // Mapping from the filter ID to the filter event - DemuxFilterEvent event{ - .filterId = filterId, - .filterType = type, - }; - mFilterEvents[filterId] = event; - - if (!createFilterMQ(bufferSize, filterId)) { - _hidl_cb(Result::UNKNOWN_ERROR, -1); + if (!filter->createFilterMQ()) { + _hidl_cb(Result::UNKNOWN_ERROR, filter); return Void(); } - _hidl_cb(Result::SUCCESS, filterId); + mFilters[filterId] = filter; + + _hidl_cb(Result::SUCCESS, filter); return Void(); } -Return Demux::getFilterQueueDesc(uint32_t filterId, getFilterQueueDesc_cb _hidl_cb) { +Return Demux::openTimeFilter(openTimeFilter_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - if (mUsedFilterIds.find(filterId) == mUsedFilterIds.end()) { - ALOGW("No filter with id: %d exists to get desc", filterId); - _hidl_cb(Result::INVALID_ARGUMENT, FilterMQ::Descriptor()); - return Void(); - } + sp timeFilter = new TimeFilter(this); - _hidl_cb(Result::SUCCESS, *mFilterMQs[filterId]->getDesc()); + _hidl_cb(Result::SUCCESS, timeFilter); return Void(); } -Return Demux::configureFilter(uint32_t filterId, const DemuxFilterSettings& settings) { - ALOGV("%s", __FUNCTION__); - - switch (mFilterEvents[filterId].filterType) { - case DemuxFilterType::SECTION: - mFilterPids[filterId] = settings.section().tpid; - break; - case DemuxFilterType::PES: - mFilterPids[filterId] = settings.pesData().tpid; - break; - case DemuxFilterType::TS: - mFilterPids[filterId] = settings.ts().tpid; - break; - case DemuxFilterType::AUDIO: - mFilterPids[filterId] = settings.audio().tpid; - break; - case DemuxFilterType::VIDEO: - mFilterPids[filterId] = settings.video().tpid; - break; - case DemuxFilterType::RECORD: - mFilterPids[filterId] = settings.record().tpid; - break; - case DemuxFilterType::PCR: - mFilterPids[filterId] = settings.pcr().tpid; - break; - default: - return Result::UNKNOWN_ERROR; - } - return Result::SUCCESS; -} - -Return Demux::startFilter(uint32_t filterId) { - ALOGV("%s", __FUNCTION__); - Result result; - - if (mUsedFilterIds.find(filterId) == mUsedFilterIds.end()) { - ALOGW("No filter with id: %d exists to start filter", filterId); - return Result::INVALID_ARGUMENT; - } - - result = startFilterLoop(filterId); - - return result; -} - -Return Demux::stopFilter(uint32_t filterId) { - ALOGV("%s", __FUNCTION__); - - mFilterThreadRunning[filterId] = false; - - std::lock_guard lock(mFilterThreadLock); - - return Result::SUCCESS; -} - -Return Demux::flushFilter(uint32_t filterId) { - ALOGV("%s", __FUNCTION__); - - // temp implementation to flush the FMQ - int size = mFilterMQs[filterId]->availableToRead(); - char* buffer = new char[size]; - mOutputMQ->read((unsigned char*)&buffer[0], size); - delete[] buffer; - mFilterStatus[filterId] = DemuxFilterStatus::DATA_READY; - - return Result::SUCCESS; -} - -Return Demux::removeFilter(uint32_t filterId) { - ALOGV("%s", __FUNCTION__); - - // resetFilterRecords(filterId); - mUsedFilterIds.erase(filterId); - mUnusedFilterIds.insert(filterId); - - return Result::SUCCESS; -} - -Return Demux::getAvSyncHwId(uint32_t /* filterId */, getAvSyncHwId_cb _hidl_cb) { +Return Demux::getAvSyncHwId(const sp& /* filter */, getAvSyncHwId_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); AvSyncHwId avSyncHwId = 0; @@ -256,588 +119,81 @@ Return Demux::getAvSyncTime(AvSyncHwId /* avSyncHwId */, getAvSyncTime_cb Return Demux::close() { ALOGV("%s", __FUNCTION__); - set::iterator it; - mInputThread = 0; - mOutputThread = 0; - mFilterThreads.clear(); mUnusedFilterIds.clear(); mUsedFilterIds.clear(); - mFilterCallbacks.clear(); - mFilterMQs.clear(); - mFilterEvents.clear(); - mFilterEventFlags.clear(); - mFilterOutputs.clear(); - mFilterPids.clear(); mLastUsedFilterId = -1; return Result::SUCCESS; } -Return Demux::addOutput(uint32_t bufferSize, const sp& cb) { +Return Demux::openDvr(DvrType type, uint32_t bufferSize, const sp& cb, + openDvr_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); - // Create a synchronized FMQ that supports blocking read/write - std::unique_ptr tmpFilterMQ = - std::unique_ptr(new (std::nothrow) FilterMQ(bufferSize, true)); - if (!tmpFilterMQ->isValid()) { - ALOGW("Failed to create output FMQ"); - return Result::UNKNOWN_ERROR; - } - - mOutputMQ = std::move(tmpFilterMQ); - - if (EventFlag::createEventFlag(mOutputMQ->getEventFlagWord(), &mOutputEventFlag) != OK) { - return Result::UNKNOWN_ERROR; - } - - mOutputCallback = cb; - - return Result::SUCCESS; -} - -Return Demux::getOutputQueueDesc(getOutputQueueDesc_cb _hidl_cb) { - ALOGV("%s", __FUNCTION__); - - if (!mOutputMQ) { - _hidl_cb(Result::NOT_INITIALIZED, FilterMQ::Descriptor()); + if (cb == nullptr) { + ALOGW("DVR callback can't be null"); + _hidl_cb(Result::INVALID_ARGUMENT, new Dvr()); return Void(); } - _hidl_cb(Result::SUCCESS, *mOutputMQ->getDesc()); - return Void(); -} + sp dvr = new Dvr(type, bufferSize, cb, this); -Return Demux::configureOutput(const DemuxOutputSettings& settings) { - ALOGV("%s", __FUNCTION__); - - mOutputConfigured = true; - mOutputSettings = settings; - return Result::SUCCESS; -} - -Return Demux::attachOutputFilter(uint32_t /*filterId*/) { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::detachOutputFilter(uint32_t /* filterId */) { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::startOutput() { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::stopOutput() { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::flushOutput() { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::removeOutput() { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::addInput(uint32_t bufferSize, const sp& cb) { - ALOGV("%s", __FUNCTION__); - - // Create a synchronized FMQ that supports blocking read/write - std::unique_ptr tmpInputMQ = - std::unique_ptr(new (std::nothrow) FilterMQ(bufferSize, true)); - if (!tmpInputMQ->isValid()) { - ALOGW("Failed to create input FMQ"); - return Result::UNKNOWN_ERROR; - } - - mInputMQ = std::move(tmpInputMQ); - - if (EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &mInputEventFlag) != OK) { - return Result::UNKNOWN_ERROR; - } - - mInputCallback = cb; - - return Result::SUCCESS; -} - -Return Demux::getInputQueueDesc(getInputQueueDesc_cb _hidl_cb) { - ALOGV("%s", __FUNCTION__); - - if (!mInputMQ) { - _hidl_cb(Result::NOT_INITIALIZED, FilterMQ::Descriptor()); + if (!dvr->createDvrMQ()) { + _hidl_cb(Result::UNKNOWN_ERROR, dvr); return Void(); } - _hidl_cb(Result::SUCCESS, *mInputMQ->getDesc()); + _hidl_cb(Result::SUCCESS, dvr); return Void(); } -Return Demux::configureInput(const DemuxInputSettings& settings) { +Result Demux::removeFilter(uint32_t filterId) { ALOGV("%s", __FUNCTION__); - mInputConfigured = true; - mInputSettings = settings; + // resetFilterRecords(filterId); + mUsedFilterIds.erase(filterId); + mUnusedFilterIds.insert(filterId); + mFilters.erase(filterId); return Result::SUCCESS; } -Return Demux::startInput() { - ALOGV("%s", __FUNCTION__); - - if (!mInputCallback) { - return Result::NOT_INITIALIZED; - } - - if (!mInputConfigured) { - return Result::INVALID_STATE; - } - - pthread_create(&mInputThread, NULL, __threadLoopInput, this); - pthread_setname_np(mInputThread, "demux_input_waiting_loop"); - - // TODO start another thread to send filter status callback to the framework - - return Result::SUCCESS; -} - -Return Demux::stopInput() { - ALOGV("%s", __FUNCTION__); - - mInputThreadRunning = false; - - std::lock_guard lock(mInputThreadLock); - - return Result::SUCCESS; -} - -Return Demux::flushInput() { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::removeInput() { - ALOGV("%s", __FUNCTION__); - - mInputMQ = nullptr; - - return Result::SUCCESS; -} - -Result Demux::startFilterLoop(uint32_t filterId) { - struct ThreadArgs* threadArgs = (struct ThreadArgs*)malloc(sizeof(struct ThreadArgs)); - threadArgs->user = this; - threadArgs->filterId = filterId; - - pthread_t mFilterThread; - pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs); - mFilterThreads[filterId] = mFilterThread; - pthread_setname_np(mFilterThread, "demux_filter_waiting_loop"); - - return Result::SUCCESS; -} - -Result Demux::startSectionFilterHandler(uint32_t filterId) { - if (mFilterOutputs[filterId].empty()) { - return Result::SUCCESS; - } - if (!writeSectionsAndCreateEvent(filterId, mFilterOutputs[filterId])) { - ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId); - return Result::UNKNOWN_ERROR; - } - - mFilterOutputs[filterId].clear(); - - return Result::SUCCESS; -} - -Result Demux::startPesFilterHandler(uint32_t filterId) { - std::lock_guard lock(mFilterEventLock); - if (mFilterOutputs[filterId].empty()) { - return Result::SUCCESS; - } - - for (int i = 0; i < mFilterOutputs[filterId].size(); i += 188) { - if (mPesSizeLeft == 0) { - uint32_t prefix = (mFilterOutputs[filterId][i + 4] << 16) | - (mFilterOutputs[filterId][i + 5] << 8) | - mFilterOutputs[filterId][i + 6]; - ALOGD("[Demux] prefix %d", prefix); - if (prefix == 0x000001) { - // TODO handle mulptiple Pes filters - mPesSizeLeft = - (mFilterOutputs[filterId][i + 8] << 8) | mFilterOutputs[filterId][i + 9]; - mPesSizeLeft += 6; - ALOGD("[Demux] pes data length %d", mPesSizeLeft); - } else { - continue; - } - } - - int endPoint = min(184, mPesSizeLeft); - // append data and check size - vector::const_iterator first = mFilterOutputs[filterId].begin() + i + 4; - vector::const_iterator last = mFilterOutputs[filterId].begin() + i + 4 + endPoint; - mPesOutput.insert(mPesOutput.end(), first, last); - // size does not match then continue - mPesSizeLeft -= endPoint; - if (mPesSizeLeft > 0) { - continue; - } - // size match then create event - if (!writeDataToFilterMQ(mPesOutput, filterId)) { - mFilterOutputs[filterId].clear(); - return Result::INVALID_STATE; - } - maySendFilterStatusCallback(filterId); - DemuxFilterPesEvent pesEvent; - pesEvent = { - // temp dump meta data - .streamId = mPesOutput[3], - .dataLength = static_cast(mPesOutput.size()), - }; - ALOGD("[Demux] assembled pes data length %d", pesEvent.dataLength); - - int size = mFilterEvents[filterId].events.size(); - mFilterEvents[filterId].events.resize(size + 1); - mFilterEvents[filterId].events[size].pes(pesEvent); - mPesOutput.clear(); - } - - mFilterOutputs[filterId].clear(); - - return Result::SUCCESS; -} - -Result Demux::startTsFilterHandler() { - // TODO handle starting TS filter - return Result::SUCCESS; -} - -Result Demux::startMediaFilterHandler(uint32_t filterId) { - DemuxFilterMediaEvent mediaEvent; - mediaEvent = { - // temp dump meta data - .pts = 0, - .dataLength = 530, - .secureMemory = nullptr, - }; - mFilterEvents[filterId].events.resize(1); - mFilterEvents[filterId].events[0].media() = mediaEvent; - - mFilterOutputs[filterId].clear(); - // TODO handle write FQM for media stream - return Result::SUCCESS; -} - -Result Demux::startRecordFilterHandler(uint32_t filterId) { - DemuxFilterRecordEvent recordEvent; - recordEvent = { - // temp dump meta data - .tpid = 0, - .packetNum = 0, - }; - recordEvent.indexMask.tsIndexMask() = 0x01; - mFilterEvents[filterId].events.resize(1); - mFilterEvents[filterId].events[0].ts() = recordEvent; - - mFilterOutputs[filterId].clear(); - return Result::SUCCESS; -} - -Result Demux::startPcrFilterHandler() { - // TODO handle starting PCR filter - return Result::SUCCESS; -} - -bool Demux::createFilterMQ(uint32_t bufferSize, uint32_t filterId) { - ALOGV("%s", __FUNCTION__); - - // Create a synchronized FMQ that supports blocking read/write - std::unique_ptr tmpFilterMQ = - std::unique_ptr(new (std::nothrow) FilterMQ(bufferSize, true)); - if (!tmpFilterMQ->isValid()) { - ALOGW("Failed to create FMQ of filter with id: %d", filterId); - return false; - } - - mFilterMQs[filterId] = std::move(tmpFilterMQ); - - EventFlag* filterEventFlag; - if (EventFlag::createEventFlag(mFilterMQs[filterId]->getEventFlagWord(), &filterEventFlag) != - OK) { - return false; - } - mFilterEventFlags[filterId] = filterEventFlag; - - return true; -} - -bool Demux::writeSectionsAndCreateEvent(uint32_t filterId, vector data) { - // TODO check how many sections has been read - std::lock_guard lock(mFilterEventLock); - if (!writeDataToFilterMQ(data, filterId)) { - return false; - } - int size = mFilterEvents[filterId].events.size(); - mFilterEvents[filterId].events.resize(size + 1); - DemuxFilterSectionEvent secEvent; - secEvent = { - // temp dump meta data - .tableId = 0, - .version = 1, - .sectionNum = 1, - .dataLength = static_cast(data.size()), - }; - mFilterEvents[filterId].events[size].section(secEvent); - return true; -} - -bool Demux::writeDataToFilterMQ(const std::vector& data, uint32_t filterId) { - std::lock_guard lock(mWriteLock); - if (mFilterMQs[filterId]->write(data.data(), data.size())) { - return true; - } - return false; -} - -bool Demux::readInputFMQ() { - // Read input data from the input FMQ - int size = mInputMQ->availableToRead(); - int inputPacketSize = mInputSettings.packetSize; - vector dataOutputBuffer; - dataOutputBuffer.resize(inputPacketSize); - - // Dispatch the packet to the PID matching filter output buffer - for (int i = 0; i < size / inputPacketSize; i++) { - if (!mInputMQ->read(dataOutputBuffer.data(), inputPacketSize)) { - return false; - } - startTsFilter(dataOutputBuffer); - } - - return true; -} - void Demux::startTsFilter(vector data) { set::iterator it; for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff)); - ALOGW("start ts filter pid: %d", pid); - if (pid == mFilterPids[*it]) { - mFilterOutputs[*it].insert(mFilterOutputs[*it].end(), data.begin(), data.end()); + if (DEBUG_FILTER) { + ALOGW("start ts filter pid: %d", pid); + } + if (pid == mFilters[*it]->getTpid()) { + mFilters[*it]->updateFilterOutput(data); } } } bool Demux::startFilterDispatcher() { - Result result; set::iterator it; // Handle the output data per filter type for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { - switch (mFilterEvents[*it].filterType) { - case DemuxFilterType::SECTION: - result = startSectionFilterHandler(*it); - break; - case DemuxFilterType::PES: - result = startPesFilterHandler(*it); - break; - case DemuxFilterType::TS: - result = startTsFilterHandler(); - break; - case DemuxFilterType::AUDIO: - case DemuxFilterType::VIDEO: - result = startMediaFilterHandler(*it); - break; - case DemuxFilterType::RECORD: - result = startRecordFilterHandler(*it); - break; - case DemuxFilterType::PCR: - result = startPcrFilterHandler(); - break; - default: - return false; + if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) { + return false; } } - return result == Result::SUCCESS; + return true; } -void* Demux::__threadLoopFilter(void* threadArg) { - Demux* const self = static_cast(((struct ThreadArgs*)threadArg)->user); - self->filterThreadLoop(((struct ThreadArgs*)threadArg)->filterId); - return 0; +Result Demux::startFilterHandler(uint32_t filterId) { + return mFilters[filterId]->startFilterHandler(); } -void* Demux::__threadLoopInput(void* user) { - Demux* const self = static_cast(user); - self->inputThreadLoop(); - return 0; +void Demux::updateFilterOutput(uint16_t filterId, vector data) { + mFilters[filterId]->updateFilterOutput(data); } -void Demux::filterThreadLoop(uint32_t filterId) { - ALOGD("[Demux] filter %d threadLoop start.", filterId); - std::lock_guard lock(mFilterThreadLock); - mFilterThreadRunning[filterId] = true; - - // For the first time of filter output, implementation needs to send the filter - // Event Callback without waiting for the DATA_CONSUMED to init the process. - while (mFilterThreadRunning[filterId]) { - if (mFilterEvents[filterId].events.size() == 0) { - ALOGD("[Demux] wait for filter data output."); - usleep(1000 * 1000); - continue; - } - // After successfully write, send a callback and wait for the read to be done - mFilterCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]); - mFilterEvents[filterId].events.resize(0); - mFilterStatus[filterId] = DemuxFilterStatus::DATA_READY; - mFilterCallbacks[filterId]->onFilterStatus(filterId, mFilterStatus[filterId]); - break; - } - - while (mFilterThreadRunning[filterId]) { - uint32_t efState = 0; - // We do not wait for the last round of writen data to be read to finish the thread - // because the VTS can verify the reading itself. - for (int i = 0; i < SECTION_WRITE_COUNT; i++) { - while (mFilterThreadRunning[filterId]) { - status_t status = mFilterEventFlags[filterId]->wait( - static_cast(DemuxQueueNotifyBits::DATA_CONSUMED), &efState, - WAIT_TIMEOUT, true /* retry on spurious wake */); - if (status != OK) { - ALOGD("[Demux] wait for data consumed"); - continue; - } - break; - } - - if (mFilterCallbacks[filterId] == nullptr) { - ALOGD("[Demux] filter %d does not hava callback. Ending thread", filterId); - break; - } - - maySendFilterStatusCallback(filterId); - - while (mFilterThreadRunning[filterId]) { - std::lock_guard lock(mFilterEventLock); - if (mFilterEvents[filterId].events.size() == 0) { - continue; - } - // After successfully write, send a callback and wait for the read to be done - mFilterCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]); - mFilterEvents[filterId].events.resize(0); - break; - } - // We do not wait for the last read to be done - // VTS can verify the read result itself. - if (i == SECTION_WRITE_COUNT - 1) { - ALOGD("[Demux] filter %d writing done. Ending thread", filterId); - break; - } - } - mFilterThreadRunning[filterId] = false; - } - - ALOGD("[Demux] filter thread ended."); -} - -void Demux::inputThreadLoop() { - ALOGD("[Demux] input threadLoop start."); - std::lock_guard lock(mInputThreadLock); - mInputThreadRunning = true; - - while (mInputThreadRunning) { - uint32_t efState = 0; - status_t status = - mInputEventFlag->wait(static_cast(DemuxQueueNotifyBits::DATA_READY), - &efState, WAIT_TIMEOUT, true /* retry on spurious wake */); - if (status != OK) { - ALOGD("[Demux] wait for data ready on the input FMQ"); - continue; - } - // Our current implementation filter the data and write it into the filter FMQ immedaitely - // after the DATA_READY from the VTS/framework - if (!readInputFMQ() || !startFilterDispatcher()) { - ALOGD("[Demux] input data failed to be filtered. Ending thread"); - break; - } - - maySendInputStatusCallback(); - } - - mInputThreadRunning = false; - ALOGD("[Demux] input thread ended."); -} - -void Demux::maySendInputStatusCallback() { - std::lock_guard lock(mInputStatusLock); - int availableToRead = mInputMQ->availableToRead(); - int availableToWrite = mInputMQ->availableToWrite(); - - DemuxInputStatus newStatus = - checkInputStatusChange(availableToWrite, availableToRead, mInputSettings.highThreshold, - mInputSettings.lowThreshold); - if (mIntputStatus != newStatus) { - mInputCallback->onInputStatus(newStatus); - mIntputStatus = newStatus; - } -} - -void Demux::maySendFilterStatusCallback(uint32_t filterId) { - std::lock_guard lock(mFilterStatusLock); - int availableToRead = mFilterMQs[filterId]->availableToRead(); - int availableToWrite = mFilterMQs[filterId]->availableToWrite(); - int fmqSize = mFilterMQs[filterId]->getQuantumCount(); - - DemuxFilterStatus newStatus = - checkFilterStatusChange(filterId, availableToWrite, availableToRead, - ceil(fmqSize * 0.75), ceil(fmqSize * 0.25)); - if (mFilterStatus[filterId] != newStatus) { - mFilterCallbacks[filterId]->onFilterStatus(filterId, newStatus); - mFilterStatus[filterId] = newStatus; - } -} - -DemuxInputStatus Demux::checkInputStatusChange(uint32_t availableToWrite, uint32_t availableToRead, - uint32_t highThreshold, uint32_t lowThreshold) { - if (availableToWrite == 0) { - return DemuxInputStatus::SPACE_FULL; - } else if (availableToRead > highThreshold) { - return DemuxInputStatus::SPACE_ALMOST_FULL; - } else if (availableToRead < lowThreshold) { - return DemuxInputStatus::SPACE_ALMOST_EMPTY; - } else if (availableToRead == 0) { - return DemuxInputStatus::SPACE_EMPTY; - } - return mIntputStatus; -} - -DemuxFilterStatus Demux::checkFilterStatusChange(uint32_t filterId, uint32_t availableToWrite, - uint32_t availableToRead, uint32_t highThreshold, - uint32_t lowThreshold) { - if (availableToWrite == 0) { - return DemuxFilterStatus::OVERFLOW; - } else if (availableToRead > highThreshold) { - return DemuxFilterStatus::HIGH_WATER; - } else if (availableToRead < lowThreshold) { - return DemuxFilterStatus::LOW_WATER; - } - return mFilterStatus[filterId]; +uint16_t Demux::getFilterTpid(uint32_t filterId) { + return mFilters[filterId]->getTpid(); } Result Demux::startBroadcastInputLoop() { @@ -876,6 +232,7 @@ void Demux::broadcastInputThreadLoop() { for (int i = 0; i < writePacketAmount; i++) { inputData.read(buffer, packetSize); if (!inputData) { + mKeepFetchingDataFromFrontend = false; mBroadcastInputThreadRunning = false; break; } @@ -888,7 +245,7 @@ void Demux::broadcastInputThreadLoop() { startTsFilter(byteBuffer); } startFilterDispatcher(); - sleep(1); + usleep(100); } } @@ -898,6 +255,7 @@ void Demux::broadcastInputThreadLoop() { } void Demux::stopBroadcastInput() { + ALOGD("[Demux] stop frontend on demux"); mKeepFetchingDataFromFrontend = false; mBroadcastInputThreadRunning = false; std::lock_guard lock(mBroadcastInputThreadLock); diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h index ba0b9b099a..a9756cc248 100644 --- a/tv/tuner/1.0/default/Demux.h +++ b/tv/tuner/1.0/default/Demux.h @@ -21,7 +21,10 @@ #include #include #include +#include "Dvr.h" +#include "Filter.h" #include "Frontend.h" +#include "TimeFilter.h" #include "Tuner.h" using namespace std; @@ -38,13 +41,17 @@ using ::android::hardware::kSynchronizedReadWrite; using ::android::hardware::MessageQueue; using ::android::hardware::MQDescriptorSync; using ::android::hardware::tv::tuner::V1_0::IDemux; -using ::android::hardware::tv::tuner::V1_0::IDemuxCallback; +using ::android::hardware::tv::tuner::V1_0::IDvrCallback; +using ::android::hardware::tv::tuner::V1_0::IFilterCallback; using ::android::hardware::tv::tuner::V1_0::Result; using FilterMQ = MessageQueue; -class Tuner; +class Dvr; +class Filter; class Frontend; +class TimeFilter; +class Tuner; class Demux : public IDemux { public: @@ -54,63 +61,27 @@ class Demux : public IDemux { virtual Return setFrontendDataSource(uint32_t frontendId) override; - virtual Return close() override; + virtual Return openFilter(const DemuxFilterType& type, uint32_t bufferSize, + const sp& cb, openFilter_cb _hidl_cb) override; - virtual Return addFilter(DemuxFilterType type, uint32_t bufferSize, - const sp& cb, addFilter_cb _hidl_cb) override; + virtual Return openTimeFilter(openTimeFilter_cb _hidl_cb) override; - virtual Return getFilterQueueDesc(uint32_t filterId, - getFilterQueueDesc_cb _hidl_cb) override; - - virtual Return configureFilter(uint32_t filterId, - const DemuxFilterSettings& settings) override; - - virtual Return startFilter(uint32_t filterId) override; - - virtual Return stopFilter(uint32_t filterId) override; - - virtual Return flushFilter(uint32_t filterId) override; - - virtual Return removeFilter(uint32_t filterId) override; - - virtual Return getAvSyncHwId(uint32_t filterId, getAvSyncHwId_cb _hidl_cb) override; + virtual Return getAvSyncHwId(const sp& filter, + getAvSyncHwId_cb _hidl_cb) override; virtual Return getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) override; - virtual Return addInput(uint32_t bufferSize, const sp& cb) override; + virtual Return close() override; - virtual Return getInputQueueDesc(getInputQueueDesc_cb _hidl_cb) override; - - virtual Return configureInput(const DemuxInputSettings& settings) override; - - virtual Return startInput() override; - - virtual Return stopInput() override; - - virtual Return flushInput() override; - - virtual Return removeInput() override; - - virtual Return addOutput(uint32_t bufferSize, const sp& cb) override; - - virtual Return getOutputQueueDesc(getOutputQueueDesc_cb _hidl_cb) override; - - virtual Return configureOutput(const DemuxOutputSettings& settings) override; - - virtual Return attachOutputFilter(uint32_t filterId) override; - - virtual Return detachOutputFilter(uint32_t filterId) override; - - virtual Return startOutput() override; - - virtual Return stopOutput() override; - - virtual Return flushOutput() override; - - virtual Return removeOutput() override; + virtual Return openDvr(DvrType type, uint32_t bufferSize, const sp& cb, + openDvr_cb _hidl_cb) override; // Functions interacts with Tuner Service void stopBroadcastInput(); + Result removeFilter(uint32_t filterId); + Result startFilterHandler(uint32_t filterId); + void updateFilterOutput(uint16_t filterId, vector data); + uint16_t getFilterTpid(uint32_t filterId); private: // Tuner service @@ -126,19 +97,9 @@ class Demux : public IDemux { uint32_t filterId; }; - /** - * Filter handlers to handle the data filtering. - * They are also responsible to write the filtered output into the filter FMQ - * and update the filterEvent bound with the same filterId. - */ - Result startSectionFilterHandler(uint32_t filterId); - Result startPesFilterHandler(uint32_t filterId); - Result startTsFilterHandler(); - Result startMediaFilterHandler(uint32_t filterId); - Result startRecordFilterHandler(uint32_t filterId); - Result startPcrFilterHandler(); - Result startFilterLoop(uint32_t filterId); Result startBroadcastInputLoop(); + static void* __threadLoopBroadcast(void* user); + void broadcastInputThreadLoop(); /** * To create a FilterMQ with the the next available Filter ID. @@ -147,32 +108,14 @@ class Demux : public IDemux { * * Return false is any of the above processes fails. */ - bool createFilterMQ(uint32_t bufferSize, uint32_t filterId); - bool createMQ(FilterMQ* queue, EventFlag* eventFlag, uint32_t bufferSize); void deleteEventFlag(); - bool writeDataToFilterMQ(const std::vector& data, uint32_t filterId); bool readDataFromMQ(); - bool writeSectionsAndCreateEvent(uint32_t filterId, vector data); - void maySendInputStatusCallback(); - void maySendFilterStatusCallback(uint32_t filterId); - DemuxInputStatus checkInputStatusChange(uint32_t availableToWrite, uint32_t availableToRead, - uint32_t highThreshold, uint32_t lowThreshold); - DemuxFilterStatus checkFilterStatusChange(uint32_t filterId, uint32_t availableToWrite, - uint32_t availableToRead, uint32_t highThreshold, - uint32_t lowThreshold); /** * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. */ - bool readInputFMQ(); - void startTsFilter(vector data); bool startFilterDispatcher(); - static void* __threadLoopFilter(void* data); - static void* __threadLoopInput(void* user); - static void* __threadLoopBroadcast(void* user); - void filterThreadLoop(uint32_t filterId); - void inputThreadLoop(); - void broadcastInputThreadLoop(); + void startTsFilter(vector data); uint32_t mDemuxId; /** @@ -196,69 +139,30 @@ class Demux : public IDemux { * A list of created FilterMQ ptrs. * The array number is the filter ID. */ - vector mFilterPids; - vector> mFilterOutputs; - vector> mFilterMQs; - vector mFilterEventFlags; - vector mFilterEvents; - unique_ptr mInputMQ; - unique_ptr mOutputMQ; - EventFlag* mInputEventFlag; - EventFlag* mOutputEventFlag; - /** - * Demux callbacks used on filter events or IO buffer status - */ - vector> mFilterCallbacks; - sp mInputCallback; - sp mOutputCallback; - bool mInputConfigured = false; - bool mOutputConfigured = false; - DemuxInputSettings mInputSettings; - DemuxOutputSettings mOutputSettings; + std::map> mFilters; // Thread handlers - pthread_t mInputThread; - pthread_t mOutputThread; pthread_t mBroadcastInputThread; - vector mFilterThreads; - - // FMQ status local records - DemuxInputStatus mIntputStatus; - vector mFilterStatus; /** * If a specific filter's writing loop is still running */ - vector mFilterThreadRunning; - bool mInputThreadRunning; bool mBroadcastInputThreadRunning; bool mKeepFetchingDataFromFrontend; /** * Lock to protect writes to the FMQs */ std::mutex mWriteLock; - /** - * Lock to protect writes to the filter event - */ - // TODO make each filter separate event lock - std::mutex mFilterEventLock; /** * Lock to protect writes to the input status */ - std::mutex mInputStatusLock; - std::mutex mFilterStatusLock; std::mutex mBroadcastInputThreadLock; - std::mutex mFilterThreadLock; - std::mutex mInputThreadLock; - /** - * How many times a filter should write - * TODO make this dynamic/random/can take as a parameter - */ - const uint16_t SECTION_WRITE_COUNT = 10; // temp handle single PES filter // TODO handle mulptiple Pes filters int mPesSizeLeft = 0; vector mPesOutput; + + const bool DEBUG_FILTER = false; }; } // namespace implementation diff --git a/tv/tuner/1.0/default/Descrambler.cpp b/tv/tuner/1.0/default/Descrambler.cpp index 085f2c8d54..e3f5b22bcb 100644 --- a/tv/tuner/1.0/default/Descrambler.cpp +++ b/tv/tuner/1.0/default/Descrambler.cpp @@ -50,13 +50,15 @@ Return Descrambler::setKeyToken(const hidl_vec& /* keyToken */) return Result::SUCCESS; } -Return Descrambler::addPid(uint16_t /* pid */) { +Return Descrambler::addPid(const DemuxPid& /* pid */, + const sp& /* optionalSourceFilter */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; } -Return Descrambler::removePid(uint16_t /* pid */) { +Return Descrambler::removePid(const DemuxPid& /* pid */, + const sp& /* optionalSourceFilter */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; diff --git a/tv/tuner/1.0/default/Descrambler.h b/tv/tuner/1.0/default/Descrambler.h index 436adcfc43..c8898200c0 100644 --- a/tv/tuner/1.0/default/Descrambler.h +++ b/tv/tuner/1.0/default/Descrambler.h @@ -40,9 +40,11 @@ class Descrambler : public IDescrambler { virtual Return setKeyToken(const hidl_vec& keyToken) override; - virtual Return addPid(uint16_t pid) override; + virtual Return addPid(const DemuxPid& pid, + const sp& optionalSourceFilter) override; - virtual Return removePid(uint16_t pid) override; + virtual Return removePid(const DemuxPid& pid, + const sp& optionalSourceFilter) override; virtual Return close() override; diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp new file mode 100644 index 0000000000..eb38f9040e --- /dev/null +++ b/tv/tuner/1.0/default/Dvr.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "android.hardware.tv.tuner@1.0-Dvr" + +#include "Dvr.h" +#include + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +#define WAIT_TIMEOUT 3000000000 + +Dvr::Dvr() {} + +Dvr::Dvr(DvrType type, uint32_t bufferSize, const sp& cb, sp demux) { + mType = type; + mBufferSize = bufferSize; + mCallback = cb; + mDemux = demux; +} + +Dvr::~Dvr() {} + +Return Dvr::getQueueDesc(getQueueDesc_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + _hidl_cb(Result::SUCCESS, *mDvrMQ->getDesc()); + return Void(); +} + +Return Dvr::configure(const DvrSettings& settings) { + ALOGV("%s", __FUNCTION__); + + mDvrSettings = settings; + mDvrConfigured = true; + + return Result::SUCCESS; +} + +Return Dvr::attachFilter(const sp& filter) { + ALOGV("%s", __FUNCTION__); + + uint32_t filterId; + Result status; + + filter->getId([&](Result result, uint32_t id) { + filterId = id; + status = result; + }); + + if (status != Result::SUCCESS) { + return status; + } + + mFilters[filterId] = filter; + + return Result::SUCCESS; +} + +Return Dvr::detachFilter(const sp& filter) { + ALOGV("%s", __FUNCTION__); + + uint32_t filterId; + Result status; + + filter->getId([&](Result result, uint32_t id) { + filterId = id; + status = result; + }); + + if (status != Result::SUCCESS) { + return status; + } + + std::map>::iterator it; + + it = mFilters.find(filterId); + if (it != mFilters.end()) { + mFilters.erase(filterId); + } + + return Result::SUCCESS; +} + +Return Dvr::start() { + ALOGV("%s", __FUNCTION__); + + if (!mCallback) { + return Result::NOT_INITIALIZED; + } + + if (!mDvrConfigured) { + return Result::INVALID_STATE; + } + + if (mType == DvrType::PLAYBACK) { + pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this); + pthread_setname_np(mDvrThread, "playback_waiting_loop"); + } else if (mType == DvrType::RECORD) { + /*pthread_create(&mInputThread, NULL, __threadLoopInput, this); + pthread_setname_np(mInputThread, "playback_waiting_loop");*/ + } + + // TODO start another thread to send filter status callback to the framework + + return Result::SUCCESS; +} + +Return Dvr::stop() { + ALOGV("%s", __FUNCTION__); + + mDvrThreadRunning = false; + + std::lock_guard lock(mDvrThreadLock); + + return Result::SUCCESS; +} + +Return Dvr::flush() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Dvr::close() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +bool Dvr::createDvrMQ() { + ALOGV("%s", __FUNCTION__); + + // Create a synchronized FMQ that supports blocking read/write + std::unique_ptr tmpDvrMQ = + std::unique_ptr(new (std::nothrow) DvrMQ(mBufferSize, true)); + if (!tmpDvrMQ->isValid()) { + ALOGW("Failed to create FMQ of DVR"); + return false; + } + + mDvrMQ = std::move(tmpDvrMQ); + + if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) { + return false; + } + + return true; +} + +void* Dvr::__threadLoopPlayback(void* user) { + Dvr* const self = static_cast(user); + self->playbackThreadLoop(); + return 0; +} + +void Dvr::playbackThreadLoop() { + ALOGD("[Dvr] playback threadLoop start."); + std::lock_guard lock(mDvrThreadLock); + mDvrThreadRunning = true; + + while (mDvrThreadRunning) { + uint32_t efState = 0; + status_t status = + mDvrEventFlag->wait(static_cast(DemuxQueueNotifyBits::DATA_READY), + &efState, WAIT_TIMEOUT, true /* retry on spurious wake */); + if (status != OK) { + ALOGD("[Dvr] wait for data ready on the playback FMQ"); + continue; + } + // Our current implementation filter the data and write it into the filter FMQ immediately + // after the DATA_READY from the VTS/framework + if (!readPlaybackFMQ() || !startFilterDispatcher()) { + ALOGD("[Dvr] playback data failed to be filtered. Ending thread"); + break; + } + + maySendPlaybackStatusCallback(); + } + + mDvrThreadRunning = false; + ALOGD("[Dvr] playback thread ended."); +} + +void Dvr::maySendPlaybackStatusCallback() { + std::lock_guard lock(mPlaybackStatusLock); + int availableToRead = mDvrMQ->availableToRead(); + int availableToWrite = mDvrMQ->availableToWrite(); + + PlaybackStatus newStatus = checkPlaybackStatusChange(availableToWrite, availableToRead, + mDvrSettings.playback().highThreshold, + mDvrSettings.playback().lowThreshold); + if (mPlaybackStatus != newStatus) { + mCallback->onPlaybackStatus(newStatus); + mPlaybackStatus = newStatus; + } +} + +PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold) { + if (availableToWrite == 0) { + return PlaybackStatus::SPACE_FULL; + } else if (availableToRead > highThreshold) { + return PlaybackStatus::SPACE_ALMOST_FULL; + } else if (availableToRead < lowThreshold) { + return PlaybackStatus::SPACE_ALMOST_EMPTY; + } else if (availableToRead == 0) { + return PlaybackStatus::SPACE_EMPTY; + } + return mPlaybackStatus; +} + +bool Dvr::readPlaybackFMQ() { + // Read playback data from the input FMQ + int size = mDvrMQ->availableToRead(); + int playbackPacketSize = mDvrSettings.playback().packetSize; + vector dataOutputBuffer; + dataOutputBuffer.resize(playbackPacketSize); + + // Dispatch the packet to the PID matching filter output buffer + for (int i = 0; i < size / playbackPacketSize; i++) { + if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) { + return false; + } + startTpidFilter(dataOutputBuffer); + } + + return true; +} + +void Dvr::startTpidFilter(vector data) { + std::map>::iterator it; + for (it = mFilters.begin(); it != mFilters.end(); it++) { + uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff)); + if (DEBUG_DVR) { + ALOGW("[Dvr] start ts filter pid: %d", pid); + } + if (pid == mDemux->getFilterTpid(it->first)) { + mDemux->updateFilterOutput(it->first, data); + } + } +} + +bool Dvr::startFilterDispatcher() { + std::map>::iterator it; + + // Handle the output data per filter type + for (it = mFilters.begin(); it != mFilters.end(); it++) { + if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) { + return false; + } + } + + return true; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h new file mode 100644 index 0000000000..fbb778ca6c --- /dev/null +++ b/tv/tuner/1.0/default/Dvr.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_ +#define ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_ + +#include +#include +#include +#include +#include "Demux.h" +#include "Frontend.h" +#include "Tuner.h" + +using namespace std; + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::EventFlag; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::MQDescriptorSync; +using ::android::hardware::tv::tuner::V1_0::IDemux; +using ::android::hardware::tv::tuner::V1_0::IDvrCallback; +using ::android::hardware::tv::tuner::V1_0::Result; + +using DvrMQ = MessageQueue; + +class Demux; +class Filter; +class Frontend; +class Tuner; + +class Dvr : public IDvr { + public: + Dvr(); + + Dvr(DvrType type, uint32_t bufferSize, const sp& cb, sp demux); + + ~Dvr(); + + virtual Return getQueueDesc(getQueueDesc_cb _hidl_cb) override; + + virtual Return configure(const DvrSettings& settings) override; + + virtual Return attachFilter(const sp& filter) override; + + virtual Return detachFilter(const sp& filter) override; + + virtual Return start() override; + + virtual Return stop() override; + + virtual Return flush() override; + + virtual Return close() override; + + /** + * To create a DvrMQ and its Event Flag. + * + * Return false is any of the above processes fails. + */ + bool createDvrMQ(); + + private: + // Demux service + sp mDemux; + + DvrType mType; + uint32_t mBufferSize; + sp mCallback; + std::map> mFilters; + + void deleteEventFlag(); + bool readDataFromMQ(); + void maySendPlaybackStatusCallback(); + void maySendRecordStatusCallback(); + PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold); + /** + * A dispatcher to read and dispatch input data to all the started filters. + * Each filter handler handles the data filtering/output writing/filterEvent updating. + */ + bool readPlaybackFMQ(); + void startTpidFilter(vector data); + bool startFilterDispatcher(); + static void* __threadLoopPlayback(void* user); + static void* __threadLoopBroadcast(void* user); + void playbackThreadLoop(); + void broadcastInputThreadLoop(); + + unique_ptr mDvrMQ; + EventFlag* mDvrEventFlag; + /** + * Demux callbacks used on filter events or IO buffer status + */ + bool mDvrConfigured = false; + DvrSettings mDvrSettings; + + // Thread handlers + pthread_t mDvrThread; + pthread_t mBroadcastInputThread; + + // FMQ status local records + PlaybackStatus mPlaybackStatus; + /** + * If a specific filter's writing loop is still running + */ + bool mDvrThreadRunning; + bool mBroadcastInputThreadRunning; + bool mKeepFetchingDataFromFrontend; + /** + * Lock to protect writes to the FMQs + */ + std::mutex mWriteLock; + /** + * Lock to protect writes to the input status + */ + std::mutex mPlaybackStatusLock; + std::mutex mBroadcastInputThreadLock; + std::mutex mDvrThreadLock; + + const bool DEBUG_DVR = false; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_ \ No newline at end of file diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp new file mode 100644 index 0000000000..3d8a97731c --- /dev/null +++ b/tv/tuner/1.0/default/Filter.cpp @@ -0,0 +1,456 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "android.hardware.tv.tuner@1.0-Filter" + +#include "Filter.h" +#include + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +#define WAIT_TIMEOUT 3000000000 + +Filter::Filter() {} + +Filter::Filter(DemuxFilterType type, uint32_t filterId, uint32_t bufferSize, + const sp& cb, sp demux) { + mType = type; + mFilterId = filterId; + mBufferSize = bufferSize; + mCallback = cb; + mDemux = demux; +} + +Filter::~Filter() {} + +Return Filter::getId(getId_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + _hidl_cb(Result::SUCCESS, mFilterId); + return Void(); +} + +Return Filter::setDataSource(const sp& filter) { + ALOGV("%s", __FUNCTION__); + + mDataSource = filter; + mIsDataSourceDemux = false; + + return Result::SUCCESS; +} + +Return Filter::getQueueDesc(getQueueDesc_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + _hidl_cb(Result::SUCCESS, *mFilterMQ->getDesc()); + return Void(); +} + +Return Filter::configure(const DemuxFilterSettings& settings) { + ALOGV("%s", __FUNCTION__); + + mFilterSettings = settings; + switch (mType.mainType) { + case DemuxFilterMainType::TS: + mTpid = settings.ts().tpid; + break; + case DemuxFilterMainType::MMTP: + /*mmtpSettings*/ + break; + case DemuxFilterMainType::IP: + /*ipSettings*/ + break; + case DemuxFilterMainType::TLV: + /*tlvSettings*/ + break; + case DemuxFilterMainType::ALP: + /*alpSettings*/ + break; + default: + break; + } + + return Result::SUCCESS; +} + +Return Filter::start() { + ALOGV("%s", __FUNCTION__); + + return startFilterLoop(); +} + +Return Filter::stop() { + ALOGV("%s", __FUNCTION__); + + mFilterThreadRunning = false; + + std::lock_guard lock(mFilterThreadLock); + + return Result::SUCCESS; +} + +Return Filter::flush() { + ALOGV("%s", __FUNCTION__); + + // temp implementation to flush the FMQ + int size = mFilterMQ->availableToRead(); + char* buffer = new char[size]; + mFilterMQ->read((unsigned char*)&buffer[0], size); + delete[] buffer; + mFilterStatus = DemuxFilterStatus::DATA_READY; + + return Result::SUCCESS; +} + +Return Filter::close() { + ALOGV("%s", __FUNCTION__); + + return mDemux->removeFilter(mFilterId); +} + +bool Filter::createFilterMQ() { + ALOGV("%s", __FUNCTION__); + + // Create a synchronized FMQ that supports blocking read/write + std::unique_ptr tmpFilterMQ = + std::unique_ptr(new (std::nothrow) FilterMQ(mBufferSize, true)); + if (!tmpFilterMQ->isValid()) { + ALOGW("Failed to create FMQ of filter with id: %d", mFilterId); + return false; + } + + mFilterMQ = std::move(tmpFilterMQ); + + if (EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterEventFlag) != OK) { + return false; + } + + return true; +} + +Result Filter::startFilterLoop() { + pthread_create(&mFilterThread, NULL, __threadLoopFilter, this); + pthread_setname_np(mFilterThread, "filter_waiting_loop"); + + return Result::SUCCESS; +} + +void* Filter::__threadLoopFilter(void* user) { + Filter* const self = static_cast(user); + self->filterThreadLoop(); + return 0; +} + +void Filter::filterThreadLoop() { + ALOGD("[Filter] filter %d threadLoop start.", mFilterId); + std::lock_guard lock(mFilterThreadLock); + mFilterThreadRunning = true; + + // For the first time of filter output, implementation needs to send the filter + // Event Callback without waiting for the DATA_CONSUMED to init the process. + while (mFilterThreadRunning) { + if (mFilterEvent.events.size() == 0) { + ALOGD("[Filter] wait for filter data output."); + usleep(1000 * 1000); + continue; + } + // After successfully write, send a callback and wait for the read to be done + mCallback->onFilterEvent(mFilterEvent); + mFilterEvent.events.resize(0); + mFilterStatus = DemuxFilterStatus::DATA_READY; + mCallback->onFilterStatus(mFilterStatus); + break; + } + + while (mFilterThreadRunning) { + uint32_t efState = 0; + // We do not wait for the last round of written data to be read to finish the thread + // because the VTS can verify the reading itself. + for (int i = 0; i < SECTION_WRITE_COUNT; i++) { + while (mFilterThreadRunning) { + status_t status = mFilterEventFlag->wait( + static_cast(DemuxQueueNotifyBits::DATA_CONSUMED), &efState, + WAIT_TIMEOUT, true /* retry on spurious wake */); + if (status != OK) { + ALOGD("[Filter] wait for data consumed"); + continue; + } + break; + } + + if (mCallback == nullptr) { + ALOGD("[Filter] filter %d does not hava callback. Ending thread", mFilterId); + break; + } + + maySendFilterStatusCallback(); + + while (mFilterThreadRunning) { + std::lock_guard lock(mFilterEventLock); + if (mFilterEvent.events.size() == 0) { + continue; + } + // After successfully write, send a callback and wait for the read to be done + mCallback->onFilterEvent(mFilterEvent); + mFilterEvent.events.resize(0); + break; + } + // We do not wait for the last read to be done + // VTS can verify the read result itself. + if (i == SECTION_WRITE_COUNT - 1) { + ALOGD("[Filter] filter %d writing done. Ending thread", mFilterId); + break; + } + } + mFilterThreadRunning = false; + } + + ALOGD("[Filter] filter thread ended."); +} + +void Filter::maySendFilterStatusCallback() { + std::lock_guard lock(mFilterStatusLock); + int availableToRead = mFilterMQ->availableToRead(); + int availableToWrite = mFilterMQ->availableToWrite(); + int fmqSize = mFilterMQ->getQuantumCount(); + + DemuxFilterStatus newStatus = checkFilterStatusChange( + availableToWrite, availableToRead, ceil(fmqSize * 0.75), ceil(fmqSize * 0.25)); + if (mFilterStatus != newStatus) { + mCallback->onFilterStatus(newStatus); + mFilterStatus = newStatus; + } +} + +DemuxFilterStatus Filter::checkFilterStatusChange(uint32_t availableToWrite, + uint32_t availableToRead, uint32_t highThreshold, + uint32_t lowThreshold) { + if (availableToWrite == 0) { + return DemuxFilterStatus::OVERFLOW; + } else if (availableToRead > highThreshold) { + return DemuxFilterStatus::HIGH_WATER; + } else if (availableToRead < lowThreshold) { + return DemuxFilterStatus::LOW_WATER; + } + return mFilterStatus; +} + +uint16_t Filter::getTpid() { + return mTpid; +} + +void Filter::updateFilterOutput(vector data) { + std::lock_guard lock(mFilterOutputLock); + ALOGD("[Filter] handler output updated"); + mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end()); +} + +Result Filter::startFilterHandler() { + std::lock_guard lock(mFilterOutputLock); + switch (mType.mainType) { + case DemuxFilterMainType::TS: + switch (mType.subType.tsFilterType()) { + case DemuxTsFilterType::UNDEFINED: + break; + case DemuxTsFilterType::SECTION: + startSectionFilterHandler(); + break; + case DemuxTsFilterType::PES: + startPesFilterHandler(); + break; + case DemuxTsFilterType::TS: + startTsFilterHandler(); + break; + case DemuxTsFilterType::AUDIO: + case DemuxTsFilterType::VIDEO: + startMediaFilterHandler(); + break; + case DemuxTsFilterType::PCR: + startPcrFilterHandler(); + break; + case DemuxTsFilterType::RECORD: + startRecordFilterHandler(); + break; + } + break; + case DemuxFilterMainType::MMTP: + /*mmtpSettings*/ + break; + case DemuxFilterMainType::IP: + /*ipSettings*/ + break; + case DemuxFilterMainType::TLV: + /*tlvSettings*/ + break; + case DemuxFilterMainType::ALP: + /*alpSettings*/ + break; + default: + break; + } + return Result::SUCCESS; +} + +Result Filter::startSectionFilterHandler() { + if (mFilterOutput.empty()) { + return Result::SUCCESS; + } + if (!writeSectionsAndCreateEvent(mFilterOutput)) { + ALOGD("[Filter] filter %d fails to write into FMQ. Ending thread", mFilterId); + return Result::UNKNOWN_ERROR; + } + + mFilterOutput.clear(); + + return Result::SUCCESS; +} + +Result Filter::startPesFilterHandler() { + std::lock_guard lock(mFilterEventLock); + if (mFilterOutput.empty()) { + return Result::SUCCESS; + } + + for (int i = 0; i < mFilterOutput.size(); i += 188) { + if (mPesSizeLeft == 0) { + uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) | + mFilterOutput[i + 6]; + ALOGD("[Filter] prefix %d", prefix); + if (prefix == 0x000001) { + // TODO handle mulptiple Pes filters + mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9]; + mPesSizeLeft += 6; + ALOGD("[Filter] pes data length %d", mPesSizeLeft); + } else { + continue; + } + } + + int endPoint = min(184, mPesSizeLeft); + // append data and check size + vector::const_iterator first = mFilterOutput.begin() + i + 4; + vector::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint; + mPesOutput.insert(mPesOutput.end(), first, last); + // size does not match then continue + mPesSizeLeft -= endPoint; + ALOGD("[Filter] pes data left %d", mPesSizeLeft); + if (mPesSizeLeft > 0) { + continue; + } + // size match then create event + if (!writeDataToFilterMQ(mPesOutput)) { + ALOGD("[Filter] pes data write failed"); + mFilterOutput.clear(); + return Result::INVALID_STATE; + } + maySendFilterStatusCallback(); + DemuxFilterPesEvent pesEvent; + pesEvent = { + // temp dump meta data + .streamId = mPesOutput[3], + .dataLength = static_cast(mPesOutput.size()), + }; + ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength); + + int size = mFilterEvent.events.size(); + mFilterEvent.events.resize(size + 1); + mFilterEvent.events[size].pes(pesEvent); + mPesOutput.clear(); + } + + mFilterOutput.clear(); + + return Result::SUCCESS; +} + +Result Filter::startTsFilterHandler() { + // TODO handle starting TS filter + return Result::SUCCESS; +} + +Result Filter::startMediaFilterHandler() { + DemuxFilterMediaEvent mediaEvent; + mediaEvent = { + // temp dump meta data + .pts = 0, + .dataLength = 530, + .avMemory = nullptr, + .isSecureMemory = false, + }; + mFilterEvent.events.resize(1); + mFilterEvent.events[0].media(mediaEvent); + + mFilterOutput.clear(); + // TODO handle write FQM for media stream + return Result::SUCCESS; +} + +Result Filter::startRecordFilterHandler() { + DemuxFilterTsRecordEvent tsRecordEvent; + tsRecordEvent.pid.tPid(0); + tsRecordEvent.indexMask.tsIndexMask(0x01); + mFilterEvent.events.resize(1); + mFilterEvent.events[0].tsRecord(tsRecordEvent); + + mFilterOutput.clear(); + return Result::SUCCESS; +} + +Result Filter::startPcrFilterHandler() { + // TODO handle starting PCR filter + return Result::SUCCESS; +} + +bool Filter::writeSectionsAndCreateEvent(vector data) { + // TODO check how many sections has been read + ALOGD("[Filter] section hander"); + std::lock_guard lock(mFilterEventLock); + if (!writeDataToFilterMQ(data)) { + return false; + } + int size = mFilterEvent.events.size(); + mFilterEvent.events.resize(size + 1); + DemuxFilterSectionEvent secEvent; + secEvent = { + // temp dump meta data + .tableId = 0, + .version = 1, + .sectionNum = 1, + .dataLength = static_cast(data.size()), + }; + mFilterEvent.events[size].section(secEvent); + return true; +} + +bool Filter::writeDataToFilterMQ(const std::vector& data) { + std::lock_guard lock(mWriteLock); + if (mFilterMQ->write(data.data(), data.size())) { + return true; + } + return false; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h new file mode 100644 index 0000000000..21d42974d7 --- /dev/null +++ b/tv/tuner/1.0/default/Filter.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_ +#define ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_ + +#include +#include +#include +#include +#include "Demux.h" +#include "Frontend.h" + +using namespace std; + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::EventFlag; +using ::android::hardware::kSynchronizedReadWrite; +using ::android::hardware::MessageQueue; +using ::android::hardware::MQDescriptorSync; +using ::android::hardware::tv::tuner::V1_0::IDemux; +using ::android::hardware::tv::tuner::V1_0::IFilterCallback; +using ::android::hardware::tv::tuner::V1_0::Result; + +using FilterMQ = MessageQueue; + +class Demux; + +class Filter : public IFilter { + public: + Filter(); + + Filter(DemuxFilterType type, uint32_t filterId, uint32_t bufferSize, + const sp& cb, sp demux); + + ~Filter(); + + virtual Return getId(getId_cb _hidl_cb) override; + + virtual Return setDataSource(const sp& filter) override; + + virtual Return getQueueDesc(getQueueDesc_cb _hidl_cb) override; + + virtual Return configure(const DemuxFilterSettings& settings) override; + + virtual Return start() override; + + virtual Return stop() override; + + virtual Return flush() override; + + virtual Return close() override; + + /** + * To create a FilterMQ and its Event Flag. + * + * Return false is any of the above processes fails. + */ + bool createFilterMQ(); + uint16_t getTpid(); + void updateFilterOutput(vector data); + Result startFilterHandler(); + + private: + // Tuner service + sp mDemux; + /** + * Filter callbacks used on filter events or FMQ status + */ + sp mCallback; + + uint32_t mFilterId; + uint32_t mBufferSize; + DemuxFilterType mType; + DemuxFilterSettings mFilterSettings; + + uint16_t mTpid; + sp mDataSource; + bool mIsDataSourceDemux = true; + vector mFilterOutput; + unique_ptr mFilterMQ; + EventFlag* mFilterEventFlag; + DemuxFilterEvent mFilterEvent; + + // Thread handlers + pthread_t mFilterThread; + + // FMQ status local records + DemuxFilterStatus mFilterStatus; + /** + * If a specific filter's writing loop is still running + */ + bool mFilterThreadRunning; + bool mKeepFetchingDataFromFrontend; + + /** + * How many times a filter should write + * TODO make this dynamic/random/can take as a parameter + */ + const uint16_t SECTION_WRITE_COUNT = 10; + + /** + * Filter handlers to handle the data filtering. + * They are also responsible to write the filtered output into the filter FMQ + * and update the filterEvent bound with the same filterId. + */ + Result startSectionFilterHandler(); + Result startPesFilterHandler(); + Result startTsFilterHandler(); + Result startMediaFilterHandler(); + Result startRecordFilterHandler(); + Result startPcrFilterHandler(); + Result startFilterLoop(); + + void deleteEventFlag(); + bool writeDataToFilterMQ(const std::vector& data); + bool readDataFromMQ(); + bool writeSectionsAndCreateEvent(vector data); + void maySendFilterStatusCallback(); + DemuxFilterStatus checkFilterStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold); + /** + * A dispatcher to read and dispatch input data to all the started filters. + * Each filter handler handles the data filtering/output writing/filterEvent updating. + */ + void startTsFilter(vector data); + bool startFilterDispatcher(); + static void* __threadLoopFilter(void* user); + void filterThreadLoop(); + + /** + * Lock to protect writes to the FMQs + */ + std::mutex mWriteLock; + /** + * Lock to protect writes to the filter event + */ + // TODO make each filter separate event lock + std::mutex mFilterEventLock; + /** + * Lock to protect writes to the input status + */ + std::mutex mFilterStatusLock; + std::mutex mFilterThreadLock; + std::mutex mFilterOutputLock; + + // temp handle single PES filter + // TODO handle mulptiple Pes filters + int mPesSizeLeft = 0; + vector mPesOutput; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_ \ No newline at end of file diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h index 07fa7b93ab..eab43a39fb 100644 --- a/tv/tuner/1.0/default/Frontend.h +++ b/tv/tuner/1.0/default/Frontend.h @@ -75,7 +75,7 @@ class Frontend : public IFrontend { FrontendType mType = FrontendType::UNDEFINED; FrontendId mId = 0; - const string FRONTEND_STREAM_FILE = "/vendor/etc/test1.ts"; + const string FRONTEND_STREAM_FILE = "/vendor/etc/dumpTs3.ts"; string mSourceStreamFile; std::ifstream mFrontendData; }; diff --git a/tv/tuner/1.0/default/Lnb.cpp b/tv/tuner/1.0/default/Lnb.cpp index 1446f7f344..51931d67fe 100644 --- a/tv/tuner/1.0/default/Lnb.cpp +++ b/tv/tuner/1.0/default/Lnb.cpp @@ -30,19 +30,25 @@ Lnb::Lnb() {} Lnb::~Lnb() {} -Return Lnb::setVoltage(FrontendLnbVoltage /* voltage */) { +Return Lnb::setCallback(const sp& /* callback */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; } -Return Lnb::setTone(FrontendLnbTone /* tone */) { +Return Lnb::setVoltage(LnbVoltage /* voltage */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; } -Return Lnb::setSatellitePosition(FrontendLnbPosition /* position */) { +Return Lnb::setTone(LnbTone /* tone */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return Lnb::setSatellitePosition(LnbPosition /* position */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; diff --git a/tv/tuner/1.0/default/Lnb.h b/tv/tuner/1.0/default/Lnb.h index 4c251f7591..f285cb9e65 100644 --- a/tv/tuner/1.0/default/Lnb.h +++ b/tv/tuner/1.0/default/Lnb.h @@ -29,20 +29,23 @@ namespace tuner { namespace V1_0 { namespace implementation { -using ::android::hardware::tv::tuner::V1_0::FrontendLnbPosition; -using ::android::hardware::tv::tuner::V1_0::FrontendLnbTone; -using ::android::hardware::tv::tuner::V1_0::FrontendLnbVoltage; +using ::android::hardware::tv::tuner::V1_0::ILnbCallback; +using ::android::hardware::tv::tuner::V1_0::LnbPosition; +using ::android::hardware::tv::tuner::V1_0::LnbTone; +using ::android::hardware::tv::tuner::V1_0::LnbVoltage; using ::android::hardware::tv::tuner::V1_0::Result; class Lnb : public ILnb { public: Lnb(); - virtual Return setVoltage(FrontendLnbVoltage voltage) override; + virtual Return setCallback(const sp& callback) override; - virtual Return setTone(FrontendLnbTone tone) override; + virtual Return setVoltage(LnbVoltage voltage) override; - virtual Return setSatellitePosition(FrontendLnbPosition position) override; + virtual Return setTone(LnbTone tone) override; + + virtual Return setSatellitePosition(LnbPosition position) override; virtual Return sendDiseqcMessage(const hidl_vec& diseqcMessage) override; diff --git a/tv/tuner/1.0/default/TimeFilter.cpp b/tv/tuner/1.0/default/TimeFilter.cpp new file mode 100644 index 0000000000..0b1fd1cfd2 --- /dev/null +++ b/tv/tuner/1.0/default/TimeFilter.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "android.hardware.tv.tuner@1.0-TimeFilter" + +#include "TimeFilter.h" +#include + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +TimeFilter::TimeFilter() {} + +TimeFilter::TimeFilter(sp demux) { + mDemux = demux; +} + +TimeFilter::~TimeFilter() {} + +Return TimeFilter::setTimeStamp(uint64_t /* timeStamp */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return TimeFilter::clearTimeStamp() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +Return TimeFilter::getTimeStamp(getTimeStamp_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + uint64_t timeStamp = 0; + + _hidl_cb(Result::SUCCESS, timeStamp); + return Void(); +} + +Return TimeFilter::getSourceTime(getSourceTime_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + uint64_t time = 0; + + _hidl_cb(Result::SUCCESS, time); + return Void(); +} + +Return TimeFilter::close() { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/tv/tuner/1.0/default/TimeFilter.h b/tv/tuner/1.0/default/TimeFilter.h new file mode 100644 index 0000000000..7131df85f6 --- /dev/null +++ b/tv/tuner/1.0/default/TimeFilter.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_ +#define ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_ + +#include +#include "Demux.h" + +using namespace std; + +namespace android { +namespace hardware { +namespace tv { +namespace tuner { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::tv::tuner::V1_0::IDemux; +using ::android::hardware::tv::tuner::V1_0::IFilterCallback; +using ::android::hardware::tv::tuner::V1_0::Result; + +using FilterMQ = MessageQueue; + +class Demux; + +class TimeFilter : public ITimeFilter { + public: + TimeFilter(); + + TimeFilter(sp demux); + + ~TimeFilter(); + + virtual Return setTimeStamp(uint64_t timeStamp) override; + + virtual Return clearTimeStamp() override; + + virtual Return getTimeStamp(getTimeStamp_cb _hidl_cb) override; + + virtual Return getSourceTime(getSourceTime_cb _hidl_cb) override; + + virtual Return close() override; + + private: + sp mDemux; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace tuner +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_ \ No newline at end of file From 5d794f4ffae8cb522d53526bdf940470f32516fb Mon Sep 17 00:00:00 2001 From: Amy Date: Fri, 18 Oct 2019 18:05:39 -0700 Subject: [PATCH 3/3] VTS refactoring for filter separation Test: atest Bug: 135708935 Change-Id: I22b6249a953b81793fdfbf17adbadeebde12277a (cherry picked from commit 0f94ba87a0184ff46827705683af851309a6acf8) Merged-In: I22b6249a953b81793fdfbf17adbadeebde12277a --- .../VtsHalTvTunerV1_0TargetTest.cpp | 612 +++++++++++------- 1 file changed, 380 insertions(+), 232 deletions(-) diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 7936185af5..c66622608d 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -20,8 +20,11 @@ #include #include #include -#include #include +#include +#include +#include +#include #include #include #include @@ -57,8 +60,9 @@ using android::hardware::MessageQueue; using android::hardware::MQDescriptorSync; using android::hardware::Return; using android::hardware::Void; -using android::hardware::tv::tuner::V1_0::DemuxDataFormat; +using android::hardware::tv::tuner::V1_0::DataFormat; using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; @@ -66,10 +70,11 @@ using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; using android::hardware::tv::tuner::V1_0::DemuxFilterType; -using android::hardware::tv::tuner::V1_0::DemuxInputSettings; -using android::hardware::tv::tuner::V1_0::DemuxInputStatus; -using android::hardware::tv::tuner::V1_0::DemuxOutputStatus; using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; +using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings; +using android::hardware::tv::tuner::V1_0::DemuxTsFilterType; +using android::hardware::tv::tuner::V1_0::DvrSettings; +using android::hardware::tv::tuner::V1_0::DvrType; using android::hardware::tv::tuner::V1_0::FrontendAtscModulation; using android::hardware::tv::tuner::V1_0::FrontendAtscSettings; using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings; @@ -80,11 +85,17 @@ using android::hardware::tv::tuner::V1_0::FrontendScanMessage; using android::hardware::tv::tuner::V1_0::FrontendScanMessageType; using android::hardware::tv::tuner::V1_0::FrontendSettings; using android::hardware::tv::tuner::V1_0::IDemux; -using android::hardware::tv::tuner::V1_0::IDemuxCallback; using android::hardware::tv::tuner::V1_0::IDescrambler; +using android::hardware::tv::tuner::V1_0::IDvr; +using android::hardware::tv::tuner::V1_0::IDvrCallback; +using android::hardware::tv::tuner::V1_0::IFilter; +using android::hardware::tv::tuner::V1_0::IFilterCallback; using android::hardware::tv::tuner::V1_0::IFrontend; using android::hardware::tv::tuner::V1_0::IFrontendCallback; using android::hardware::tv::tuner::V1_0::ITuner; +using android::hardware::tv::tuner::V1_0::PlaybackSettings; +using android::hardware::tv::tuner::V1_0::PlaybackStatus; +using android::hardware::tv::tuner::V1_0::RecordStatus; using android::hardware::tv::tuner::V1_0::Result; namespace { @@ -131,17 +142,28 @@ const std::vector goldenDataOutputBuffer{ 0x73, 0x63, 0x65, 0x6e, 0x65, }; -const uint16_t FMQ_SIZE_4K = 0x1000; +// const uint16_t FMQ_SIZE_4K = 0x1000; const uint32_t FMQ_SIZE_1M = 0x100000; +const uint32_t FMQ_SIZE_16M = 0x1000000; struct FilterConf { DemuxFilterType type; DemuxFilterSettings setting; }; -struct InputConf { +enum FilterEventType : uint8_t { + UNDEFINED, + SECTION, + MEDIA, + PES, + RECORD, + MMTPRECORD, + DOWNLOAD, +}; + +struct PlaybackConf { string inputDataFile; - DemuxInputSettings setting; + PlaybackSettings setting; }; class FrontendCallback : public IFrontendCallback { @@ -154,14 +176,6 @@ class FrontendCallback : public IFrontendCallback { return Void(); } - virtual Return onDiseqcMessage(const hidl_vec& diseqcMessage) override { - android::Mutex::Autolock autoLock(mMsgLock); - mDiseqcMessageReceived = true; - mEventMessage = diseqcMessage; - mMsgCondition.signal(); - return Void(); - } - virtual Return onScanMessage(FrontendScanMessageType /* type */, const FrontendScanMessage& /* message */) override { android::Mutex::Autolock autoLock(mMsgLock); @@ -211,14 +225,14 @@ void FrontendCallback::testOnDiseqcMessage(sp& frontend, FrontendSett } } -class DemuxCallback : public IDemuxCallback { +class FilterCallback : public IFilterCallback { public: virtual Return onFilterEvent(const DemuxFilterEvent& filterEvent) override { android::Mutex::Autolock autoLock(mMsgLock); // Temprarily we treat the first coming back filter data on the matching pid a success // once all of the MQ are cleared, means we got all the expected output - mFilterIdToEvent[filterEvent.filterId] = filterEvent; - readFilterEventData(filterEvent.filterId); + mFilterIdToEvent = filterEvent; + readFilterEventData(); mPidFilterOutputCount++; // mFilterIdToMQ.erase(filterEvent.filterId); @@ -227,96 +241,50 @@ class DemuxCallback : public IDemuxCallback { return Void(); } - virtual Return onFilterStatus(uint32_t /*filterId*/, - const DemuxFilterStatus /*status*/) override { + virtual Return onFilterStatus(const DemuxFilterStatus /*status*/) override { return Void(); } - virtual Return onOutputStatus(DemuxOutputStatus /*status*/) override { return Void(); } + void setFilterId(uint32_t filterId) { mFilterId = filterId; } + void setFilterEventType(FilterEventType type) { mFilterEventType = type; } - virtual Return onInputStatus(DemuxInputStatus status) override { - // android::Mutex::Autolock autoLock(mMsgLock); - ALOGW("[vts] input status %d", status); - switch (status) { - case DemuxInputStatus::SPACE_EMPTY: - case DemuxInputStatus::SPACE_ALMOST_EMPTY: - ALOGW("[vts] keep inputing %d", status); - mKeepWritingInputFMQ = true; - break; - case DemuxInputStatus::SPACE_ALMOST_FULL: - case DemuxInputStatus::SPACE_FULL: - ALOGW("[vts] stop inputing %d", status); - mKeepWritingInputFMQ = false; - break; - } - return Void(); - } - - void testOnFilterEvent(uint32_t filterId); void testFilterDataOutput(); - void stopInputThread(); - void startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor); void startFilterEventThread(DemuxFilterEvent event); - static void* __threadLoopInput(void* threadArgs); static void* __threadLoopFilter(void* threadArgs); - void inputThreadLoop(InputConf* inputConf, bool* keepWritingInputFMQ); void filterThreadLoop(DemuxFilterEvent& event); - void updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor); - void updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile); - bool readFilterEventData(uint32_t filterId); + void updateFilterMQ(MQDesc& filterMQDescriptor); + void updateGoldenOutputMap(string goldenOutputFile); + bool readFilterEventData(); private: - struct InputThreadArgs { - DemuxCallback* user; - InputConf* inputConf; - bool* keepWritingInputFMQ; - }; struct FilterThreadArgs { - DemuxCallback* user; + FilterCallback* user; DemuxFilterEvent event; }; uint16_t mDataLength = 0; std::vector mDataOutputBuffer; - bool mFilterEventReceived; - std::map mFilterIdToGoldenOutput; + string mFilterIdToGoldenOutput; - std::map> mFilterIdToMQ; - std::unique_ptr mInputMQ; - std::map mFilterIdToMQEventFlag; - std::map mFilterIdToEvent; - EventFlag* mInputMQEventFlag; + uint32_t mFilterId; + FilterEventType mFilterEventType; + std::unique_ptr mFilterIdToMQ; + EventFlag* mFilterIdToMQEventFlag; + DemuxFilterEvent mFilterIdToEvent; android::Mutex mMsgLock; android::Mutex mFilterOutputLock; - android::Mutex mInputThreadLock; android::Condition mMsgCondition; android::Condition mFilterOutputCondition; - bool mKeepWritingInputFMQ = true; - bool mInputThreadRunning; - pthread_t mInputThread; pthread_t mFilterThread; int mPidFilterOutputCount = 0; }; -void DemuxCallback::startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor) { - mInputMQ = std::make_unique(inputMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(mInputMQ); - struct InputThreadArgs* threadArgs = - (struct InputThreadArgs*)malloc(sizeof(struct InputThreadArgs)); - threadArgs->user = this; - threadArgs->inputConf = &inputConf; - threadArgs->keepWritingInputFMQ = &mKeepWritingInputFMQ; - - pthread_create(&mInputThread, NULL, __threadLoopInput, (void*)threadArgs); - pthread_setname_np(mInputThread, "test_playback_input_loop"); -} - -void DemuxCallback::startFilterEventThread(DemuxFilterEvent event) { +void FilterCallback::startFilterEventThread(DemuxFilterEvent event) { struct FilterThreadArgs* threadArgs = (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs)); threadArgs->user = this; @@ -326,7 +294,7 @@ void DemuxCallback::startFilterEventThread(DemuxFilterEvent event) { pthread_setname_np(mFilterThread, "test_playback_input_loop"); } -void DemuxCallback::testFilterDataOutput() { +void FilterCallback::testFilterDataOutput() { android::Mutex::Autolock autoLock(mMsgLock); while (mPidFilterOutputCount < 1) { if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { @@ -338,95 +306,25 @@ void DemuxCallback::testFilterDataOutput() { ALOGW("[vts] pass and stop"); } -void DemuxCallback::stopInputThread() { - mInputThreadRunning = false; - mKeepWritingInputFMQ = false; - - android::Mutex::Autolock autoLock(mInputThreadLock); +void FilterCallback::updateFilterMQ(MQDesc& filterMQDescriptor) { + mFilterIdToMQ = std::make_unique(filterMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mFilterIdToMQ); + EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ->getEventFlagWord(), + &mFilterIdToMQEventFlag) == android::OK); } -void DemuxCallback::updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor) { - mFilterIdToMQ[filterId] = - std::make_unique(filterMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(mFilterIdToMQ[filterId]); - EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ[filterId]->getEventFlagWord(), - &mFilterIdToMQEventFlag[filterId]) == android::OK); +void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) { + mFilterIdToGoldenOutput = goldenOutputFile; } -void DemuxCallback::updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile) { - mFilterIdToGoldenOutput[filterId] = goldenOutputFile; -} - -void* DemuxCallback::__threadLoopInput(void* threadArgs) { - DemuxCallback* const self = - static_cast(((struct InputThreadArgs*)threadArgs)->user); - self->inputThreadLoop(((struct InputThreadArgs*)threadArgs)->inputConf, - ((struct InputThreadArgs*)threadArgs)->keepWritingInputFMQ); - return 0; -} - -void DemuxCallback::inputThreadLoop(InputConf* inputConf, bool* keepWritingInputFMQ) { - android::Mutex::Autolock autoLock(mInputThreadLock); - mInputThreadRunning = true; - - // Create the EventFlag that is used to signal the HAL impl that data have been - // written into the Input FMQ - EventFlag* inputMQEventFlag; - EXPECT_TRUE(EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &inputMQEventFlag) == - android::OK); - - // open the stream and get its length - std::ifstream inputData(inputConf->inputDataFile, std::ifstream::binary); - int writeSize = inputConf->setting.packetSize * 6; - char* buffer = new char[writeSize]; - ALOGW("[vts] input thread loop start %s", inputConf->inputDataFile.c_str()); - if (!inputData.is_open()) { - mInputThreadRunning = false; - ALOGW("[vts] Error %s", strerror(errno)); - } - - while (mInputThreadRunning) { - // move the stream pointer for packet size * 6 every read until the end - while (*keepWritingInputFMQ) { - inputData.read(buffer, writeSize); - if (!inputData) { - int leftSize = inputData.gcount(); - if (leftSize == 0) { - mInputThreadRunning = false; - break; - } - inputData.clear(); - inputData.read(buffer, leftSize); - // Write the left over of the input data and quit the thread - if (leftSize > 0) { - EXPECT_TRUE(mInputMQ->write((unsigned char*)&buffer[0], leftSize)); - inputMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); - } - mInputThreadRunning = false; - break; - } - // Write input FMQ and notify the Tuner Implementation - EXPECT_TRUE(mInputMQ->write((unsigned char*)&buffer[0], writeSize)); - inputMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); - inputData.seekg(writeSize, inputData.cur); - sleep(1); - } - } - - ALOGW("[vts] Input thread end."); - - delete[] buffer; - inputData.close(); -} - -void* DemuxCallback::__threadLoopFilter(void* threadArgs) { - DemuxCallback* const self = - static_cast(((struct FilterThreadArgs*)threadArgs)->user); +void* FilterCallback::__threadLoopFilter(void* threadArgs) { + FilterCallback* const self = + static_cast(((struct FilterThreadArgs*)threadArgs)->user); self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event); return 0; } -void DemuxCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { +void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { android::Mutex::Autolock autoLock(mFilterOutputLock); // Read from mFilterIdToMQ[event.filterId] per event and filter type @@ -439,30 +337,184 @@ void DemuxCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { // end thread } -bool DemuxCallback::readFilterEventData(uint32_t filterId) { +bool FilterCallback::readFilterEventData() { bool result = false; - DemuxFilterEvent filterEvent = mFilterIdToEvent[filterId]; - ALOGW("[vts] reading from filter FMQ %d", filterId); + DemuxFilterEvent filterEvent = mFilterIdToEvent; + ALOGW("[vts] reading from filter FMQ %d", mFilterId); // todo separate filter handlers for (int i = 0; i < filterEvent.events.size(); i++) { - DemuxFilterPesEvent event = filterEvent.events[i].pes(); - mDataLength = event.dataLength; + switch (mFilterEventType) { + case FilterEventType::SECTION: + mDataLength = filterEvent.events[i].section().dataLength; + break; + case FilterEventType::PES: + mDataLength = filterEvent.events[i].pes().dataLength; + break; + case FilterEventType::MEDIA: + break; + case FilterEventType::RECORD: + break; + case FilterEventType::MMTPRECORD: + break; + case FilterEventType::DOWNLOAD: + break; + default: + break; + } // EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not // match"; mDataOutputBuffer.resize(mDataLength); - result = mFilterIdToMQ[filterId]->read(mDataOutputBuffer.data(), mDataLength); + result = mFilterIdToMQ->read(mDataOutputBuffer.data(), mDataLength); EXPECT_TRUE(result) << "can't read from Filter MQ"; /*for (int i = 0; i < mDataLength; i++) { EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; }*/ } - mFilterIdToMQEventFlag[filterId]->wake( - static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); + mFilterIdToMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); return result; } +class DvrCallback : public IDvrCallback { + public: + virtual Return onRecordStatus(RecordStatus /*status*/) override { return Void(); } + + virtual Return onPlaybackStatus(PlaybackStatus status) override { + // android::Mutex::Autolock autoLock(mMsgLock); + ALOGW("[vts] playback status %d", status); + switch (status) { + case PlaybackStatus::SPACE_EMPTY: + case PlaybackStatus::SPACE_ALMOST_EMPTY: + ALOGW("[vts] keep playback inputing %d", status); + mKeepWritingPlaybackFMQ = true; + break; + case PlaybackStatus::SPACE_ALMOST_FULL: + case PlaybackStatus::SPACE_FULL: + ALOGW("[vts] stop playback inputing %d", status); + mKeepWritingPlaybackFMQ = false; + break; + } + return Void(); + } + + void testFilterDataOutput(); + void stopPlaybackThread(); + + void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor); + static void* __threadLoopPlayback(void* threadArgs); + void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ); + + private: + struct PlaybackThreadArgs { + DvrCallback* user; + PlaybackConf* playbackConf; + bool* keepWritingPlaybackFMQ; + }; + uint16_t mDataLength = 0; + std::vector mDataOutputBuffer; + + std::map> mFilterIdToMQ; + std::unique_ptr mPlaybackMQ; + std::map mFilterIdToMQEventFlag; + std::map mFilterIdToEvent; + EventFlag* mPlaybackMQEventFlag; + + android::Mutex mMsgLock; + android::Mutex mPlaybackThreadLock; + android::Condition mMsgCondition; + + bool mKeepWritingPlaybackFMQ = true; + bool mPlaybackThreadRunning; + pthread_t mPlaybackThread; + + int mPidFilterOutputCount = 0; +}; + +void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf, + MQDesc& playbackMQDescriptor) { + mPlaybackMQ = std::make_unique(playbackMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mPlaybackMQ); + struct PlaybackThreadArgs* threadArgs = + (struct PlaybackThreadArgs*)malloc(sizeof(struct PlaybackThreadArgs)); + threadArgs->user = this; + threadArgs->playbackConf = &playbackConf; + threadArgs->keepWritingPlaybackFMQ = &mKeepWritingPlaybackFMQ; + + pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, (void*)threadArgs); + pthread_setname_np(mPlaybackThread, "test_playback_input_loop"); +} + +void DvrCallback::stopPlaybackThread() { + mPlaybackThreadRunning = false; + mKeepWritingPlaybackFMQ = false; + + android::Mutex::Autolock autoLock(mPlaybackThreadLock); +} + +void* DvrCallback::__threadLoopPlayback(void* threadArgs) { + DvrCallback* const self = + static_cast(((struct PlaybackThreadArgs*)threadArgs)->user); + self->playbackThreadLoop(((struct PlaybackThreadArgs*)threadArgs)->playbackConf, + ((struct PlaybackThreadArgs*)threadArgs)->keepWritingPlaybackFMQ); + return 0; +} + +void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ) { + android::Mutex::Autolock autoLock(mPlaybackThreadLock); + mPlaybackThreadRunning = true; + + // Create the EventFlag that is used to signal the HAL impl that data have been + // written into the Playback FMQ + EventFlag* playbackMQEventFlag; + EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) == + android::OK); + + // open the stream and get its length + std::ifstream inputData(playbackConf->inputDataFile, std::ifstream::binary); + int writeSize = playbackConf->setting.packetSize * 6; + char* buffer = new char[writeSize]; + ALOGW("[vts] playback thread loop start %s", playbackConf->inputDataFile.c_str()); + if (!inputData.is_open()) { + mPlaybackThreadRunning = false; + ALOGW("[vts] Error %s", strerror(errno)); + } + + while (mPlaybackThreadRunning) { + // move the stream pointer for packet size * 6 every read until the end + while (*keepWritingPlaybackFMQ) { + inputData.read(buffer, writeSize); + if (!inputData) { + int leftSize = inputData.gcount(); + if (leftSize == 0) { + mPlaybackThreadRunning = false; + break; + } + inputData.clear(); + inputData.read(buffer, leftSize); + // Write the left over of the input data and quit the thread + if (leftSize > 0) { + EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], leftSize)); + playbackMQEventFlag->wake( + static_cast(DemuxQueueNotifyBits::DATA_READY)); + } + mPlaybackThreadRunning = false; + break; + } + // Write input FMQ and notify the Tuner Implementation + EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], writeSize)); + playbackMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_READY)); + inputData.seekg(writeSize, inputData.cur); + sleep(1); + } + } + + ALOGW("[vts] Playback thread end."); + + delete[] buffer; + inputData.close(); +} + // Test environment for Tuner HIDL HAL. class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: @@ -494,16 +546,21 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { sp mFrontendCallback; sp mDescrambler; sp mDemux; - sp mDemuxCallback; + sp mDvr; + sp mFilter; + std::map> mFilters; + std::map> mFilterCallbacks; + sp mFilterCallback; + sp mDvrCallback; MQDesc mFilterMQDescriptor; - MQDesc mInputMQDescriptor; + MQDesc mPlaybackMQDescriptor; vector mUsedFilterIds; uint32_t mDemuxId; uint32_t mFilterId; - pthread_t mInputThread; - bool mInputThreadRunning; + pthread_t mPlaybackshread; + bool mPlaybackThreadRunning; ::testing::AssertionResult createFrontend(int32_t frontendId); ::testing::AssertionResult tuneFrontend(int32_t frontendId); @@ -512,16 +569,16 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { ::testing::AssertionResult createDemux(); ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId, FrontendSettings settings); - ::testing::AssertionResult getInputMQDescriptor(); - ::testing::AssertionResult addInputToDemux(DemuxInputSettings setting); + ::testing::AssertionResult getPlaybackMQDescriptor(); + ::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting); ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting); - ::testing::AssertionResult getFilterMQDescriptor(const uint32_t filterId); + ::testing::AssertionResult getFilterMQDescriptor(); ::testing::AssertionResult closeDemux(); ::testing::AssertionResult createDescrambler(); ::testing::AssertionResult closeDescrambler(); ::testing::AssertionResult playbackDataFlowTest(vector filterConf, - InputConf inputConf, + PlaybackConf playbackConf, vector goldenOutputFiles); ::testing::AssertionResult broadcastDataFlowTest(vector filterConf, vector goldenOutputFiles); @@ -665,39 +722,43 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionResult(status == Result::SUCCESS); } -::testing::AssertionResult TunerHidlTest::addInputToDemux(DemuxInputSettings setting) { +::testing::AssertionResult TunerHidlTest::addPlaybackToDemux(PlaybackSettings setting) { Result status; if (!mDemux && createDemux() == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } - // Create demux callback - if (!mDemuxCallback) { - mDemuxCallback = new DemuxCallback(); - } + // Create dvr callback + mDvrCallback = new DvrCallback(); // Add playback input to the local demux - status = mDemux->addInput(FMQ_SIZE_1M, mDemuxCallback); + mDemux->openDvr(DvrType::PLAYBACK, FMQ_SIZE_1M, mDvrCallback, + [&](Result result, const sp& dvr) { + mDvr = dvr; + status = result; + }); if (status != Result::SUCCESS) { return ::testing::AssertionFailure(); } - status = mDemux->configureInput(setting); + DvrSettings dvrSetting; + dvrSetting.playback(setting); + status = mDvr->configure(dvrSetting); return ::testing::AssertionResult(status == Result::SUCCESS); } -::testing::AssertionResult TunerHidlTest::getInputMQDescriptor() { +::testing::AssertionResult TunerHidlTest::getPlaybackMQDescriptor() { Result status; - if (!mDemux && createDemux() == ::testing::AssertionFailure()) { + if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) { return ::testing::AssertionFailure(); } - mDemux->getInputQueueDesc([&](Result result, const MQDesc& inputMQDesc) { - mInputMQDescriptor = inputMQDesc; + mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) { + mPlaybackMQDescriptor = dvrMQDesc; status = result; }); @@ -713,13 +774,20 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { } // Create demux callback - if (!mDemuxCallback) { - mDemuxCallback = new DemuxCallback(); - } + mFilterCallback = new FilterCallback(); // Add filter to the local demux - mDemux->addFilter(type, FMQ_SIZE_4K, mDemuxCallback, [&](Result result, uint32_t filterId) { - // TODO use a map to save all the filter id and FMQ + mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback, + [&](Result result, const sp& filter) { + mFilter = filter; + status = result; + }); + + if (status != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + + mFilter->getId([&](Result result, uint32_t filterId) { mFilterId = filterId; status = result; }); @@ -728,20 +796,64 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { return ::testing::AssertionFailure(); } + mFilterCallback->setFilterId(mFilterId); + + FilterEventType eventType = FilterEventType::UNDEFINED; + switch (type.mainType) { + case DemuxFilterMainType::TS: + switch (type.subType.tsFilterType()) { + case DemuxTsFilterType::UNDEFINED: + break; + case DemuxTsFilterType::SECTION: + eventType = FilterEventType::SECTION; + break; + case DemuxTsFilterType::PES: + eventType = FilterEventType::PES; + break; + case DemuxTsFilterType::TS: + break; + case DemuxTsFilterType::AUDIO: + case DemuxTsFilterType::VIDEO: + eventType = FilterEventType::MEDIA; + break; + case DemuxTsFilterType::PCR: + break; + case DemuxTsFilterType::RECORD: + eventType = FilterEventType::RECORD; + break; + } + break; + case DemuxFilterMainType::MMTP: + /*mmtpSettings*/ + break; + case DemuxFilterMainType::IP: + /*ipSettings*/ + break; + case DemuxFilterMainType::TLV: + /*tlvSettings*/ + break; + case DemuxFilterMainType::ALP: + /*alpSettings*/ + break; + default: + break; + } + mFilterCallback->setFilterEventType(eventType); + // Configure the filter - status = mDemux->configureFilter(mFilterId, setting); + status = mFilter->configure(setting); return ::testing::AssertionResult(status == Result::SUCCESS); } -::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor(const uint32_t filterId) { +::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor() { Result status; - if (!mDemux) { + if (!mDemux || !mFilter) { return ::testing::AssertionFailure(); } - mDemux->getFilterQueueDesc(filterId, [&](Result result, const MQDesc& filterMQDesc) { + mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) { mFilterMQDescriptor = filterMQDesc; status = result; }); @@ -750,7 +862,8 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { } ::testing::AssertionResult TunerHidlTest::playbackDataFlowTest( - vector filterConf, InputConf inputConf, vector /*goldenOutputFiles*/) { + vector filterConf, PlaybackConf playbackConf, + vector /*goldenOutputFiles*/) { Result status; int filterIdsSize; // Filter Configuration Module @@ -758,45 +871,58 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) == ::testing::AssertionFailure() || // TODO use a map to save the FMQs/EvenFlags and pass to callback - getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) { + getFilterMQDescriptor() == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } filterIdsSize = mUsedFilterIds.size(); mUsedFilterIds.resize(filterIdsSize + 1); mUsedFilterIds[filterIdsSize] = mFilterId; - mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor); - // mDemuxCallback->updateGoldenOutputMap(mFilterId, goldenOutputFiles[i]); - status = mDemux->startFilter(mFilterId); + mFilters[mFilterId] = mFilter; + mFilterCallbacks[mFilterId] = mFilterCallback; + mFilterCallback->updateFilterMQ(mFilterMQDescriptor); + // mDemuxCallback->updateGoldenOutputMap(goldenOutputFiles[i]); + status = mFilter->start(); if (status != Result::SUCCESS) { return ::testing::AssertionFailure(); } } // Playback Input Module - DemuxInputSettings inputSetting = inputConf.setting; - if (addInputToDemux(inputSetting) == ::testing::AssertionFailure() || - getInputMQDescriptor() == ::testing::AssertionFailure()) { + PlaybackSettings playbackSetting = playbackConf.setting; + if (addPlaybackToDemux(playbackSetting) == ::testing::AssertionFailure() || + getPlaybackMQDescriptor() == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } - mDemuxCallback->startPlaybackInputThread(inputConf, mInputMQDescriptor); - status = mDemux->startInput(); + for (int i = 0; i <= filterIdsSize; i++) { + if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) { + return ::testing::AssertionFailure(); + } + } + mDvrCallback->startPlaybackInputThread(playbackConf, mPlaybackMQDescriptor); + status = mDvr->start(); if (status != Result::SUCCESS) { return ::testing::AssertionFailure(); } // Data Verify Module - mDemuxCallback->testFilterDataOutput(); - mDemuxCallback->stopInputThread(); + std::map>::iterator it; + for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) { + it->second->testFilterDataOutput(); + } + mDvrCallback->stopPlaybackThread(); // Clean Up Module for (int i = 0; i <= filterIdsSize; i++) { - if (mDemux->stopFilter(mUsedFilterIds[i]) != Result::SUCCESS) { + if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) { return ::testing::AssertionFailure(); } } - if (mDemux->stopInput() != Result::SUCCESS) { + if (mDvr->stop() != Result::SUCCESS) { return ::testing::AssertionFailure(); } + mUsedFilterIds.clear(); + mFilterCallbacks.clear(); + mFilters.clear(); return closeDemux(); } @@ -831,31 +957,39 @@ class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase { if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) == ::testing::AssertionFailure() || // TODO use a map to save the FMQs/EvenFlags and pass to callback - getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) { + getFilterMQDescriptor() == ::testing::AssertionFailure()) { return ::testing::AssertionFailure(); } filterIdsSize = mUsedFilterIds.size(); mUsedFilterIds.resize(filterIdsSize + 1); mUsedFilterIds[filterIdsSize] = mFilterId; - mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor); - status = mDemux->startFilter(mFilterId); + mFilters[mFilterId] = mFilter; + mFilterCallbacks[mFilterId] = mFilterCallback; + mFilterCallback->updateFilterMQ(mFilterMQDescriptor); + status = mFilter->start(); if (status != Result::SUCCESS) { return ::testing::AssertionFailure(); } } // Data Verify Module - mDemuxCallback->testFilterDataOutput(); + std::map>::iterator it; + for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) { + it->second->testFilterDataOutput(); + } // Clean Up Module for (int i = 0; i <= filterIdsSize; i++) { - if (mDemux->stopFilter(mUsedFilterIds[i]) != Result::SUCCESS) { + if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) { return ::testing::AssertionFailure(); } } if (mFrontend->stopTune() != Result::SUCCESS) { return ::testing::AssertionFailure(); } + mUsedFilterIds.clear(); + mFilterCallbacks.clear(); + mFilters.clear(); return closeDemux(); } @@ -992,7 +1126,7 @@ TEST_F(TunerHidlTest, CloseDescrambler) { /* * DATA FLOW TESTS */ -TEST_F(TunerHidlTest, PlaybackDataFlowWithPesFilterTest) { +TEST_F(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) { description("Feed ts data from playback and configure pes filter to get output"); // todo modulize the filter conf parser @@ -1000,32 +1134,39 @@ TEST_F(TunerHidlTest, PlaybackDataFlowWithPesFilterTest) { filterConf.resize(1); DemuxFilterSettings filterSetting; - DemuxFilterPesDataSettings pesFilterSetting{ + DemuxTsFilterSettings tsFilterSetting{ .tpid = 18, }; - filterSetting.pesData(pesFilterSetting); - FilterConf pesFilterConf{ - .type = DemuxFilterType::PES, + DemuxFilterSectionSettings sectionFilterSetting; + tsFilterSetting.filterSettings.section(sectionFilterSetting); + filterSetting.ts(tsFilterSetting); + + DemuxFilterType type{ + .mainType = DemuxFilterMainType::TS, + }; + type.subType.tsFilterType(DemuxTsFilterType::SECTION); + FilterConf sectionFilterConf{ + .type = type, .setting = filterSetting, }; - filterConf[0] = pesFilterConf; + filterConf[0] = sectionFilterConf; - DemuxInputSettings inputSetting{ + PlaybackSettings playbackSetting{ .statusMask = 0xf, .lowThreshold = 0x1000, .highThreshold = 0x07fff, - .dataFormat = DemuxDataFormat::TS, + .dataFormat = DataFormat::TS, .packetSize = 188, }; - InputConf inputConf{ + PlaybackConf playbackConf{ .inputDataFile = "/vendor/etc/test1.ts", - .setting = inputSetting, + .setting = playbackSetting, }; vector goldenOutputFiles; - ASSERT_TRUE(playbackDataFlowTest(filterConf, inputConf, goldenOutputFiles)); + ASSERT_TRUE(playbackDataFlowTest(filterConf, playbackConf, goldenOutputFiles)); } TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) { @@ -1036,12 +1177,19 @@ TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) { filterConf.resize(1); DemuxFilterSettings filterSetting; - DemuxFilterPesDataSettings pesFilterSetting{ - .tpid = 18, + DemuxTsFilterSettings tsFilterSetting{ + .tpid = 119, }; - filterSetting.pesData(pesFilterSetting); + DemuxFilterPesDataSettings pesFilterSetting; + tsFilterSetting.filterSettings.pesData(pesFilterSetting); + filterSetting.ts(tsFilterSetting); + + DemuxFilterType type{ + .mainType = DemuxFilterMainType::TS, + }; + type.subType.tsFilterType(DemuxTsFilterType::PES); FilterConf pesFilterConf{ - .type = DemuxFilterType::PES, + .type = type, .setting = filterSetting, }; filterConf[0] = pesFilterConf;