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