Loading media/java/android/media/tv/tuner/Descrambler.java +28 −5 Original line number Original line Diff line number Diff line Loading @@ -52,8 +52,12 @@ public class Descrambler implements AutoCloseable { */ */ public static final int PID_TYPE_MMTP = 2; public static final int PID_TYPE_MMTP = 2; private static final String TAG = "Descrambler"; private long mNativeContext; private long mNativeContext; private boolean mIsClosed = false; private final Object mLock = new Object(); private native int nativeAddPid(int pidType, int pid, Filter filter); private native int nativeAddPid(int pidType, int pid, Filter filter); private native int nativeRemovePid(int pidType, int pid, Filter filter); private native int nativeRemovePid(int pidType, int pid, Filter filter); Loading @@ -80,8 +84,11 @@ public class Descrambler implements AutoCloseable { */ */ @Result @Result public int addPid(@PidType int pidType, int pid, @Nullable Filter filter) { public int addPid(@PidType int pidType, int pid, @Nullable Filter filter) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeAddPid(pidType, pid, filter); return nativeAddPid(pidType, pid, filter); } } } /** /** * Remove packets' PID from the descrambler * Remove packets' PID from the descrambler Loading @@ -95,8 +102,11 @@ public class Descrambler implements AutoCloseable { */ */ @Result @Result public int removePid(@PidType int pidType, int pid, @Nullable Filter filter) { public int removePid(@PidType int pidType, int pid, @Nullable Filter filter) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeRemovePid(pidType, pid, filter); return nativeRemovePid(pidType, pid, filter); } } } /** /** * Set a key token to link descrambler to a key slot * Set a key token to link descrambler to a key slot Loading @@ -109,16 +119,29 @@ public class Descrambler implements AutoCloseable { */ */ @Result @Result public int setKeyToken(@NonNull byte[] keyToken) { public int setKeyToken(@NonNull byte[] keyToken) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); Objects.requireNonNull(keyToken, "key token must not be null"); Objects.requireNonNull(keyToken, "key token must not be null"); return nativeSetKeyToken(keyToken); return nativeSetKeyToken(keyToken); } } } /** /** * Release the descrambler instance. * Release the descrambler instance. */ */ @Override @Override public void close() { public void close() { nativeClose(); synchronized (mLock) { if (mIsClosed) { return; } int res = nativeClose(); if (res != Tuner.RESULT_SUCCESS) { TunerUtils.throwExceptionForResult(res, "Failed to close descrambler"); } else { mIsClosed = true; } } } } } } media/java/android/media/tv/tuner/Lnb.java +41 −8 Original line number Original line Diff line number Diff line Loading @@ -143,9 +143,12 @@ public class Lnb implements AutoCloseable { */ */ public static final int EVENT_TYPE_LNB_OVERLOAD = Constants.LnbEventType.LNB_OVERLOAD; public static final int EVENT_TYPE_LNB_OVERLOAD = Constants.LnbEventType.LNB_OVERLOAD; private static final String TAG = "Lnb"; int mId; int mId; LnbCallback mCallback; LnbCallback mCallback; Executor mExecutor; Executor mExecutor; Tuner mTuner; private native int nativeSetVoltage(int voltage); private native int nativeSetVoltage(int voltage); Loading @@ -156,13 +159,17 @@ public class Lnb implements AutoCloseable { private long mNativeContext; private long mNativeContext; private Boolean mIsClosed = false; private final Object mLock = new Object(); private Lnb(int id) { private Lnb(int id) { mId = id; mId = id; } } void setCallback(Executor executor, @Nullable LnbCallback callback) { void setCallback(Executor executor, @Nullable LnbCallback callback, Tuner tuner) { mCallback = callback; mCallback = callback; mExecutor = executor; mExecutor = executor; mTuner = tuner; } } private void onEvent(int eventType) { private void onEvent(int eventType) { Loading @@ -177,6 +184,12 @@ public class Lnb implements AutoCloseable { } } } } /* package */ boolean isClosed() { synchronized (mLock) { return mIsClosed; } } /** /** * Sets the LNB's power voltage. * Sets the LNB's power voltage. * * Loading @@ -185,8 +198,11 @@ public class Lnb implements AutoCloseable { */ */ @Result @Result public int setVoltage(@Voltage int voltage) { public int setVoltage(@Voltage int voltage) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeSetVoltage(voltage); return nativeSetVoltage(voltage); } } } /** /** * Sets the LNB's tone mode. * Sets the LNB's tone mode. Loading @@ -196,8 +212,11 @@ public class Lnb implements AutoCloseable { */ */ @Result @Result public int setTone(@Tone int tone) { public int setTone(@Tone int tone) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeSetTone(tone); return nativeSetTone(tone); } } } /** /** * Selects the LNB's position. * Selects the LNB's position. Loading @@ -207,8 +226,11 @@ public class Lnb implements AutoCloseable { */ */ @Result @Result public int setSatellitePosition(@Position int position) { public int setSatellitePosition(@Position int position) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeSetSatellitePosition(position); return nativeSetSatellitePosition(position); } } } /** /** * Sends DiSEqC (Digital Satellite Equipment Control) message. * Sends DiSEqC (Digital Satellite Equipment Control) message. Loading @@ -222,16 +244,27 @@ public class Lnb implements AutoCloseable { */ */ @Result @Result public int sendDiseqcMessage(@NonNull byte[] message) { public int sendDiseqcMessage(@NonNull byte[] message) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeSendDiseqcMessage(message); return nativeSendDiseqcMessage(message); } } } /** /** * Releases the LNB instance. * Releases the LNB instance. */ */ public void close() { public void close() { synchronized (mLock) { if (mIsClosed) { return; } int res = nativeClose(); int res = nativeClose(); if (res != Tuner.RESULT_SUCCESS) { if (res != Tuner.RESULT_SUCCESS) { TunerUtils.throwExceptionForResult(res, "Failed to close LNB"); TunerUtils.throwExceptionForResult(res, "Failed to close LNB"); } else { mIsClosed = true; mTuner.releaseLnb(); } } } } } } } media/java/android/media/tv/tuner/Tuner.java +53 −24 Original line number Original line Diff line number Diff line Loading @@ -57,7 +57,10 @@ import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.Executor; Loading Loading @@ -222,8 +225,8 @@ public class Tuner implements AutoCloseable { private Executor mOnResourceLostListenerExecutor; private Executor mOnResourceLostListenerExecutor; private Integer mDemuxHandle; private Integer mDemuxHandle; private Integer mDescramblerHandle; private Map<Integer, Descrambler> mDescramblers = new HashMap<>(); private Descrambler mDescrambler; private List<Filter> mFilters = new ArrayList<>(); private final TunerResourceManager.ResourcesReclaimListener mResourceListener = private final TunerResourceManager.ResourcesReclaimListener mResourceListener = new TunerResourceManager.ResourcesReclaimListener() { new TunerResourceManager.ResourcesReclaimListener() { Loading Loading @@ -356,9 +359,20 @@ public class Tuner implements AutoCloseable { mFrontend = null; mFrontend = null; } } if (mLnb != null) { if (mLnb != null) { mTunerResourceManager.releaseLnb(mLnbHandle, mClientId); releaseLnb(); mLnb = null; } mLnbHandle = null; if (!mDescramblers.isEmpty()) { for (Map.Entry<Integer, Descrambler> d : mDescramblers.entrySet()) { d.getValue().close(); mTunerResourceManager.releaseDescrambler(d.getKey(), mClientId); } mDescramblers.clear(); } if (!mFilters.isEmpty()) { for (Filter f : mFilters) { f.close(); } mFilters.clear(); } } TunerUtils.throwExceptionForResult(nativeClose(), "failed to close tuner"); TunerUtils.throwExceptionForResult(nativeClose(), "failed to close tuner"); } } Loading Loading @@ -857,6 +871,7 @@ public class Tuner implements AutoCloseable { if (mHandler == null) { if (mHandler == null) { mHandler = createEventHandler(); mHandler = createEventHandler(); } } mFilters.add(filter); } } return filter; return filter; } } Loading @@ -875,9 +890,11 @@ public class Tuner implements AutoCloseable { public Lnb openLnb(@CallbackExecutor @NonNull Executor executor, @NonNull LnbCallback cb) { public Lnb openLnb(@CallbackExecutor @NonNull Executor executor, @NonNull LnbCallback cb) { Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(cb, "LnbCallback must not be null"); Objects.requireNonNull(cb, "LnbCallback must not be null"); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB); if (mLnb != null) { if (mLnb != null) { mLnb.setCallback(executor, cb); return mLnb; } if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB) && mLnb != null) { mLnb.setCallback(executor, cb, this); } } return mLnb; return mLnb; } } Loading @@ -897,9 +914,14 @@ public class Tuner implements AutoCloseable { Objects.requireNonNull(name, "LNB name must not be null"); Objects.requireNonNull(name, "LNB name must not be null"); Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(cb, "LnbCallback must not be null"); Objects.requireNonNull(cb, "LnbCallback must not be null"); mLnb = nativeOpenLnbByName(name); Lnb newLnb = nativeOpenLnbByName(name); if (newLnb != null) { if (mLnb != null) { if (mLnb != null) { mLnb.setCallback(executor, cb); mLnb.close(); mLnbHandle = null; } mLnb = newLnb; mLnb.setCallback(executor, cb, this); } } return mLnb; return mLnb; } } Loading Loading @@ -934,8 +956,7 @@ public class Tuner implements AutoCloseable { @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) @Nullable @Nullable public Descrambler openDescrambler() { public Descrambler openDescrambler() { checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DESCRAMBLER); return requestDescrambler(); return mDescrambler; } } /** /** Loading Loading @@ -995,15 +1016,21 @@ public class Tuner implements AutoCloseable { return granted; return granted; } } private boolean requestDescrambler() { private Descrambler requestDescrambler() { int[] descramblerHandle = new int[1]; int[] descramblerHandle = new int[1]; TunerDescramblerRequest request = new TunerDescramblerRequest(mClientId); TunerDescramblerRequest request = new TunerDescramblerRequest(mClientId); boolean granted = mTunerResourceManager.requestDescrambler(request, descramblerHandle); boolean granted = mTunerResourceManager.requestDescrambler(request, descramblerHandle); if (granted) { if (!granted) { mDescramblerHandle = descramblerHandle[0]; return null; mDescrambler = nativeOpenDescramblerByHandle(mDescramblerHandle); } } return granted; int handle = descramblerHandle[0]; Descrambler descrambler = nativeOpenDescramblerByHandle(handle); if (descrambler != null) { mDescramblers.put(handle, descrambler); } else { mTunerResourceManager.releaseDescrambler(handle, mClientId); } return descrambler; } } private boolean checkResource(int resourceType) { private boolean checkResource(int resourceType) { Loading @@ -1015,7 +1042,7 @@ public class Tuner implements AutoCloseable { break; break; } } case TunerResourceManager.TUNER_RESOURCE_TYPE_LNB: { case TunerResourceManager.TUNER_RESOURCE_TYPE_LNB: { if (mLnbHandle == null && !requestLnb()) { if (mLnb == null && !requestLnb()) { return false; return false; } } break; break; Loading @@ -1026,13 +1053,15 @@ public class Tuner implements AutoCloseable { } } break; break; } } case TunerResourceManager.TUNER_RESOURCE_TYPE_DESCRAMBLER: { default: if (mDescramblerHandle == null && !requestDescrambler()) { return false; return false; } } break; } } return true; return true; } } /* package */ void releaseLnb() { mTunerResourceManager.releaseLnb(mLnbHandle, mClientId); mLnbHandle = null; mLnb = null; } } } media/java/android/media/tv/tuner/TunerUtils.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -157,5 +157,16 @@ public final class TunerUtils { throw new RuntimeException("Unexpected result " + r + ". " + msg); throw new RuntimeException("Unexpected result " + r + ". " + msg); } } /** * Checks the state of a resource instance. * * @throws IllegalStateException if the resource has already been closed. */ public static void checkResourceState(String name, boolean closed) { if (closed) { throw new IllegalStateException(name + " has been closed"); } } private TunerUtils() {} private TunerUtils() {} } } media/java/android/media/tv/tuner/filter/Filter.java +55 −23 Original line number Original line Diff line number Diff line Loading @@ -180,6 +180,8 @@ public class Filter implements AutoCloseable { */ */ public static final int STATUS_OVERFLOW = Constants.DemuxFilterStatus.OVERFLOW; public static final int STATUS_OVERFLOW = Constants.DemuxFilterStatus.OVERFLOW; private static final String TAG = "Filter"; private long mNativeContext; private long mNativeContext; private FilterCallback mCallback; private FilterCallback mCallback; private Executor mExecutor; private Executor mExecutor; Loading @@ -188,6 +190,8 @@ public class Filter implements AutoCloseable { private int mSubtype; private int mSubtype; private Filter mSource; private Filter mSource; private boolean mStarted; private boolean mStarted; private boolean mIsClosed = false; private final Object mLock = new Object(); private native int nativeConfigureFilter( private native int nativeConfigureFilter( int type, int subType, FilterConfiguration settings); int type, int subType, FilterConfiguration settings); Loading Loading @@ -244,6 +248,8 @@ public class Filter implements AutoCloseable { */ */ @Result @Result public int configure(@NonNull FilterConfiguration config) { public int configure(@NonNull FilterConfiguration config) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); Settings s = config.getSettings(); Settings s = config.getSettings(); int subType = (s == null) ? mSubtype : s.getType(); int subType = (s == null) ? mSubtype : s.getType(); if (mMainType != config.getType() || mSubtype != subType) { if (mMainType != config.getType() || mSubtype != subType) { Loading @@ -253,13 +259,17 @@ public class Filter implements AutoCloseable { } } return nativeConfigureFilter(config.getType(), subType, config); return nativeConfigureFilter(config.getType(), subType, config); } } } /** /** * Gets the filter Id. * Gets the filter Id. */ */ public int getId() { public int getId() { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeGetId(); return nativeGetId(); } } } /** /** * Sets the filter's data source. * Sets the filter's data source. Loading @@ -276,6 +286,8 @@ public class Filter implements AutoCloseable { */ */ @Result @Result public int setDataSource(@Nullable Filter source) { public int setDataSource(@Nullable Filter source) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); if (mSource != null) { if (mSource != null) { throw new IllegalStateException("Data source is existing"); throw new IllegalStateException("Data source is existing"); } } Loading @@ -285,6 +297,7 @@ public class Filter implements AutoCloseable { } } return res; return res; } } } /** /** * Starts filtering data. * Starts filtering data. Loading @@ -295,8 +308,11 @@ public class Filter implements AutoCloseable { */ */ @Result @Result public int start() { public int start() { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeStartFilter(); return nativeStartFilter(); } } } /** /** Loading @@ -308,8 +324,11 @@ public class Filter implements AutoCloseable { */ */ @Result @Result public int stop() { public int stop() { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeStopFilter(); return nativeStopFilter(); } } } /** /** * Flushes the filter. * Flushes the filter. Loading @@ -321,8 +340,11 @@ public class Filter implements AutoCloseable { */ */ @Result @Result public int flush() { public int flush() { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeFlushFilter(); return nativeFlushFilter(); } } } /** /** * Copies filtered data from filter output to the given byte array. * Copies filtered data from filter output to the given byte array. Loading @@ -333,18 +355,28 @@ public class Filter implements AutoCloseable { * @return the number of bytes read. * @return the number of bytes read. */ */ public int read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) { public int read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); size = Math.min(size, buffer.length - offset); size = Math.min(size, buffer.length - offset); return nativeRead(buffer, offset, size); return nativeRead(buffer, offset, size); } } } /** /** * Stops filtering data and releases the Filter instance. * Stops filtering data and releases the Filter instance. */ */ @Override @Override public void close() { public void close() { synchronized (mLock) { if (mIsClosed) { return; } int res = nativeClose(); int res = nativeClose(); if (res != Tuner.RESULT_SUCCESS) { if (res != Tuner.RESULT_SUCCESS) { TunerUtils.throwExceptionForResult(res, "Failed to close filter."); TunerUtils.throwExceptionForResult(res, "Failed to close filter."); } else { mIsClosed = true; } } } } } } } Loading
media/java/android/media/tv/tuner/Descrambler.java +28 −5 Original line number Original line Diff line number Diff line Loading @@ -52,8 +52,12 @@ public class Descrambler implements AutoCloseable { */ */ public static final int PID_TYPE_MMTP = 2; public static final int PID_TYPE_MMTP = 2; private static final String TAG = "Descrambler"; private long mNativeContext; private long mNativeContext; private boolean mIsClosed = false; private final Object mLock = new Object(); private native int nativeAddPid(int pidType, int pid, Filter filter); private native int nativeAddPid(int pidType, int pid, Filter filter); private native int nativeRemovePid(int pidType, int pid, Filter filter); private native int nativeRemovePid(int pidType, int pid, Filter filter); Loading @@ -80,8 +84,11 @@ public class Descrambler implements AutoCloseable { */ */ @Result @Result public int addPid(@PidType int pidType, int pid, @Nullable Filter filter) { public int addPid(@PidType int pidType, int pid, @Nullable Filter filter) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeAddPid(pidType, pid, filter); return nativeAddPid(pidType, pid, filter); } } } /** /** * Remove packets' PID from the descrambler * Remove packets' PID from the descrambler Loading @@ -95,8 +102,11 @@ public class Descrambler implements AutoCloseable { */ */ @Result @Result public int removePid(@PidType int pidType, int pid, @Nullable Filter filter) { public int removePid(@PidType int pidType, int pid, @Nullable Filter filter) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeRemovePid(pidType, pid, filter); return nativeRemovePid(pidType, pid, filter); } } } /** /** * Set a key token to link descrambler to a key slot * Set a key token to link descrambler to a key slot Loading @@ -109,16 +119,29 @@ public class Descrambler implements AutoCloseable { */ */ @Result @Result public int setKeyToken(@NonNull byte[] keyToken) { public int setKeyToken(@NonNull byte[] keyToken) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); Objects.requireNonNull(keyToken, "key token must not be null"); Objects.requireNonNull(keyToken, "key token must not be null"); return nativeSetKeyToken(keyToken); return nativeSetKeyToken(keyToken); } } } /** /** * Release the descrambler instance. * Release the descrambler instance. */ */ @Override @Override public void close() { public void close() { nativeClose(); synchronized (mLock) { if (mIsClosed) { return; } int res = nativeClose(); if (res != Tuner.RESULT_SUCCESS) { TunerUtils.throwExceptionForResult(res, "Failed to close descrambler"); } else { mIsClosed = true; } } } } } }
media/java/android/media/tv/tuner/Lnb.java +41 −8 Original line number Original line Diff line number Diff line Loading @@ -143,9 +143,12 @@ public class Lnb implements AutoCloseable { */ */ public static final int EVENT_TYPE_LNB_OVERLOAD = Constants.LnbEventType.LNB_OVERLOAD; public static final int EVENT_TYPE_LNB_OVERLOAD = Constants.LnbEventType.LNB_OVERLOAD; private static final String TAG = "Lnb"; int mId; int mId; LnbCallback mCallback; LnbCallback mCallback; Executor mExecutor; Executor mExecutor; Tuner mTuner; private native int nativeSetVoltage(int voltage); private native int nativeSetVoltage(int voltage); Loading @@ -156,13 +159,17 @@ public class Lnb implements AutoCloseable { private long mNativeContext; private long mNativeContext; private Boolean mIsClosed = false; private final Object mLock = new Object(); private Lnb(int id) { private Lnb(int id) { mId = id; mId = id; } } void setCallback(Executor executor, @Nullable LnbCallback callback) { void setCallback(Executor executor, @Nullable LnbCallback callback, Tuner tuner) { mCallback = callback; mCallback = callback; mExecutor = executor; mExecutor = executor; mTuner = tuner; } } private void onEvent(int eventType) { private void onEvent(int eventType) { Loading @@ -177,6 +184,12 @@ public class Lnb implements AutoCloseable { } } } } /* package */ boolean isClosed() { synchronized (mLock) { return mIsClosed; } } /** /** * Sets the LNB's power voltage. * Sets the LNB's power voltage. * * Loading @@ -185,8 +198,11 @@ public class Lnb implements AutoCloseable { */ */ @Result @Result public int setVoltage(@Voltage int voltage) { public int setVoltage(@Voltage int voltage) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeSetVoltage(voltage); return nativeSetVoltage(voltage); } } } /** /** * Sets the LNB's tone mode. * Sets the LNB's tone mode. Loading @@ -196,8 +212,11 @@ public class Lnb implements AutoCloseable { */ */ @Result @Result public int setTone(@Tone int tone) { public int setTone(@Tone int tone) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeSetTone(tone); return nativeSetTone(tone); } } } /** /** * Selects the LNB's position. * Selects the LNB's position. Loading @@ -207,8 +226,11 @@ public class Lnb implements AutoCloseable { */ */ @Result @Result public int setSatellitePosition(@Position int position) { public int setSatellitePosition(@Position int position) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeSetSatellitePosition(position); return nativeSetSatellitePosition(position); } } } /** /** * Sends DiSEqC (Digital Satellite Equipment Control) message. * Sends DiSEqC (Digital Satellite Equipment Control) message. Loading @@ -222,16 +244,27 @@ public class Lnb implements AutoCloseable { */ */ @Result @Result public int sendDiseqcMessage(@NonNull byte[] message) { public int sendDiseqcMessage(@NonNull byte[] message) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeSendDiseqcMessage(message); return nativeSendDiseqcMessage(message); } } } /** /** * Releases the LNB instance. * Releases the LNB instance. */ */ public void close() { public void close() { synchronized (mLock) { if (mIsClosed) { return; } int res = nativeClose(); int res = nativeClose(); if (res != Tuner.RESULT_SUCCESS) { if (res != Tuner.RESULT_SUCCESS) { TunerUtils.throwExceptionForResult(res, "Failed to close LNB"); TunerUtils.throwExceptionForResult(res, "Failed to close LNB"); } else { mIsClosed = true; mTuner.releaseLnb(); } } } } } } }
media/java/android/media/tv/tuner/Tuner.java +53 −24 Original line number Original line Diff line number Diff line Loading @@ -57,7 +57,10 @@ import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.Executor; Loading Loading @@ -222,8 +225,8 @@ public class Tuner implements AutoCloseable { private Executor mOnResourceLostListenerExecutor; private Executor mOnResourceLostListenerExecutor; private Integer mDemuxHandle; private Integer mDemuxHandle; private Integer mDescramblerHandle; private Map<Integer, Descrambler> mDescramblers = new HashMap<>(); private Descrambler mDescrambler; private List<Filter> mFilters = new ArrayList<>(); private final TunerResourceManager.ResourcesReclaimListener mResourceListener = private final TunerResourceManager.ResourcesReclaimListener mResourceListener = new TunerResourceManager.ResourcesReclaimListener() { new TunerResourceManager.ResourcesReclaimListener() { Loading Loading @@ -356,9 +359,20 @@ public class Tuner implements AutoCloseable { mFrontend = null; mFrontend = null; } } if (mLnb != null) { if (mLnb != null) { mTunerResourceManager.releaseLnb(mLnbHandle, mClientId); releaseLnb(); mLnb = null; } mLnbHandle = null; if (!mDescramblers.isEmpty()) { for (Map.Entry<Integer, Descrambler> d : mDescramblers.entrySet()) { d.getValue().close(); mTunerResourceManager.releaseDescrambler(d.getKey(), mClientId); } mDescramblers.clear(); } if (!mFilters.isEmpty()) { for (Filter f : mFilters) { f.close(); } mFilters.clear(); } } TunerUtils.throwExceptionForResult(nativeClose(), "failed to close tuner"); TunerUtils.throwExceptionForResult(nativeClose(), "failed to close tuner"); } } Loading Loading @@ -857,6 +871,7 @@ public class Tuner implements AutoCloseable { if (mHandler == null) { if (mHandler == null) { mHandler = createEventHandler(); mHandler = createEventHandler(); } } mFilters.add(filter); } } return filter; return filter; } } Loading @@ -875,9 +890,11 @@ public class Tuner implements AutoCloseable { public Lnb openLnb(@CallbackExecutor @NonNull Executor executor, @NonNull LnbCallback cb) { public Lnb openLnb(@CallbackExecutor @NonNull Executor executor, @NonNull LnbCallback cb) { Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(cb, "LnbCallback must not be null"); Objects.requireNonNull(cb, "LnbCallback must not be null"); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB); if (mLnb != null) { if (mLnb != null) { mLnb.setCallback(executor, cb); return mLnb; } if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB) && mLnb != null) { mLnb.setCallback(executor, cb, this); } } return mLnb; return mLnb; } } Loading @@ -897,9 +914,14 @@ public class Tuner implements AutoCloseable { Objects.requireNonNull(name, "LNB name must not be null"); Objects.requireNonNull(name, "LNB name must not be null"); Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(cb, "LnbCallback must not be null"); Objects.requireNonNull(cb, "LnbCallback must not be null"); mLnb = nativeOpenLnbByName(name); Lnb newLnb = nativeOpenLnbByName(name); if (newLnb != null) { if (mLnb != null) { if (mLnb != null) { mLnb.setCallback(executor, cb); mLnb.close(); mLnbHandle = null; } mLnb = newLnb; mLnb.setCallback(executor, cb, this); } } return mLnb; return mLnb; } } Loading Loading @@ -934,8 +956,7 @@ public class Tuner implements AutoCloseable { @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) @Nullable @Nullable public Descrambler openDescrambler() { public Descrambler openDescrambler() { checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DESCRAMBLER); return requestDescrambler(); return mDescrambler; } } /** /** Loading Loading @@ -995,15 +1016,21 @@ public class Tuner implements AutoCloseable { return granted; return granted; } } private boolean requestDescrambler() { private Descrambler requestDescrambler() { int[] descramblerHandle = new int[1]; int[] descramblerHandle = new int[1]; TunerDescramblerRequest request = new TunerDescramblerRequest(mClientId); TunerDescramblerRequest request = new TunerDescramblerRequest(mClientId); boolean granted = mTunerResourceManager.requestDescrambler(request, descramblerHandle); boolean granted = mTunerResourceManager.requestDescrambler(request, descramblerHandle); if (granted) { if (!granted) { mDescramblerHandle = descramblerHandle[0]; return null; mDescrambler = nativeOpenDescramblerByHandle(mDescramblerHandle); } } return granted; int handle = descramblerHandle[0]; Descrambler descrambler = nativeOpenDescramblerByHandle(handle); if (descrambler != null) { mDescramblers.put(handle, descrambler); } else { mTunerResourceManager.releaseDescrambler(handle, mClientId); } return descrambler; } } private boolean checkResource(int resourceType) { private boolean checkResource(int resourceType) { Loading @@ -1015,7 +1042,7 @@ public class Tuner implements AutoCloseable { break; break; } } case TunerResourceManager.TUNER_RESOURCE_TYPE_LNB: { case TunerResourceManager.TUNER_RESOURCE_TYPE_LNB: { if (mLnbHandle == null && !requestLnb()) { if (mLnb == null && !requestLnb()) { return false; return false; } } break; break; Loading @@ -1026,13 +1053,15 @@ public class Tuner implements AutoCloseable { } } break; break; } } case TunerResourceManager.TUNER_RESOURCE_TYPE_DESCRAMBLER: { default: if (mDescramblerHandle == null && !requestDescrambler()) { return false; return false; } } break; } } return true; return true; } } /* package */ void releaseLnb() { mTunerResourceManager.releaseLnb(mLnbHandle, mClientId); mLnbHandle = null; mLnb = null; } } }
media/java/android/media/tv/tuner/TunerUtils.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -157,5 +157,16 @@ public final class TunerUtils { throw new RuntimeException("Unexpected result " + r + ". " + msg); throw new RuntimeException("Unexpected result " + r + ". " + msg); } } /** * Checks the state of a resource instance. * * @throws IllegalStateException if the resource has already been closed. */ public static void checkResourceState(String name, boolean closed) { if (closed) { throw new IllegalStateException(name + " has been closed"); } } private TunerUtils() {} private TunerUtils() {} } }
media/java/android/media/tv/tuner/filter/Filter.java +55 −23 Original line number Original line Diff line number Diff line Loading @@ -180,6 +180,8 @@ public class Filter implements AutoCloseable { */ */ public static final int STATUS_OVERFLOW = Constants.DemuxFilterStatus.OVERFLOW; public static final int STATUS_OVERFLOW = Constants.DemuxFilterStatus.OVERFLOW; private static final String TAG = "Filter"; private long mNativeContext; private long mNativeContext; private FilterCallback mCallback; private FilterCallback mCallback; private Executor mExecutor; private Executor mExecutor; Loading @@ -188,6 +190,8 @@ public class Filter implements AutoCloseable { private int mSubtype; private int mSubtype; private Filter mSource; private Filter mSource; private boolean mStarted; private boolean mStarted; private boolean mIsClosed = false; private final Object mLock = new Object(); private native int nativeConfigureFilter( private native int nativeConfigureFilter( int type, int subType, FilterConfiguration settings); int type, int subType, FilterConfiguration settings); Loading Loading @@ -244,6 +248,8 @@ public class Filter implements AutoCloseable { */ */ @Result @Result public int configure(@NonNull FilterConfiguration config) { public int configure(@NonNull FilterConfiguration config) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); Settings s = config.getSettings(); Settings s = config.getSettings(); int subType = (s == null) ? mSubtype : s.getType(); int subType = (s == null) ? mSubtype : s.getType(); if (mMainType != config.getType() || mSubtype != subType) { if (mMainType != config.getType() || mSubtype != subType) { Loading @@ -253,13 +259,17 @@ public class Filter implements AutoCloseable { } } return nativeConfigureFilter(config.getType(), subType, config); return nativeConfigureFilter(config.getType(), subType, config); } } } /** /** * Gets the filter Id. * Gets the filter Id. */ */ public int getId() { public int getId() { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeGetId(); return nativeGetId(); } } } /** /** * Sets the filter's data source. * Sets the filter's data source. Loading @@ -276,6 +286,8 @@ public class Filter implements AutoCloseable { */ */ @Result @Result public int setDataSource(@Nullable Filter source) { public int setDataSource(@Nullable Filter source) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); if (mSource != null) { if (mSource != null) { throw new IllegalStateException("Data source is existing"); throw new IllegalStateException("Data source is existing"); } } Loading @@ -285,6 +297,7 @@ public class Filter implements AutoCloseable { } } return res; return res; } } } /** /** * Starts filtering data. * Starts filtering data. Loading @@ -295,8 +308,11 @@ public class Filter implements AutoCloseable { */ */ @Result @Result public int start() { public int start() { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeStartFilter(); return nativeStartFilter(); } } } /** /** Loading @@ -308,8 +324,11 @@ public class Filter implements AutoCloseable { */ */ @Result @Result public int stop() { public int stop() { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeStopFilter(); return nativeStopFilter(); } } } /** /** * Flushes the filter. * Flushes the filter. Loading @@ -321,8 +340,11 @@ public class Filter implements AutoCloseable { */ */ @Result @Result public int flush() { public int flush() { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); return nativeFlushFilter(); return nativeFlushFilter(); } } } /** /** * Copies filtered data from filter output to the given byte array. * Copies filtered data from filter output to the given byte array. Loading @@ -333,18 +355,28 @@ public class Filter implements AutoCloseable { * @return the number of bytes read. * @return the number of bytes read. */ */ public int read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) { public int read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) { synchronized (mLock) { TunerUtils.checkResourceState(TAG, mIsClosed); size = Math.min(size, buffer.length - offset); size = Math.min(size, buffer.length - offset); return nativeRead(buffer, offset, size); return nativeRead(buffer, offset, size); } } } /** /** * Stops filtering data and releases the Filter instance. * Stops filtering data and releases the Filter instance. */ */ @Override @Override public void close() { public void close() { synchronized (mLock) { if (mIsClosed) { return; } int res = nativeClose(); int res = nativeClose(); if (res != Tuner.RESULT_SUCCESS) { if (res != Tuner.RESULT_SUCCESS) { TunerUtils.throwExceptionForResult(res, "Failed to close filter."); TunerUtils.throwExceptionForResult(res, "Failed to close filter."); } else { mIsClosed = true; } } } } } } }