Add SharedFilter to tuner frameworks.
The SharedFilter is used to share the Filter created by TIS to another process. The TIS uses Filter.createSharedFilter() to create a token and share it to another process. The new process will use Tuner.openSharedFilter() to open that new token and create a SharedFilter. The new process will be able to read the TIS owned Filter's data with this new SharedFilter. Bug: 196124225 Test: atest android.media.tv.tuner.cts on both AIDL and HIDL HAL. Change-Id: Id93b30e4db242d35a3d1ae6023b967a90a78c448
This commit is contained in:
@@ -20,6 +20,7 @@ package android {
|
||||
field public static final String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
|
||||
field public static final String ACCESS_TUNED_INFO = "android.permission.ACCESS_TUNED_INFO";
|
||||
field public static final String ACCESS_TV_DESCRAMBLER = "android.permission.ACCESS_TV_DESCRAMBLER";
|
||||
field public static final String ACCESS_TV_SHARED_FILTER = "android.permission.ACCESS_TV_SHARED_FILTER";
|
||||
field public static final String ACCESS_TV_TUNER = "android.permission.ACCESS_TV_TUNER";
|
||||
field public static final String ACCESS_VIBRATOR_STATE = "android.permission.ACCESS_VIBRATOR_STATE";
|
||||
field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
|
||||
@@ -6125,6 +6126,7 @@ package android.media.tv.tuner {
|
||||
method @Nullable public android.media.tv.tuner.filter.Filter openFilter(int, int, long, @Nullable java.util.concurrent.Executor, @Nullable android.media.tv.tuner.filter.FilterCallback);
|
||||
method @Nullable public android.media.tv.tuner.Lnb openLnb(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.LnbCallback);
|
||||
method @Nullable public android.media.tv.tuner.Lnb openLnbByName(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.LnbCallback);
|
||||
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_SHARED_FILTER) public static android.media.tv.tuner.filter.SharedFilter openSharedFilter(@NonNull android.content.Context, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.filter.SharedFilterCallback);
|
||||
method @Nullable public android.media.tv.tuner.filter.TimeFilter openTimeFilter();
|
||||
method public int scan(@NonNull android.media.tv.tuner.frontend.FrontendSettings, int, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.ScanCallback);
|
||||
method public int setLnaEnabled(boolean);
|
||||
@@ -6333,10 +6335,12 @@ package android.media.tv.tuner.filter {
|
||||
public class Filter implements java.lang.AutoCloseable {
|
||||
method public void close();
|
||||
method public int configure(@NonNull android.media.tv.tuner.filter.FilterConfiguration);
|
||||
method @Nullable public String createSharedFilter();
|
||||
method public int flush();
|
||||
method @Deprecated public int getId();
|
||||
method public long getIdLong();
|
||||
method public int read(@NonNull byte[], long, long);
|
||||
method public void releaseSharedFilter(@NonNull String);
|
||||
method public int setDataSource(@Nullable android.media.tv.tuner.filter.Filter);
|
||||
method public int setMonitorEventMask(int);
|
||||
method public int start();
|
||||
@@ -6586,6 +6590,20 @@ package android.media.tv.tuner.filter {
|
||||
method public int getType();
|
||||
}
|
||||
|
||||
public final class SharedFilter implements java.lang.AutoCloseable {
|
||||
method public void close();
|
||||
method public int flush();
|
||||
method public int read(@NonNull byte[], long, long);
|
||||
method public int start();
|
||||
method public int stop();
|
||||
field public static final int STATUS_INACCESSIBLE = 128; // 0x80
|
||||
}
|
||||
|
||||
public interface SharedFilterCallback {
|
||||
method public void onFilterEvent(@NonNull android.media.tv.tuner.filter.SharedFilter, @NonNull android.media.tv.tuner.filter.FilterEvent[]);
|
||||
method public void onFilterStatusChanged(@NonNull android.media.tv.tuner.filter.SharedFilter, int);
|
||||
}
|
||||
|
||||
public class TemiEvent extends android.media.tv.tuner.filter.FilterEvent {
|
||||
method @NonNull public byte[] getDescriptorData();
|
||||
method public byte getDescriptorTag();
|
||||
|
||||
@@ -5802,6 +5802,12 @@
|
||||
<permission android:name="android.permission.ACCESS_TV_DESCRAMBLER"
|
||||
android:protectionLevel="signature|privileged|vendorPrivileged" />
|
||||
|
||||
<!-- @SystemApi Allows an application to access shared filter of TV tuner HAL
|
||||
<p>Not for use by third-party applications.
|
||||
@hide -->
|
||||
<permission android:name="android.permission.ACCESS_TV_SHARED_FILTER"
|
||||
android:protectionLevel="signature|privileged|vendorPrivileged" />
|
||||
|
||||
<!-- Allows an application to create trusted displays. @hide -->
|
||||
<permission android:name="android.permission.ADD_TRUSTED_DISPLAY"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
@@ -425,6 +425,7 @@ applications that come with the platform
|
||||
<permission name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"/>
|
||||
<!-- Permissions required for CTS test - TunerTest -->
|
||||
<permission name="android.permission.ACCESS_TV_DESCRAMBLER" />
|
||||
<permission name="android.permission.ACCESS_TV_SHARED_FILTER" />
|
||||
<permission name="android.permission.ACCESS_TV_TUNER" />
|
||||
<permission name="android.permission.TUNER_RESOURCE_ACCESS" />
|
||||
<!-- Permissions required for CTS test - TVInputManagerTest -->
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.annotation.RequiresPermission;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.tv.tuner.Constant;
|
||||
import android.hardware.tv.tuner.Constant64Bit;
|
||||
import android.hardware.tv.tuner.FrontendScanType;
|
||||
@@ -37,6 +38,8 @@ import android.media.tv.tuner.filter.Filter;
|
||||
import android.media.tv.tuner.filter.Filter.Subtype;
|
||||
import android.media.tv.tuner.filter.Filter.Type;
|
||||
import android.media.tv.tuner.filter.FilterCallback;
|
||||
import android.media.tv.tuner.filter.SharedFilter;
|
||||
import android.media.tv.tuner.filter.SharedFilterCallback;
|
||||
import android.media.tv.tuner.filter.TimeFilter;
|
||||
import android.media.tv.tuner.frontend.Atsc3PlpInfo;
|
||||
import android.media.tv.tuner.frontend.FrontendInfo;
|
||||
@@ -620,6 +623,7 @@ public class Tuner implements AutoCloseable {
|
||||
private native int nativeCloseFrontend(int handle);
|
||||
private native int nativeClose();
|
||||
|
||||
private static native SharedFilter nativeOpenSharedFilter(String token);
|
||||
|
||||
/**
|
||||
* Listener for resource lost.
|
||||
@@ -1570,6 +1574,37 @@ public class Tuner implements AutoCloseable {
|
||||
return dvr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a shared filter instance.
|
||||
*
|
||||
* @param context the context of the caller.
|
||||
* @param sharedFilterToken the token of the shared filter being opened.
|
||||
* @param executor the executor on which callback will be invoked.
|
||||
* @param cb the listener to receive notifications from shared filter.
|
||||
* @return the opened shared filter object. {@code null} if the operation failed.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.ACCESS_TV_SHARED_FILTER)
|
||||
@Nullable
|
||||
static public SharedFilter openSharedFilter(@NonNull Context context,
|
||||
@NonNull String sharedFilterToken, @CallbackExecutor @NonNull Executor executor,
|
||||
@NonNull SharedFilterCallback cb) {
|
||||
Objects.requireNonNull(sharedFilterToken, "sharedFilterToken must not be null");
|
||||
Objects.requireNonNull(executor, "executor must not be null");
|
||||
Objects.requireNonNull(cb, "SharedFilterCallback must not be null");
|
||||
|
||||
if (context.checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.ACCESS_TV_SHARED_FILTER)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException("Caller must have ACCESS_TV_SHAREDFILTER permission.");
|
||||
}
|
||||
|
||||
SharedFilter filter = nativeOpenSharedFilter(sharedFilterToken);
|
||||
if (filter != null) {
|
||||
filter.setCallback(cb, executor);
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
private boolean requestDemux() {
|
||||
int[] demuxHandle = new int[1];
|
||||
TunerDemuxRequest request = new TunerDemuxRequest();
|
||||
|
||||
@@ -172,5 +172,16 @@ public final class TunerUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the accessibility of a resource instance.
|
||||
*
|
||||
* @throws IllegalStateException if the resource has already been inaccessible.
|
||||
*/
|
||||
public static void checkResourceAccessible(String name, boolean accessible) {
|
||||
if (!accessible) {
|
||||
throw new IllegalStateException(name + " is inaccessible");
|
||||
}
|
||||
}
|
||||
|
||||
private TunerUtils() {}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.media.tv.tuner.Tuner;
|
||||
import android.media.tv.tuner.Tuner.Result;
|
||||
import android.media.tv.tuner.TunerUtils;
|
||||
import android.media.tv.tuner.TunerVersionChecker;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -235,6 +236,8 @@ public class Filter implements AutoCloseable {
|
||||
private Filter mSource;
|
||||
private boolean mStarted;
|
||||
private boolean mIsClosed = false;
|
||||
private boolean mIsStarted = false;
|
||||
private boolean mIsShared = false;
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private native int nativeConfigureFilter(
|
||||
@@ -248,6 +251,8 @@ public class Filter implements AutoCloseable {
|
||||
private native int nativeFlushFilter();
|
||||
private native int nativeRead(byte[] buffer, long offset, long size);
|
||||
private native int nativeClose();
|
||||
private native String nativeCreateSharedFilter();
|
||||
private native void nativeReleaseSharedFilter(String token);
|
||||
|
||||
// Called by JNI
|
||||
private Filter(long id) {
|
||||
@@ -312,6 +317,8 @@ public class Filter implements AutoCloseable {
|
||||
* coming events until it receives {@link RestartEvent} through {@link FilterCallback} to avoid
|
||||
* using the events from the previous configuration.
|
||||
*
|
||||
* <p>If this filter is shared, do nothing and just return {@link Tuner#RESULT_INVALID_STATE}.
|
||||
*
|
||||
* @param config the configuration of the filter.
|
||||
* @return result status of the operation.
|
||||
*/
|
||||
@@ -319,6 +326,9 @@ public class Filter implements AutoCloseable {
|
||||
public int configure(@NonNull FilterConfiguration config) {
|
||||
synchronized (mLock) {
|
||||
TunerUtils.checkResourceState(TAG, mIsClosed);
|
||||
if (mIsShared) {
|
||||
return Tuner.RESULT_INVALID_STATE;
|
||||
}
|
||||
Settings s = config.getSettings();
|
||||
int subType = (s == null) ? mSubtype : s.getType();
|
||||
if (mMainType != config.getType() || mSubtype != subType) {
|
||||
@@ -374,6 +384,8 @@ public class Filter implements AutoCloseable {
|
||||
* will cause no-op. Use {@link TunerVersionChecker#getTunerVersion()} to get the version
|
||||
* information.
|
||||
*
|
||||
* <p>If this filter is shared, do nothing and just return {@link Tuner#RESULT_INVALID_STATE}.
|
||||
*
|
||||
* @param monitorEventMask Types of event to be monitored. Set corresponding bit to
|
||||
* monitor it. Reset to stop monitoring.
|
||||
* @return result status of the operation.
|
||||
@@ -382,6 +394,9 @@ public class Filter implements AutoCloseable {
|
||||
public int setMonitorEventMask(@MonitorEventMask int monitorEventMask) {
|
||||
synchronized (mLock) {
|
||||
TunerUtils.checkResourceState(TAG, mIsClosed);
|
||||
if (mIsShared) {
|
||||
return Tuner.RESULT_INVALID_STATE;
|
||||
}
|
||||
if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
|
||||
TunerVersionChecker.TUNER_VERSION_1_1, "setMonitorEventMask")) {
|
||||
return Tuner.RESULT_UNAVAILABLE;
|
||||
@@ -398,6 +413,8 @@ public class Filter implements AutoCloseable {
|
||||
* extract all protocols' header. Then a filter's data source can be output
|
||||
* from another filter.
|
||||
*
|
||||
* <p>If this filter is shared, do nothing and just return {@link Tuner#RESULT_INVALID_STATE}.
|
||||
*
|
||||
* @param source the filter instance which provides data input. Switch to
|
||||
* use demux as data source if the filter instance is NULL.
|
||||
* @return result status of the operation.
|
||||
@@ -407,6 +424,9 @@ public class Filter implements AutoCloseable {
|
||||
public int setDataSource(@Nullable Filter source) {
|
||||
synchronized (mLock) {
|
||||
TunerUtils.checkResourceState(TAG, mIsClosed);
|
||||
if (mIsShared) {
|
||||
return Tuner.RESULT_INVALID_STATE;
|
||||
}
|
||||
if (mSource != null) {
|
||||
throw new IllegalStateException("Data source is existing");
|
||||
}
|
||||
@@ -427,17 +447,25 @@ public class Filter implements AutoCloseable {
|
||||
* coming events until it receives {@link RestartEvent} through {@link FilterCallback} to avoid
|
||||
* using the events from the previous configuration.
|
||||
*
|
||||
* <p>If this filter is shared, do nothing and just return {@link Tuner#RESULT_INVALID_STATE}.
|
||||
*
|
||||
* @return result status of the operation.
|
||||
*/
|
||||
@Result
|
||||
public int start() {
|
||||
synchronized (mLock) {
|
||||
TunerUtils.checkResourceState(TAG, mIsClosed);
|
||||
return nativeStartFilter();
|
||||
if (mIsShared) {
|
||||
return Tuner.RESULT_INVALID_STATE;
|
||||
}
|
||||
int res = nativeStartFilter();
|
||||
if (res == Tuner.RESULT_SUCCESS) {
|
||||
mIsStarted = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stops filtering data.
|
||||
*
|
||||
@@ -449,13 +477,22 @@ public class Filter implements AutoCloseable {
|
||||
* coming events until it receives {@link RestartEvent} through {@link FilterCallback} to avoid
|
||||
* using the events from the previous configuration.
|
||||
*
|
||||
* <p>If this filter is shared, do nothing and just return {@link Tuner#RESULT_INVALID_STATE}.
|
||||
*
|
||||
* @return result status of the operation.
|
||||
*/
|
||||
@Result
|
||||
public int stop() {
|
||||
synchronized (mLock) {
|
||||
TunerUtils.checkResourceState(TAG, mIsClosed);
|
||||
return nativeStopFilter();
|
||||
if (mIsShared) {
|
||||
return Tuner.RESULT_INVALID_STATE;
|
||||
}
|
||||
int res = nativeStopFilter();
|
||||
if (res == Tuner.RESULT_SUCCESS) {
|
||||
mIsStarted = false;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,12 +502,17 @@ public class Filter implements AutoCloseable {
|
||||
* <p>The data which is already produced by filter but not consumed yet will
|
||||
* be cleared.
|
||||
*
|
||||
* <p>If this filter is shared, do nothing and just return {@link Tuner#RESULT_INVALID_STATE}.
|
||||
*
|
||||
* @return result status of the operation.
|
||||
*/
|
||||
@Result
|
||||
public int flush() {
|
||||
synchronized (mLock) {
|
||||
TunerUtils.checkResourceState(TAG, mIsClosed);
|
||||
if (mIsShared) {
|
||||
return Tuner.RESULT_INVALID_STATE;
|
||||
}
|
||||
return nativeFlushFilter();
|
||||
}
|
||||
}
|
||||
@@ -478,6 +520,8 @@ public class Filter implements AutoCloseable {
|
||||
/**
|
||||
* Copies filtered data from filter output to the given byte array.
|
||||
*
|
||||
* <p>If this filter is shared, do nothing and just return {@link Tuner#RESULT_INVALID_STATE}.
|
||||
*
|
||||
* @param buffer the buffer to store the filtered data.
|
||||
* @param offset the index of the first byte in {@code buffer} to write.
|
||||
* @param size the maximum number of bytes to read.
|
||||
@@ -486,6 +530,9 @@ public class Filter implements AutoCloseable {
|
||||
public int read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) {
|
||||
synchronized (mLock) {
|
||||
TunerUtils.checkResourceState(TAG, mIsClosed);
|
||||
if (mIsShared) {
|
||||
return 0;
|
||||
}
|
||||
size = Math.min(size, buffer.length - offset);
|
||||
return nativeRead(buffer, offset, size);
|
||||
}
|
||||
@@ -493,6 +540,10 @@ public class Filter implements AutoCloseable {
|
||||
|
||||
/**
|
||||
* Stops filtering data and releases the Filter instance.
|
||||
*
|
||||
* <p>If this filter is shared, this filter will be closed and a
|
||||
* {@link SharedFilterCallback#STATUS_INACCESSIBLE} event will be sent to shared filter before
|
||||
* closing.
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
@@ -504,8 +555,47 @@ public class Filter implements AutoCloseable {
|
||||
if (res != Tuner.RESULT_SUCCESS) {
|
||||
TunerUtils.throwExceptionForResult(res, "Failed to close filter.");
|
||||
} else {
|
||||
mIsStarted = false;
|
||||
mIsClosed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shared filter.
|
||||
*
|
||||
* @return a string shared filter token.
|
||||
*/
|
||||
@Nullable
|
||||
public String createSharedFilter() {
|
||||
synchronized (mLock) {
|
||||
TunerUtils.checkResourceState(TAG, mIsClosed);
|
||||
if (mIsStarted || mIsShared) {
|
||||
Log.d(TAG, "Create shared filter in a wrong state, started: " +
|
||||
mIsStarted + "shared: " + mIsShared);
|
||||
return null;
|
||||
}
|
||||
String token = nativeCreateSharedFilter();
|
||||
if (token != null) {
|
||||
mIsShared = true;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases a shared filter.
|
||||
*
|
||||
* @param filterToken the token of the shared filter being released.
|
||||
*/
|
||||
public void releaseSharedFilter(@NonNull String filterToken) {
|
||||
synchronized (mLock) {
|
||||
TunerUtils.checkResourceState(TAG, mIsClosed);
|
||||
if (!mIsShared) {
|
||||
return;
|
||||
}
|
||||
nativeReleaseSharedFilter(filterToken);
|
||||
mIsShared = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
194
media/java/android/media/tv/tuner/filter/SharedFilter.java
Normal file
194
media/java/android/media/tv/tuner/filter/SharedFilter.java
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 2021 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.media.tv.tuner.filter;
|
||||
|
||||
import android.annotation.BytesLong;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.media.tv.tuner.Tuner;
|
||||
import android.media.tv.tuner.Tuner.Result;
|
||||
import android.media.tv.tuner.TunerUtils;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Tuner shared data filter.
|
||||
*
|
||||
* <p>This class is used to filter wanted data in a different process.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class SharedFilter implements AutoCloseable {
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = "STATUS_", value = {STATUS_INACCESSIBLE})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Status {}
|
||||
|
||||
/**
|
||||
* The status of a shared filter that its data becomes inaccessible.
|
||||
*/
|
||||
public static final int STATUS_INACCESSIBLE = 1 << 7;
|
||||
|
||||
private static final String TAG = "SharedFilter";
|
||||
|
||||
private long mNativeContext;
|
||||
private SharedFilterCallback mCallback;
|
||||
private Executor mExecutor;
|
||||
private final Object mCallbackLock = new Object();
|
||||
private boolean mIsClosed = false;
|
||||
private boolean mIsAccessible = true;
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private native int nativeStartSharedFilter();
|
||||
private native int nativeStopSharedFilter();
|
||||
private native int nativeFlushSharedFilter();
|
||||
private native int nativeSharedRead(byte[] buffer, long offset, long size);
|
||||
private native int nativeSharedClose();
|
||||
|
||||
// Called by JNI
|
||||
private SharedFilter() {}
|
||||
|
||||
private void onFilterStatus(int status) {
|
||||
synchronized (mLock) {
|
||||
if (status == STATUS_INACCESSIBLE) {
|
||||
mIsAccessible = false;
|
||||
}
|
||||
}
|
||||
synchronized (mCallbackLock) {
|
||||
if (mCallback != null && mExecutor != null) {
|
||||
mExecutor.execute(() -> {
|
||||
synchronized (mCallbackLock) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onFilterStatusChanged(this, status);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onFilterEvent(FilterEvent[] events) {
|
||||
synchronized (mCallbackLock) {
|
||||
if (mCallback != null && mExecutor != null) {
|
||||
mExecutor.execute(() -> {
|
||||
synchronized (mCallbackLock) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onFilterEvent(this, events);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setCallback(SharedFilterCallback cb, Executor executor) {
|
||||
synchronized (mCallbackLock) {
|
||||
mCallback = cb;
|
||||
mExecutor = executor;
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public SharedFilterCallback getCallback() {
|
||||
synchronized (mCallbackLock) { return mCallback; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts filtering data.
|
||||
*
|
||||
* <p>Does nothing if the filter is already started.
|
||||
*
|
||||
* @return result status of the operation.
|
||||
*/
|
||||
@Result
|
||||
public int start() {
|
||||
synchronized (mLock) {
|
||||
TunerUtils.checkResourceAccessible(TAG, mIsAccessible);
|
||||
TunerUtils.checkResourceState(TAG, mIsClosed);
|
||||
return nativeStartSharedFilter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops filtering data.
|
||||
*
|
||||
* <p>Does nothing if the filter is stopped or not started.
|
||||
*
|
||||
* @return result status of the operation.
|
||||
*/
|
||||
@Result
|
||||
public int stop() {
|
||||
synchronized (mLock) {
|
||||
TunerUtils.checkResourceAccessible(TAG, mIsAccessible);
|
||||
TunerUtils.checkResourceState(TAG, mIsClosed);
|
||||
return nativeStopSharedFilter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the filter.
|
||||
*
|
||||
* <p>The data which is already produced by filter but not consumed yet will
|
||||
* be cleared.
|
||||
*
|
||||
* @return result status of the operation.
|
||||
*/
|
||||
@Result
|
||||
public int flush() {
|
||||
synchronized (mLock) {
|
||||
TunerUtils.checkResourceAccessible(TAG, mIsAccessible);
|
||||
TunerUtils.checkResourceState(TAG, mIsClosed);
|
||||
return nativeFlushSharedFilter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies filtered data from filter output to the given byte array.
|
||||
*
|
||||
* @param buffer the buffer to store the filtered data.
|
||||
* @param offset the index of the first byte in {@code buffer} to write.
|
||||
* @param size the maximum number of bytes to read.
|
||||
* @return the number of bytes read.
|
||||
*/
|
||||
public int read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) {
|
||||
synchronized (mLock) {
|
||||
TunerUtils.checkResourceAccessible(TAG, mIsAccessible);
|
||||
TunerUtils.checkResourceState(TAG, mIsClosed);
|
||||
size = Math.min(size, buffer.length - offset);
|
||||
return nativeSharedRead(buffer, offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops filtering data and releases the Filter instance.
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
synchronized (mLock) {
|
||||
if (mIsClosed) {
|
||||
return;
|
||||
}
|
||||
nativeSharedClose();
|
||||
mIsClosed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2021 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.media.tv.tuner.filter;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
|
||||
/**
|
||||
* Callback interface for receiving information from the corresponding shared filters.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public interface SharedFilterCallback {
|
||||
/**
|
||||
* Invoked when there are filter events.
|
||||
*
|
||||
* @param sharedfilter the corresponding shared filter which sent the events.
|
||||
* @param events the filter events sent from the filter.
|
||||
*/
|
||||
void onFilterEvent(@NonNull SharedFilter sharedfilter,
|
||||
@SuppressLint("ArrayReturn") @NonNull FilterEvent[] events);
|
||||
/**
|
||||
* Invoked when filter status changed.
|
||||
*
|
||||
* @param sharedfilter the corresponding shared filter whose status is changed.
|
||||
* @param status the new status of the filter.
|
||||
*/
|
||||
void onFilterStatusChanged(@NonNull SharedFilter sharedfilter, @Filter.Status int status);
|
||||
}
|
||||
@@ -298,6 +298,7 @@ struct fields_t {
|
||||
jfieldID dvrRecorderContext;
|
||||
jfieldID dvrPlaybackContext;
|
||||
jfieldID mediaEventContext;
|
||||
jfieldID sharedFilterContext;
|
||||
jmethodID frontendInitID;
|
||||
jmethodID filterInitID;
|
||||
jmethodID timeFilterInitID;
|
||||
@@ -314,6 +315,9 @@ struct fields_t {
|
||||
jmethodID descramblerInitID;
|
||||
jmethodID linearBlockInitID;
|
||||
jmethodID linearBlockSetInternalStateID;
|
||||
jmethodID sharedFilterInitID;
|
||||
jmethodID onSharedFilterStatusID;
|
||||
jmethodID onSharedFilterEventID;
|
||||
};
|
||||
|
||||
static fields_t gFields;
|
||||
@@ -884,10 +888,11 @@ void FilterClientCallbackImpl::onFilterEvent(const vector<DemuxFilterEvent> &eve
|
||||
}
|
||||
jobject filter(env->NewLocalRef(mFilterObj));
|
||||
if (!env->IsSameObject(filter, nullptr)) {
|
||||
env->CallVoidMethod(
|
||||
filter,
|
||||
gFields.onFilterEventID,
|
||||
array);
|
||||
jmethodID methodID = gFields.onFilterEventID;
|
||||
if (mSharedFilter) {
|
||||
methodID = gFields.onSharedFilterEventID;
|
||||
}
|
||||
env->CallVoidMethod(filter, methodID, array);
|
||||
} else {
|
||||
ALOGE("FilterClientCallbackImpl::onFilterEvent:"
|
||||
"Filter object has been freed. Ignoring callback.");
|
||||
@@ -899,13 +904,14 @@ void FilterClientCallbackImpl::onFilterStatus(const DemuxFilterStatus status) {
|
||||
JNIEnv *env = AndroidRuntime::getJNIEnv();
|
||||
jobject filter(env->NewLocalRef(mFilterObj));
|
||||
if (!env->IsSameObject(filter, nullptr)) {
|
||||
env->CallVoidMethod(
|
||||
filter,
|
||||
gFields.onFilterStatusID,
|
||||
(jint)status);
|
||||
jmethodID methodID = gFields.onFilterStatusID;
|
||||
if (mSharedFilter) {
|
||||
methodID = gFields.onSharedFilterStatusID;
|
||||
}
|
||||
env->CallVoidMethod(filter, methodID, (jint)static_cast<uint8_t>(status));
|
||||
} else {
|
||||
ALOGE("FilterClientCallbackImpl::onFilterStatus:"
|
||||
"Filter object has been freed. Ignoring callback.");
|
||||
"Filter object has been freed. Ignoring callback.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -914,6 +920,15 @@ void FilterClientCallbackImpl::setFilter(jweak filterObj, sp<FilterClient> filte
|
||||
// Java Object
|
||||
mFilterObj = filterObj;
|
||||
mFilterClient = filterClient;
|
||||
mSharedFilter = false;
|
||||
}
|
||||
|
||||
void FilterClientCallbackImpl::setSharedFilter(jweak filterObj, sp<FilterClient> filterClient) {
|
||||
ALOGV("FilterClientCallbackImpl::setFilter");
|
||||
// Java Object
|
||||
mFilterObj = filterObj;
|
||||
mFilterClient = filterClient;
|
||||
mSharedFilter = true;
|
||||
}
|
||||
|
||||
FilterClientCallbackImpl::~FilterClientCallbackImpl() {
|
||||
@@ -2974,6 +2989,10 @@ static sp<FilterClient> getFilterClient(JNIEnv *env, jobject filter) {
|
||||
return (FilterClient *)env->GetLongField(filter, gFields.filterContext);
|
||||
}
|
||||
|
||||
static sp<FilterClient> getSharedFilterClient(JNIEnv *env, jobject filter) {
|
||||
return (FilterClient *)env->GetLongField(filter, gFields.sharedFilterContext);
|
||||
}
|
||||
|
||||
static sp<LnbClient> getLnbClient(JNIEnv *env, jobject lnb) {
|
||||
return (LnbClient *)env->GetLongField(lnb, gFields.lnbContext);
|
||||
}
|
||||
@@ -3049,6 +3068,14 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) {
|
||||
env->GetMethodID(filterClazz, "onFilterEvent",
|
||||
"([Landroid/media/tv/tuner/filter/FilterEvent;)V");
|
||||
|
||||
jclass sharedFilterClazz = env->FindClass("android/media/tv/tuner/filter/SharedFilter");
|
||||
gFields.sharedFilterContext = env->GetFieldID(filterClazz, "mNativeContext", "J");
|
||||
gFields.sharedFilterInitID = env->GetMethodID(sharedFilterClazz, "<init>", "()V");
|
||||
gFields.onSharedFilterStatusID = env->GetMethodID(sharedFilterClazz, "onFilterStatus", "(I)V");
|
||||
gFields.onSharedFilterEventID =
|
||||
env->GetMethodID(sharedFilterClazz, "onFilterEvent",
|
||||
"([Landroid/media/tv/tuner/filter/FilterEvent;)V");
|
||||
|
||||
jclass timeFilterClazz = env->FindClass("android/media/tv/tuner/filter/TimeFilter");
|
||||
gFields.timeFilterContext = env->GetFieldID(timeFilterClazz, "mNativeContext", "J");
|
||||
gFields.timeFilterInitID = env->GetMethodID(timeFilterClazz, "<init>", "()V");
|
||||
@@ -3718,7 +3745,12 @@ static jint android_media_tv_Tuner_set_filter_data_source(
|
||||
}
|
||||
|
||||
static jint android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) {
|
||||
sp<FilterClient> filterClient = getFilterClient(env, filter);
|
||||
sp<FilterClient> filterClient = nullptr;
|
||||
if (env->IsInstanceOf(filter, env->FindClass("android/media/tv/tuner/filter/SharedFilter"))) {
|
||||
filterClient = getSharedFilterClient(env, filter);
|
||||
} else {
|
||||
filterClient = getFilterClient(env, filter);
|
||||
}
|
||||
if (filterClient == nullptr) {
|
||||
ALOGD("Failed to start filter: filter client not found");
|
||||
return (int)Result::NOT_INITIALIZED;
|
||||
@@ -3727,7 +3759,12 @@ static jint android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) {
|
||||
}
|
||||
|
||||
static jint android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) {
|
||||
sp<FilterClient> filterClient = getFilterClient(env, filter);
|
||||
sp<FilterClient> filterClient = nullptr;
|
||||
if (env->IsInstanceOf(filter, env->FindClass("android/media/tv/tuner/filter/SharedFilter"))) {
|
||||
filterClient = getSharedFilterClient(env, filter);
|
||||
} else {
|
||||
filterClient = getFilterClient(env, filter);
|
||||
}
|
||||
if (filterClient == nullptr) {
|
||||
ALOGD("Failed to stop filter: filter client not found");
|
||||
return (int)Result::NOT_INITIALIZED;
|
||||
@@ -3736,17 +3773,27 @@ static jint android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) {
|
||||
}
|
||||
|
||||
static jint android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) {
|
||||
sp<FilterClient> filterClient = getFilterClient(env, filter);
|
||||
sp<FilterClient> filterClient = nullptr;
|
||||
if (env->IsInstanceOf(filter, env->FindClass("android/media/tv/tuner/filter/SharedFilter"))) {
|
||||
filterClient = getSharedFilterClient(env, filter);
|
||||
} else {
|
||||
filterClient = getFilterClient(env, filter);
|
||||
}
|
||||
if (filterClient == nullptr) {
|
||||
ALOGD("Failed to flush filter: filter client not found");
|
||||
return (int)Result::NOT_INITIALIZED;
|
||||
return (jint)Result::NOT_INITIALIZED;
|
||||
}
|
||||
return (jint)filterClient->flush();
|
||||
}
|
||||
|
||||
static jint android_media_tv_Tuner_read_filter_fmq(
|
||||
JNIEnv *env, jobject filter, jbyteArray buffer, jlong offset, jlong size) {
|
||||
sp<FilterClient> filterClient = getFilterClient(env, filter);
|
||||
sp<FilterClient> filterClient = nullptr;
|
||||
if (env->IsInstanceOf(filter, env->FindClass("android/media/tv/tuner/filter/SharedFilter"))) {
|
||||
filterClient = getSharedFilterClient(env, filter);
|
||||
} else {
|
||||
filterClient = getFilterClient(env, filter);
|
||||
}
|
||||
if (filterClient == nullptr) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException",
|
||||
"Failed to read filter FMQ: filter client not found");
|
||||
@@ -3766,14 +3813,57 @@ static jint android_media_tv_Tuner_read_filter_fmq(
|
||||
}
|
||||
|
||||
static jint android_media_tv_Tuner_close_filter(JNIEnv *env, jobject filter) {
|
||||
sp<FilterClient> filterClient = getFilterClient(env, filter);
|
||||
sp<FilterClient> filterClient = nullptr;
|
||||
bool shared = env->IsInstanceOf(
|
||||
filter, env->FindClass("android/media/tv/tuner/filter/SharedFilter"));
|
||||
if (shared) {
|
||||
filterClient = getSharedFilterClient(env, filter);
|
||||
} else {
|
||||
filterClient = getFilterClient(env, filter);
|
||||
}
|
||||
if (filterClient == nullptr) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException",
|
||||
"Failed to close filter: filter client not found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (jint)filterClient->close();
|
||||
Result r = filterClient->close();
|
||||
filterClient->decStrong(filter);
|
||||
env->SetLongField(filter, gFields.sharedFilterContext, 0);
|
||||
if (shared) {
|
||||
} else {
|
||||
env->SetLongField(filter, gFields.filterContext, 0);
|
||||
}
|
||||
|
||||
return (jint)r;
|
||||
}
|
||||
|
||||
static jstring android_media_tv_Tuner_create_shared_filter(JNIEnv *env, jobject filter) {
|
||||
sp<FilterClient> filterClient = getFilterClient(env, filter);
|
||||
if (filterClient == nullptr) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException",
|
||||
"Failed to create shared filter: filter client not found");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
string token = filterClient->createSharedFilter();
|
||||
if (token.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return env->NewStringUTF(token.data());
|
||||
}
|
||||
|
||||
static void android_media_tv_Tuner_release_shared_filter(
|
||||
JNIEnv *env, jobject filter, jstring token) {
|
||||
sp<FilterClient> filterClient = getFilterClient(env, filter);
|
||||
if (filterClient == nullptr) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException",
|
||||
"Failed to release shared filter: filter client not found");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string filterToken(env->GetStringUTFChars(token, nullptr));
|
||||
filterClient->releaseSharedFilter(filterToken);
|
||||
}
|
||||
|
||||
static sp<TimeFilterClient> getTimeFilterClient(JNIEnv *env, jobject filter) {
|
||||
@@ -3843,10 +3933,8 @@ static int android_media_tv_Tuner_time_filter_close(JNIEnv *env, jobject filter)
|
||||
}
|
||||
|
||||
Result r = timeFilterClient->close();
|
||||
if (r == Result::SUCCESS) {
|
||||
timeFilterClient->decStrong(filter);
|
||||
env->SetLongField(filter, gFields.timeFilterContext, 0);
|
||||
}
|
||||
timeFilterClient->decStrong(filter);
|
||||
env->SetLongField(filter, gFields.timeFilterContext, 0);
|
||||
return (int)r;
|
||||
}
|
||||
|
||||
@@ -3896,9 +3984,8 @@ static jint android_media_tv_Tuner_close_descrambler(JNIEnv* env, jobject descra
|
||||
return (jint)Result::NOT_INITIALIZED;
|
||||
}
|
||||
Result r = descramblerClient->close();
|
||||
if (r == Result::SUCCESS) {
|
||||
descramblerClient->decStrong(descrambler);
|
||||
}
|
||||
descramblerClient->decStrong(descrambler);
|
||||
env->SetLongField(descrambler, gFields.descramblerContext, 0);
|
||||
return (jint)r;
|
||||
}
|
||||
|
||||
@@ -3935,6 +4022,29 @@ static jint android_media_tv_Tuner_close_demux(JNIEnv* env, jobject thiz, jint /
|
||||
return tuner->closeDemux();
|
||||
}
|
||||
|
||||
static jobject android_media_tv_Tuner_open_shared_filter(
|
||||
JNIEnv* env, jobject /* thiz */, jstring token) {
|
||||
|
||||
sp<TunerClient> tunerClient = new TunerClient();
|
||||
std::string filterToken(env->GetStringUTFChars(token, nullptr));
|
||||
sp<FilterClient> filterClient;
|
||||
sp<FilterClientCallbackImpl> callback = new FilterClientCallbackImpl();
|
||||
filterClient = tunerClient->openSharedFilter(filterToken, callback);
|
||||
if (filterClient == nullptr) {
|
||||
ALOGD("Failed to open shared filter %s", filterToken.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
jobject filterObj = env->NewObject(env->FindClass("android/media/tv/tuner/filter/SharedFilter"),
|
||||
gFields.sharedFilterInitID);
|
||||
|
||||
filterClient->incStrong(filterObj);
|
||||
env->SetLongField(filterObj, gFields.sharedFilterContext, (jlong)filterClient.get());
|
||||
callback->setSharedFilter(env->NewWeakGlobalRef(filterObj), filterClient);
|
||||
|
||||
return filterObj;
|
||||
}
|
||||
|
||||
static jint android_media_tv_Tuner_close_frontend(JNIEnv* env, jobject thiz, jint /* handle */) {
|
||||
sp<JTuner> tuner = getTuner(env, thiz);
|
||||
return tuner->closeFrontend();
|
||||
@@ -4014,7 +4124,14 @@ static jint android_media_tv_Tuner_close_dvr(JNIEnv* env, jobject dvr) {
|
||||
ALOGD("Failed to close dvr: dvr client not found");
|
||||
return (jint)Result::NOT_INITIALIZED;
|
||||
}
|
||||
return (jint)dvrClient->close();
|
||||
Result r = dvrClient->close();
|
||||
bool isRecorder =
|
||||
env->IsInstanceOf(dvr, env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"));
|
||||
jfieldID fieldId =
|
||||
isRecorder ? gFields.dvrRecorderContext : gFields.dvrPlaybackContext;
|
||||
dvrClient->decStrong(dvr);
|
||||
env->SetLongField(dvr, fieldId, 0);
|
||||
return (jint)r;
|
||||
}
|
||||
|
||||
static jint android_media_tv_Tuner_lnb_set_voltage(JNIEnv* env, jobject lnb, jint voltage) {
|
||||
@@ -4043,10 +4160,8 @@ static int android_media_tv_Tuner_lnb_send_diseqc_msg(JNIEnv* env, jobject lnb,
|
||||
static int android_media_tv_Tuner_close_lnb(JNIEnv* env, jobject lnb) {
|
||||
sp<LnbClient> lnbClient = getLnbClient(env, lnb);
|
||||
Result r = lnbClient->close();
|
||||
if (r == Result::SUCCESS) {
|
||||
lnbClient->decStrong(lnb);
|
||||
env->SetLongField(lnb, gFields.lnbContext, 0);
|
||||
}
|
||||
lnbClient->decStrong(lnb);
|
||||
env->SetLongField(lnb, gFields.lnbContext, 0);
|
||||
return (jint)r;
|
||||
}
|
||||
|
||||
@@ -4221,6 +4336,9 @@ static const JNINativeMethod gTunerMethods[] = {
|
||||
{ "nativeClose", "()I", (void *)android_media_tv_Tuner_close_tuner },
|
||||
{ "nativeCloseFrontend", "(I)I", (void *)android_media_tv_Tuner_close_frontend },
|
||||
{ "nativeCloseDemux", "(I)I", (void *)android_media_tv_Tuner_close_demux },
|
||||
{"nativeOpenSharedFilter",
|
||||
"(Ljava/lang/String;)Landroid/media/tv/tuner/filter/SharedFilter;",
|
||||
(void *)android_media_tv_Tuner_open_shared_filter},
|
||||
};
|
||||
|
||||
static const JNINativeMethod gFilterMethods[] = {
|
||||
@@ -4238,6 +4356,18 @@ static const JNINativeMethod gFilterMethods[] = {
|
||||
{ "nativeFlushFilter", "()I", (void *)android_media_tv_Tuner_flush_filter },
|
||||
{ "nativeRead", "([BJJ)I", (void *)android_media_tv_Tuner_read_filter_fmq },
|
||||
{ "nativeClose", "()I", (void *)android_media_tv_Tuner_close_filter },
|
||||
{"nativeCreateSharedFilter", "()Ljava/lang/String;",
|
||||
(void *)android_media_tv_Tuner_create_shared_filter},
|
||||
{"nativeReleaseSharedFilter", "(Ljava/lang/String;)V",
|
||||
(void *)android_media_tv_Tuner_release_shared_filter},
|
||||
};
|
||||
|
||||
static const JNINativeMethod gSharedFilterMethods[] = {
|
||||
{"nativeStartSharedFilter", "()I", (void *)android_media_tv_Tuner_start_filter},
|
||||
{"nativeStopSharedFilter", "()I", (void *)android_media_tv_Tuner_stop_filter},
|
||||
{"nativeFlushSharedFilter", "()I", (void *)android_media_tv_Tuner_flush_filter},
|
||||
{"nativeSharedRead", "([BJJ)I", (void *)android_media_tv_Tuner_read_filter_fmq},
|
||||
{"nativeSharedClose", "()I", (void *)android_media_tv_Tuner_close_filter},
|
||||
};
|
||||
|
||||
static const JNINativeMethod gTimeFilterMethods[] = {
|
||||
@@ -4321,6 +4451,13 @@ static bool register_android_media_tv_Tuner(JNIEnv *env) {
|
||||
ALOGE("Failed to register filter native methods");
|
||||
return false;
|
||||
}
|
||||
if (AndroidRuntime::registerNativeMethods(
|
||||
env, "android/media/tv/tuner/filter/SharedFilter",
|
||||
gSharedFilterMethods,
|
||||
NELEM(gSharedFilterMethods)) != JNI_OK) {
|
||||
ALOGE("Failed to register shared filter native methods");
|
||||
return false;
|
||||
}
|
||||
if (AndroidRuntime::registerNativeMethods(
|
||||
env, "android/media/tv/tuner/filter/TimeFilter",
|
||||
gTimeFilterMethods,
|
||||
|
||||
@@ -130,9 +130,12 @@ struct FilterClientCallbackImpl : public FilterClientCallback {
|
||||
virtual void onFilterStatus(const DemuxFilterStatus status);
|
||||
|
||||
void setFilter(jweak filterObj, sp<FilterClient> filterClient);
|
||||
void setSharedFilter(jweak filterObj, sp<FilterClient> filterClient);
|
||||
|
||||
private:
|
||||
jweak mFilterObj;
|
||||
sp<FilterClient> mFilterClient;
|
||||
bool mSharedFilter;
|
||||
void getSectionEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
|
||||
void getMediaEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
|
||||
void getPesEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
|
||||
|
||||
@@ -193,8 +193,27 @@ Result FilterClient::close() {
|
||||
return Result::INVALID_STATE;
|
||||
}
|
||||
|
||||
/////////////// TunerFilterCallback ///////////////////////
|
||||
string FilterClient::createSharedFilter() {
|
||||
if (mTunerFilter != nullptr) {
|
||||
string filterToken;
|
||||
if (mTunerFilter->createSharedFilter(&filterToken).isOk()) {
|
||||
return filterToken;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
Result FilterClient::releaseSharedFilter(const string& filterToken) {
|
||||
if (mTunerFilter != nullptr) {
|
||||
Status s = mTunerFilter->releaseSharedFilter(filterToken);
|
||||
return ClientHelper::getServiceSpecificErrorCode(s);
|
||||
}
|
||||
|
||||
return Result::INVALID_STATE;
|
||||
}
|
||||
|
||||
/////////////// TunerFilterCallback ///////////////////////
|
||||
TunerFilterCallback::TunerFilterCallback(sp<FilterClientCallback> filterClientCallback)
|
||||
: mFilterClientCallback(filterClientCallback) {}
|
||||
|
||||
@@ -215,14 +234,14 @@ Status TunerFilterCallback::onFilterEvent(const vector<DemuxFilterEvent>& filter
|
||||
}
|
||||
|
||||
Result FilterClient::getFilterMq() {
|
||||
if (mFilterMQ != NULL) {
|
||||
if (mFilterMQ != nullptr) {
|
||||
return Result::SUCCESS;
|
||||
}
|
||||
|
||||
AidlMQDesc aidlMqDesc;
|
||||
Result res = Result::UNAVAILABLE;
|
||||
|
||||
if (mTunerFilter != NULL) {
|
||||
if (mTunerFilter != nullptr) {
|
||||
Status s = mTunerFilter->getQueueDesc(&aidlMqDesc);
|
||||
if (s.isOk()) {
|
||||
mFilterMQ = new (nothrow) AidlMQ(aidlMqDesc, false/*resetPointer*/);
|
||||
|
||||
@@ -142,6 +142,16 @@ public:
|
||||
*/
|
||||
Result close();
|
||||
|
||||
/**
|
||||
* Create a new SharedFiler.
|
||||
*/
|
||||
string createSharedFilter();
|
||||
|
||||
/**
|
||||
* Release SharedFiler.
|
||||
*/
|
||||
Result releaseSharedFilter(const string& filterToken);
|
||||
|
||||
private:
|
||||
Result getFilterMq();
|
||||
int64_t copyData(int8_t* buffer, int64_t size);
|
||||
|
||||
@@ -33,8 +33,10 @@ int32_t TunerClient::mTunerVersion;
|
||||
/////////////// TunerClient ///////////////////////
|
||||
|
||||
TunerClient::TunerClient() {
|
||||
::ndk::SpAIBinder binder(AServiceManager_getService("media.tuner"));
|
||||
mTunerService = ITunerService::fromBinder(binder);
|
||||
if (mTunerService == nullptr) {
|
||||
::ndk::SpAIBinder binder(AServiceManager_getService("media.tuner"));
|
||||
mTunerService = ITunerService::fromBinder(binder);
|
||||
}
|
||||
if (mTunerService == nullptr) {
|
||||
ALOGE("Failed to get tuner service");
|
||||
} else {
|
||||
@@ -43,8 +45,6 @@ TunerClient::TunerClient() {
|
||||
}
|
||||
|
||||
TunerClient::~TunerClient() {
|
||||
mTunerVersion = 0;
|
||||
mTunerService = nullptr;
|
||||
}
|
||||
|
||||
vector<int32_t> TunerClient::getFrontendIds() {
|
||||
@@ -163,4 +163,26 @@ sp<LnbClient> TunerClient::openLnbByName(string lnbName) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sp<FilterClient> TunerClient::openSharedFilter(const string& filterToken,
|
||||
sp<FilterClientCallback> cb) {
|
||||
if (cb == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mTunerService != nullptr) {
|
||||
shared_ptr<ITunerFilter> tunerFilter;
|
||||
shared_ptr<TunerFilterCallback> callback =
|
||||
::ndk::SharedRefBase::make<TunerFilterCallback>(cb);
|
||||
Status s = mTunerService->openSharedFilter(filterToken, callback, &tunerFilter);
|
||||
if (!s.isOk()) {
|
||||
return nullptr;
|
||||
}
|
||||
DemuxFilterType type;
|
||||
tunerFilter->getFilterType(&type);
|
||||
return new FilterClient(type, tunerFilter);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -20,10 +20,12 @@
|
||||
#include <aidl/android/media/tv/tuner/ITunerService.h>
|
||||
#include <android/binder_parcel_utils.h>
|
||||
|
||||
#include "DemuxClient.h"
|
||||
#include "ClientHelper.h"
|
||||
#include "FrontendClient.h"
|
||||
#include "DemuxClient.h"
|
||||
#include "DescramblerClient.h"
|
||||
#include "FilterClient.h"
|
||||
#include "FilterClientCallback.h"
|
||||
#include "FrontendClient.h"
|
||||
#include "LnbClient.h"
|
||||
|
||||
using Status = ::ndk::ScopedAStatus;
|
||||
@@ -116,6 +118,15 @@ public:
|
||||
*/
|
||||
int32_t getHalTunerVersion() { return mTunerVersion; }
|
||||
|
||||
/**
|
||||
* Open a new shared filter client.
|
||||
*
|
||||
* @param filterToken the shared filter token created by FilterClient.
|
||||
* @param cb the FilterClientCallback to receive filter events.
|
||||
* @return a newly created TunerFilter interface.
|
||||
*/
|
||||
sp<FilterClient> openSharedFilter(const string& filterToken, sp<FilterClientCallback> cb);
|
||||
|
||||
private:
|
||||
/**
|
||||
* An AIDL Tuner Service Singleton assigned at the first time the Tuner Client
|
||||
|
||||
@@ -424,6 +424,7 @@
|
||||
|
||||
<!-- Permissions required for CTS test - TunerTest -->
|
||||
<uses-permission android:name="android.permission.ACCESS_TV_DESCRAMBLER" />
|
||||
<uses-permission android:name="android.permission.ACCESS_TV_SHARED_FILTER" />
|
||||
<uses-permission android:name="android.permission.ACCESS_TV_TUNER" />
|
||||
<uses-permission android:name="android.permission.TUNER_RESOURCE_ACCESS" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user