• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import android.media.tv.tuner.TunerVersionChecker;
29 
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 import java.util.concurrent.Executor;
33 
34 /**
35  * Tuner data filter.
36  *
37  * <p>This class is used to filter wanted data according to the filter's configuration.
38  *
39  * @hide
40  */
41 @SystemApi
42 public class Filter implements AutoCloseable {
43     /** @hide */
44     @IntDef(prefix = "TYPE_",
45             value = {TYPE_TS, TYPE_MMTP, TYPE_IP, TYPE_TLV, TYPE_ALP})
46     @Retention(RetentionPolicy.SOURCE)
47     public @interface Type {}
48 
49     /**
50      * Undefined filter type.
51      */
52     public static final int TYPE_UNDEFINED = 0;
53     /**
54      * TS filter type.
55      */
56     public static final int TYPE_TS = Constants.DemuxFilterMainType.TS;
57     /**
58      * MMTP filter type.
59      */
60     public static final int TYPE_MMTP = Constants.DemuxFilterMainType.MMTP;
61     /**
62      * IP filter type.
63      */
64     public static final int TYPE_IP = Constants.DemuxFilterMainType.IP;
65     /**
66      * TLV filter type.
67      */
68     public static final int TYPE_TLV = Constants.DemuxFilterMainType.TLV;
69     /**
70      * ALP filter type.
71      */
72     public static final int TYPE_ALP = Constants.DemuxFilterMainType.ALP;
73 
74     /** @hide */
75     @IntDef(prefix = "SUBTYPE_",
76             value = {SUBTYPE_UNDEFINED, SUBTYPE_SECTION, SUBTYPE_PES, SUBTYPE_AUDIO, SUBTYPE_VIDEO,
77                     SUBTYPE_DOWNLOAD, SUBTYPE_RECORD, SUBTYPE_TS, SUBTYPE_PCR, SUBTYPE_TEMI,
78                     SUBTYPE_MMTP, SUBTYPE_NTP, SUBTYPE_IP_PAYLOAD, SUBTYPE_IP,
79                     SUBTYPE_PAYLOAD_THROUGH, SUBTYPE_TLV, SUBTYPE_PTP, })
80     @Retention(RetentionPolicy.SOURCE)
81     public @interface Subtype {}
82     /**
83      * Filter subtype undefined.
84      */
85     public static final int SUBTYPE_UNDEFINED = 0;
86     /**
87      * Section filter subtype.
88      */
89     public static final int SUBTYPE_SECTION = 1;
90     /**
91      * PES filter subtype.
92      */
93     public static final int SUBTYPE_PES = 2;
94     /**
95      * Audio filter subtype.
96      */
97     public static final int SUBTYPE_AUDIO = 3;
98     /**
99      * Video filter subtype.
100      */
101     public static final int SUBTYPE_VIDEO = 4;
102     /**
103      * Download filter subtype.
104      */
105     public static final int SUBTYPE_DOWNLOAD = 5;
106     /**
107      * Record filter subtype.
108      */
109     public static final int SUBTYPE_RECORD = 6;
110     /**
111      * TS filter subtype.
112      */
113     public static final int SUBTYPE_TS = 7;
114     /**
115      * PCR filter subtype.
116      */
117     public static final int SUBTYPE_PCR = 8;
118     /**
119      * TEMI filter subtype.
120      */
121     public static final int SUBTYPE_TEMI = 9;
122     /**
123      * MMTP filter subtype.
124      */
125     public static final int SUBTYPE_MMTP = 10;
126     /**
127      * NTP filter subtype.
128      */
129     public static final int SUBTYPE_NTP = 11;
130     /**
131      * Payload filter subtype.
132      */
133     public static final int SUBTYPE_IP_PAYLOAD = 12;
134     /**
135      * IP filter subtype.
136      */
137     public static final int SUBTYPE_IP = 13;
138     /**
139      * Payload through filter subtype.
140      */
141     public static final int SUBTYPE_PAYLOAD_THROUGH = 14;
142     /**
143      * TLV filter subtype.
144      */
145     public static final int SUBTYPE_TLV = 15;
146     /**
147      * PTP filter subtype.
148      */
149     public static final int SUBTYPE_PTP = 16;
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     /** @hide */
184     @IntDef(flag = true,
185             prefix = "SCRAMBLING_STATUS_",
186             value = {SCRAMBLING_STATUS_UNKNOWN, SCRAMBLING_STATUS_NOT_SCRAMBLED,
187                     SCRAMBLING_STATUS_SCRAMBLED})
188     @Retention(RetentionPolicy.SOURCE)
189     public @interface ScramblingStatus {}
190 
191     /**
192      * Content’s scrambling status is unknown
193      */
194     public static final int SCRAMBLING_STATUS_UNKNOWN =
195             android.hardware.tv.tuner.V1_1.Constants.ScramblingStatus.UNKNOWN;
196     /**
197      * Content is not scrambled.
198      */
199     public static final int SCRAMBLING_STATUS_NOT_SCRAMBLED =
200             android.hardware.tv.tuner.V1_1.Constants.ScramblingStatus.NOT_SCRAMBLED;
201     /**
202      * Content is scrambled.
203      */
204     public static final int SCRAMBLING_STATUS_SCRAMBLED =
205             android.hardware.tv.tuner.V1_1.Constants.ScramblingStatus.SCRAMBLED;
206 
207     /** @hide */
208     @IntDef(flag = true,
209             prefix = "MONITOR_EVENT_",
210             value = {MONITOR_EVENT_SCRAMBLING_STATUS, MONITOR_EVENT_IP_CID_CHANGE})
211     @Retention(RetentionPolicy.SOURCE)
212     public @interface MonitorEventMask {}
213 
214     /**
215      * Monitor scrambling status change.
216      */
217     public static final int MONITOR_EVENT_SCRAMBLING_STATUS =
218             android.hardware.tv.tuner.V1_1.Constants.DemuxFilterMonitorEventType.SCRAMBLING_STATUS;
219     /**
220      * Monitor ip cid change.
221      */
222     public static final int MONITOR_EVENT_IP_CID_CHANGE =
223             android.hardware.tv.tuner.V1_1.Constants.DemuxFilterMonitorEventType.IP_CID_CHANGE;
224 
225     private static final String TAG = "Filter";
226 
227     private long mNativeContext;
228     private FilterCallback mCallback;
229     private Executor mExecutor;
230     private final Object mCallbackLock = new Object();
231     private final long mId;
232     private int mMainType;
233     private int mSubtype;
234     private Filter mSource;
235     private boolean mStarted;
236     private boolean mIsClosed = false;
237     private final Object mLock = new Object();
238 
nativeConfigureFilter( int type, int subType, FilterConfiguration settings)239     private native int nativeConfigureFilter(
240             int type, int subType, FilterConfiguration settings);
nativeGetId()241     private native int nativeGetId();
nativeGetId64Bit()242     private native long nativeGetId64Bit();
nativeConfigureMonitorEvent(int monitorEventMask)243     private native int nativeConfigureMonitorEvent(int monitorEventMask);
nativeSetDataSource(Filter source)244     private native int nativeSetDataSource(Filter source);
nativeStartFilter()245     private native int nativeStartFilter();
nativeStopFilter()246     private native int nativeStopFilter();
nativeFlushFilter()247     private native int nativeFlushFilter();
nativeRead(byte[] buffer, long offset, long size)248     private native int nativeRead(byte[] buffer, long offset, long size);
nativeClose()249     private native int nativeClose();
250 
251     // Called by JNI
Filter(long id)252     private Filter(long id) {
253         mId = id;
254     }
255 
onFilterStatus(int status)256     private void onFilterStatus(int status) {
257         synchronized (mCallbackLock) {
258             if (mCallback != null && mExecutor != null) {
259                 mExecutor.execute(() -> mCallback.onFilterStatusChanged(this, status));
260             }
261         }
262     }
263 
onFilterEvent(FilterEvent[] events)264     private void onFilterEvent(FilterEvent[] events) {
265         synchronized (mCallbackLock) {
266             if (mCallback != null && mExecutor != null) {
267                 mExecutor.execute(() -> mCallback.onFilterEvent(this, events));
268             }
269         }
270     }
271 
272     /** @hide */
setType(@ype int mainType, @Subtype int subtype)273     public void setType(@Type int mainType, @Subtype int subtype) {
274         mMainType = mainType;
275         mSubtype = TunerUtils.getFilterSubtype(mainType, subtype);
276     }
277 
278     /** @hide */
setCallback(FilterCallback cb, Executor executor)279     public void setCallback(FilterCallback cb, Executor executor) {
280         synchronized (mCallbackLock) {
281             mCallback = cb;
282             mExecutor = executor;
283         }
284     }
285 
286     /** @hide */
getCallback()287     public FilterCallback getCallback() {
288         synchronized (mCallbackLock) {
289             return mCallback;
290         }
291     }
292 
293     /**
294      * Configures the filter.
295      *
296      * <p>Recofiguring must happen after stopping the filter.
297      *
298      * <p>When stopping, reconfiguring and restarting the filter, the client should discard all
299      * coming events until it receives {@link RestartEvent} through {@link FilterCallback} to avoid
300      * using the events from the previous configuration.
301      *
302      * @param config the configuration of the filter.
303      * @return result status of the operation.
304      */
305     @Result
configure(@onNull FilterConfiguration config)306     public int configure(@NonNull FilterConfiguration config) {
307         synchronized (mLock) {
308             TunerUtils.checkResourceState(TAG, mIsClosed);
309             Settings s = config.getSettings();
310             int subType = (s == null) ? mSubtype : s.getType();
311             if (mMainType != config.getType() || mSubtype != subType) {
312                 throw new IllegalArgumentException("Invalid filter config. filter main type="
313                         + mMainType + ", filter subtype=" + mSubtype + ". config main type="
314                         + config.getType() + ", config subtype=" + subType);
315             }
316             return nativeConfigureFilter(config.getType(), subType, config);
317         }
318     }
319 
320     /**
321      * Gets the filter Id in 32-bit. For any Tuner SoC that supports 64-bit filter architecture,
322      * use {@link #getIdLong()}.
323      */
getId()324     public int getId() {
325         synchronized (mLock) {
326             TunerUtils.checkResourceState(TAG, mIsClosed);
327             return nativeGetId();
328         }
329     }
330 
331     /**
332      * Gets the 64-bit filter Id. For any Tuner SoC that supports 32-bit filter architecture,
333      * use {@link #getId()}.
334      */
getIdLong()335     public long getIdLong() {
336         synchronized (mLock) {
337             TunerUtils.checkResourceState(TAG, mIsClosed);
338             return nativeGetId64Bit();
339         }
340     }
341 
342     /**
343      * Configure the Filter to monitor scrambling status and ip cid change. Set corresponding bit
344      * to monitor the change. Reset to stop monitoring.
345      *
346      * <p>{@link ScramblingStatusEvent} should be sent at the following two scenarios:
347      * <ul>
348      *   <li>When this method is called with {@link #MONITOR_EVENT_SCRAMBLING_STATUS}, the first
349      *       detected scrambling status should be sent.
350      *   <li>When the Scrambling status transits into different status, event should be sent.
351      *     <ul/>
352      *
353      * <p>{@link IpCidChangeEvent} should be sent at the following two scenarios:
354      * <ul>
355      *   <li>When this method is called with {@link #MONITOR_EVENT_IP_CID_CHANGE}, the first
356      *       detected CID for the IP should be sent.
357      *   <li>When the CID is changed to different value for the IP filter, event should be sent.
358      *     <ul/>
359      *
360      * <p>This configuration is only supported in Tuner 1.1 or higher version. Unsupported version
361      * will cause no-op. Use {@link TunerVersionChecker#getTunerVersion()} to get the version
362      * information.
363      *
364      * @param monitorEventMask Types of event to be monitored. Set corresponding bit to
365      *                         monitor it. Reset to stop monitoring.
366      * @return result status of the operation.
367      */
368     @Result
setMonitorEventMask(@onitorEventMask int monitorEventMask)369     public int setMonitorEventMask(@MonitorEventMask int monitorEventMask) {
370         synchronized (mLock) {
371             TunerUtils.checkResourceState(TAG, mIsClosed);
372             if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
373                     TunerVersionChecker.TUNER_VERSION_1_1, "setMonitorEventMask")) {
374                 return Tuner.RESULT_UNAVAILABLE;
375             }
376             return nativeConfigureMonitorEvent(monitorEventMask);
377         }
378     }
379 
380     /**
381      * Sets the filter's data source.
382      *
383      * A filter uses demux as data source by default. If the data was packetized
384      * by multiple protocols, multiple filters may need to work together to
385      * extract all protocols' header. Then a filter's data source can be output
386      * from another filter.
387      *
388      * @param source the filter instance which provides data input. Switch to
389      * use demux as data source if the filter instance is NULL.
390      * @return result status of the operation.
391      * @throws IllegalStateException if the data source has been set.
392      */
393     @Result
setDataSource(@ullable Filter source)394     public int setDataSource(@Nullable Filter source) {
395         synchronized (mLock) {
396             TunerUtils.checkResourceState(TAG, mIsClosed);
397             if (mSource != null) {
398                 throw new IllegalStateException("Data source is existing");
399             }
400             int res = nativeSetDataSource(source);
401             if (res == Tuner.RESULT_SUCCESS) {
402                 mSource = source;
403             }
404             return res;
405         }
406     }
407 
408     /**
409      * Starts filtering data.
410      *
411      * <p>Does nothing if the filter is already started.
412      *
413      * <p>When stopping, reconfiguring and restarting the filter, the client should discard all
414      * coming events until it receives {@link RestartEvent} through {@link FilterCallback} to avoid
415      * using the events from the previous configuration.
416      *
417      * @return result status of the operation.
418      */
419     @Result
start()420     public int start() {
421         synchronized (mLock) {
422             TunerUtils.checkResourceState(TAG, mIsClosed);
423             return nativeStartFilter();
424         }
425     }
426 
427 
428     /**
429      * Stops filtering data.
430      *
431      * <p>Does nothing if the filter is stopped or not started.
432      *
433      * <p>Filter must be stopped to reconfigure.
434      *
435      * <p>When stopping, reconfiguring and restarting the filter, the client should discard all
436      * coming events until it receives {@link RestartEvent} through {@link FilterCallback} to avoid
437      * using the events from the previous configuration.
438      *
439      * @return result status of the operation.
440      */
441     @Result
stop()442     public int stop() {
443         synchronized (mLock) {
444             TunerUtils.checkResourceState(TAG, mIsClosed);
445             return nativeStopFilter();
446         }
447     }
448 
449     /**
450      * Flushes the filter.
451      *
452      * <p>The data which is already produced by filter but not consumed yet will
453      * be cleared.
454      *
455      * @return result status of the operation.
456      */
457     @Result
flush()458     public int flush() {
459         synchronized (mLock) {
460             TunerUtils.checkResourceState(TAG, mIsClosed);
461             return nativeFlushFilter();
462         }
463     }
464 
465     /**
466      * Copies filtered data from filter output to the given byte array.
467      *
468      * @param buffer the buffer to store the filtered data.
469      * @param offset the index of the first byte in {@code buffer} to write.
470      * @param size the maximum number of bytes to read.
471      * @return the number of bytes read.
472      */
read(@onNull byte[] buffer, @BytesLong long offset, @BytesLong long size)473     public int read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) {
474         synchronized (mLock) {
475             TunerUtils.checkResourceState(TAG, mIsClosed);
476             size = Math.min(size, buffer.length - offset);
477             return nativeRead(buffer, offset, size);
478         }
479     }
480 
481     /**
482      * Stops filtering data and releases the Filter instance.
483      */
484     @Override
close()485     public void close() {
486         synchronized (mLock) {
487             if (mIsClosed) {
488                 return;
489             }
490             int res = nativeClose();
491             if (res != Tuner.RESULT_SUCCESS) {
492                 TunerUtils.throwExceptionForResult(res, "Failed to close filter.");
493             } else {
494                 mIsClosed = true;
495             }
496         }
497     }
498 }
499