1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.media.tv.tuner.filter;
18 
19 import android.annotation.BytesLong;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SystemApi;
24 import android.hardware.tv.tuner.V1_0.Constants;
25 import android.media.tv.tuner.Tuner;
26 import android.media.tv.tuner.Tuner.Result;
27 import android.media.tv.tuner.TunerUtils;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 import java.util.concurrent.Executor;
32 
33 /**
34  * Tuner data filter.
35  *
36  * <p>This class is used to filter wanted data according to the filter's configuration.
37  *
38  * @hide
39  */
40 @SystemApi
41 public class Filter implements AutoCloseable {
42     /** @hide */
43     @IntDef(prefix = "TYPE_",
44             value = {TYPE_TS, TYPE_MMTP, TYPE_IP, TYPE_TLV, TYPE_ALP})
45     @Retention(RetentionPolicy.SOURCE)
46     public @interface Type {}
47 
48     /**
49      * Undefined filter type.
50      */
51     public static final int TYPE_UNDEFINED = 0;
52     /**
53      * TS filter type.
54      */
55     public static final int TYPE_TS = Constants.DemuxFilterMainType.TS;
56     /**
57      * MMTP filter type.
58      */
59     public static final int TYPE_MMTP = Constants.DemuxFilterMainType.MMTP;
60     /**
61      * IP filter type.
62      */
63     public static final int TYPE_IP = Constants.DemuxFilterMainType.IP;
64     /**
65      * TLV filter type.
66      */
67     public static final int TYPE_TLV = Constants.DemuxFilterMainType.TLV;
68     /**
69      * ALP filter type.
70      */
71     public static final int TYPE_ALP = Constants.DemuxFilterMainType.ALP;
72 
73     /** @hide */
74     @IntDef(prefix = "SUBTYPE_",
75             value = {SUBTYPE_UNDEFINED, SUBTYPE_SECTION, SUBTYPE_PES, SUBTYPE_AUDIO, SUBTYPE_VIDEO,
76                     SUBTYPE_DOWNLOAD, SUBTYPE_RECORD, SUBTYPE_TS, SUBTYPE_PCR, SUBTYPE_TEMI,
77                     SUBTYPE_MMTP, SUBTYPE_NTP, SUBTYPE_IP_PAYLOAD, SUBTYPE_IP,
78                     SUBTYPE_PAYLOAD_THROUGH, SUBTYPE_TLV, SUBTYPE_PTP, })
79     @Retention(RetentionPolicy.SOURCE)
80     public @interface Subtype {}
81     /**
82      * Filter subtype undefined.
83      */
84     public static final int SUBTYPE_UNDEFINED = 0;
85     /**
86      * Section filter subtype.
87      */
88     public static final int SUBTYPE_SECTION = 1;
89     /**
90      * PES filter subtype.
91      */
92     public static final int SUBTYPE_PES = 2;
93     /**
94      * Audio filter subtype.
95      */
96     public static final int SUBTYPE_AUDIO = 3;
97     /**
98      * Video filter subtype.
99      */
100     public static final int SUBTYPE_VIDEO = 4;
101     /**
102      * Download filter subtype.
103      */
104     public static final int SUBTYPE_DOWNLOAD = 5;
105     /**
106      * Record filter subtype.
107      */
108     public static final int SUBTYPE_RECORD = 6;
109     /**
110      * TS filter subtype.
111      */
112     public static final int SUBTYPE_TS = 7;
113     /**
114      * PCR filter subtype.
115      */
116     public static final int SUBTYPE_PCR = 8;
117     /**
118      * TEMI filter subtype.
119      */
120     public static final int SUBTYPE_TEMI = 9;
121     /**
122      * MMTP filter subtype.
123      */
124     public static final int SUBTYPE_MMTP = 10;
125     /**
126      * NTP filter subtype.
127      */
128     public static final int SUBTYPE_NTP = 11;
129     /**
130      * Payload filter subtype.
131      */
132     public static final int SUBTYPE_IP_PAYLOAD = 12;
133     /**
134      * IP filter subtype.
135      */
136     public static final int SUBTYPE_IP = 13;
137     /**
138      * Payload through filter subtype.
139      */
140     public static final int SUBTYPE_PAYLOAD_THROUGH = 14;
141     /**
142      * TLV filter subtype.
143      */
144     public static final int SUBTYPE_TLV = 15;
145     /**
146      * PTP filter subtype.
147      */
148     public static final int SUBTYPE_PTP = 16;
149 
150 
151 
152     /** @hide */
153     @IntDef(flag = true, prefix = "STATUS_", value = {STATUS_DATA_READY, STATUS_LOW_WATER,
154             STATUS_HIGH_WATER, STATUS_OVERFLOW})
155     @Retention(RetentionPolicy.SOURCE)
156     public @interface Status {}
157 
158     /**
159      * The status of a filter that the data in the filter buffer is ready to be read.
160      */
161     public static final int STATUS_DATA_READY = Constants.DemuxFilterStatus.DATA_READY;
162     /**
163      * The status of a filter that the amount of available data in the filter buffer is at low
164      * level.
165      *
166      * The value is set to 25 percent of the buffer size by default. It can be changed when
167      * configuring the filter.
168      */
169     public static final int STATUS_LOW_WATER = Constants.DemuxFilterStatus.LOW_WATER;
170     /**
171      * The status of a filter that the amount of available data in the filter buffer is at high
172      * level.
173      * The value is set to 75 percent of the buffer size by default. It can be changed when
174      * configuring the filter.
175      */
176     public static final int STATUS_HIGH_WATER = Constants.DemuxFilterStatus.HIGH_WATER;
177     /**
178      * The status of a filter that the filter buffer is full and newly filtered data is being
179      * discarded.
180      */
181     public static final int STATUS_OVERFLOW = Constants.DemuxFilterStatus.OVERFLOW;
182 
183     private static final String TAG = "Filter";
184 
185     private long mNativeContext;
186     private FilterCallback mCallback;
187     private Executor mExecutor;
188     private final int mId;
189     private int mMainType;
190     private int mSubtype;
191     private Filter mSource;
192     private boolean mStarted;
193     private boolean mIsClosed = false;
194     private final Object mLock = new Object();
195 
nativeConfigureFilter( int type, int subType, FilterConfiguration settings)196     private native int nativeConfigureFilter(
197             int type, int subType, FilterConfiguration settings);
nativeGetId()198     private native int nativeGetId();
nativeSetDataSource(Filter source)199     private native int nativeSetDataSource(Filter source);
nativeStartFilter()200     private native int nativeStartFilter();
nativeStopFilter()201     private native int nativeStopFilter();
nativeFlushFilter()202     private native int nativeFlushFilter();
nativeRead(byte[] buffer, long offset, long size)203     private native int nativeRead(byte[] buffer, long offset, long size);
nativeClose()204     private native int nativeClose();
205 
206     // Called by JNI
Filter(int id)207     private Filter(int id) {
208         mId = id;
209     }
210 
onFilterStatus(int status)211     private void onFilterStatus(int status) {
212         if (mCallback != null && mExecutor != null) {
213             mExecutor.execute(() -> mCallback.onFilterStatusChanged(this, status));
214         }
215     }
216 
onFilterEvent(FilterEvent[] events)217     private void onFilterEvent(FilterEvent[] events) {
218         if (mCallback != null && mExecutor != null) {
219             mExecutor.execute(() -> mCallback.onFilterEvent(this, events));
220         }
221     }
222 
223     /** @hide */
setType(@ype int mainType, @Subtype int subtype)224     public void setType(@Type int mainType, @Subtype int subtype) {
225         mMainType = mainType;
226         mSubtype = TunerUtils.getFilterSubtype(mainType, subtype);
227     }
228 
229     /** @hide */
setCallback(FilterCallback cb, Executor executor)230     public void setCallback(FilterCallback cb, Executor executor) {
231         mCallback = cb;
232         mExecutor = executor;
233     }
234 
235     /** @hide */
getCallback()236     public FilterCallback getCallback() {
237         return mCallback;
238     }
239 
240     /**
241      * Configures the filter.
242      *
243      * @param config the configuration of the filter.
244      * @return result status of the operation.
245      */
246     @Result
configure(@onNull FilterConfiguration config)247     public int configure(@NonNull FilterConfiguration config) {
248         synchronized (mLock) {
249             TunerUtils.checkResourceState(TAG, mIsClosed);
250             Settings s = config.getSettings();
251             int subType = (s == null) ? mSubtype : s.getType();
252             if (mMainType != config.getType() || mSubtype != subType) {
253                 throw new IllegalArgumentException("Invalid filter config. filter main type="
254                         + mMainType + ", filter subtype=" + mSubtype + ". config main type="
255                         + config.getType() + ", config subtype=" + subType);
256             }
257             return nativeConfigureFilter(config.getType(), subType, config);
258         }
259     }
260 
261     /**
262      * Gets the filter Id.
263      */
getId()264     public int getId() {
265         synchronized (mLock) {
266             TunerUtils.checkResourceState(TAG, mIsClosed);
267             return nativeGetId();
268         }
269     }
270 
271     /**
272      * Sets the filter's data source.
273      *
274      * A filter uses demux as data source by default. If the data was packetized
275      * by multiple protocols, multiple filters may need to work together to
276      * extract all protocols' header. Then a filter's data source can be output
277      * from another filter.
278      *
279      * @param source the filter instance which provides data input. Switch to
280      * use demux as data source if the filter instance is NULL.
281      * @return result status of the operation.
282      * @throws IllegalStateException if the data source has been set.
283      */
284     @Result
setDataSource(@ullable Filter source)285     public int setDataSource(@Nullable Filter source) {
286         synchronized (mLock) {
287             TunerUtils.checkResourceState(TAG, mIsClosed);
288             if (mSource != null) {
289                 throw new IllegalStateException("Data source is existing");
290             }
291             int res = nativeSetDataSource(source);
292             if (res == Tuner.RESULT_SUCCESS) {
293                 mSource = source;
294             }
295             return res;
296         }
297     }
298 
299     /**
300      * Starts filtering data.
301      *
302      * <p>Does nothing if the filter is already started.
303      *
304      * @return result status of the operation.
305      */
306     @Result
start()307     public int start() {
308         synchronized (mLock) {
309             TunerUtils.checkResourceState(TAG, mIsClosed);
310             return nativeStartFilter();
311         }
312     }
313 
314 
315     /**
316      * Stops filtering data.
317      *
318      * <p>Does nothing if the filter is stopped or not started.
319      *
320      * @return result status of the operation.
321      */
322     @Result
stop()323     public int stop() {
324         synchronized (mLock) {
325             TunerUtils.checkResourceState(TAG, mIsClosed);
326             return nativeStopFilter();
327         }
328     }
329 
330     /**
331      * Flushes the filter.
332      *
333      * <p>The data which is already produced by filter but not consumed yet will
334      * be cleared.
335      *
336      * @return result status of the operation.
337      */
338     @Result
flush()339     public int flush() {
340         synchronized (mLock) {
341             TunerUtils.checkResourceState(TAG, mIsClosed);
342             return nativeFlushFilter();
343         }
344     }
345 
346     /**
347      * Copies filtered data from filter output to the given byte array.
348      *
349      * @param buffer the buffer to store the filtered data.
350      * @param offset the index of the first byte in {@code buffer} to write.
351      * @param size the maximum number of bytes to read.
352      * @return the number of bytes read.
353      */
read(@onNull byte[] buffer, @BytesLong long offset, @BytesLong long size)354     public int read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) {
355         synchronized (mLock) {
356             TunerUtils.checkResourceState(TAG, mIsClosed);
357             size = Math.min(size, buffer.length - offset);
358             return nativeRead(buffer, offset, size);
359         }
360     }
361 
362     /**
363      * Stops filtering data and releases the Filter instance.
364      */
365     @Override
close()366     public void close() {
367         synchronized (mLock) {
368             if (mIsClosed) {
369                 return;
370             }
371             int res = nativeClose();
372             if (res != Tuner.RESULT_SUCCESS) {
373                 TunerUtils.throwExceptionForResult(res, "Failed to close filter.");
374             } else {
375                 mIsClosed = true;
376             }
377         }
378     }
379 }
380