Enable capability based demux management
Adding the following 3 new SystemAPIs along with new class (DemuxInfo), which holds the capabilities information such as DemuxFilterMainType - API to configue desired demux capabilities such as DemuxFilterMainType - API to get the info of currently held demux - API to get the list of infos of all the demux in the system Also, with this change Demux resource will now be managed under TunerResourceManager. Bug: 239211919 Bug: 239227510 Test: atest TunerTest TunerResourceManagerServiceTest VtsHalTvTunerTargetTest Change-Id: Ifa3a30bbd6ea4ad1ded5eedca60eb240887c0303
This commit is contained in:
@@ -7461,6 +7461,7 @@ package android.media.tv.tuner {
|
||||
method public int getAudioFilterCount();
|
||||
method public int getDemuxCount();
|
||||
method public int getFilterCapabilities();
|
||||
method @NonNull public int[] getFilterTypeCapabilityList();
|
||||
method @NonNull @Size(5) public int[] getLinkCapabilities();
|
||||
method public int getPcrFilterCount();
|
||||
method public int getPesFilterCount();
|
||||
@@ -7473,6 +7474,12 @@ package android.media.tv.tuner {
|
||||
method public boolean isTimeFilterSupported();
|
||||
}
|
||||
|
||||
public class DemuxInfo {
|
||||
ctor public DemuxInfo(int);
|
||||
method public int getFilterTypes();
|
||||
method public void setFilterTypes(int);
|
||||
}
|
||||
|
||||
public class Descrambler implements java.lang.AutoCloseable {
|
||||
method public int addPid(int, int, @Nullable android.media.tv.tuner.filter.Filter);
|
||||
method public void close();
|
||||
@@ -7525,6 +7532,7 @@ package android.media.tv.tuner {
|
||||
method public void clearResourceLostListener();
|
||||
method public void close();
|
||||
method public void closeFrontend();
|
||||
method public int configureDemux(@Nullable android.media.tv.tuner.DemuxInfo);
|
||||
method public int connectCiCam(int);
|
||||
method public int connectFrontendToCiCam(int);
|
||||
method public int disconnectCiCam();
|
||||
@@ -7532,6 +7540,7 @@ package android.media.tv.tuner {
|
||||
method public int getAvSyncHwId(@NonNull android.media.tv.tuner.filter.Filter);
|
||||
method public long getAvSyncTime(int);
|
||||
method @Nullable public java.util.List<android.media.tv.tuner.frontend.FrontendInfo> getAvailableFrontendInfos();
|
||||
method @Nullable public android.media.tv.tuner.DemuxInfo getCurrentDemuxInfo();
|
||||
method @Nullable public String getCurrentFrontendHardwareInfo();
|
||||
method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
|
||||
method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
|
||||
|
||||
@@ -36,8 +36,14 @@ import java.lang.annotation.RetentionPolicy;
|
||||
public class DemuxCapabilities {
|
||||
|
||||
/** @hide */
|
||||
@IntDef(value = {Filter.TYPE_TS, Filter.TYPE_MMTP, Filter.TYPE_IP, Filter.TYPE_TLV,
|
||||
Filter.TYPE_ALP})
|
||||
@IntDef(flag = true, prefix = { "TYPE_" }, value = {
|
||||
Filter.TYPE_UNDEFINED,
|
||||
Filter.TYPE_TS,
|
||||
Filter.TYPE_MMTP,
|
||||
Filter.TYPE_IP,
|
||||
Filter.TYPE_TLV,
|
||||
Filter.TYPE_ALP,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface FilterCapabilities {}
|
||||
|
||||
@@ -51,14 +57,16 @@ public class DemuxCapabilities {
|
||||
private final int mPesFilterCount;
|
||||
private final int mPcrFilterCount;
|
||||
private final long mSectionFilterLength;
|
||||
private final int mFilterCaps;
|
||||
private final @FilterCapabilities int mFilterCaps;
|
||||
private final @FilterCapabilities int[] mFilterCapsList;
|
||||
private final int[] mLinkCaps;
|
||||
private final boolean mSupportTimeFilter;
|
||||
|
||||
// Used by JNI
|
||||
private DemuxCapabilities(int demuxCount, int recordCount, int playbackCount, int tsFilterCount,
|
||||
int sectionFilterCount, int audioFilterCount, int videoFilterCount, int pesFilterCount,
|
||||
int pcrFilterCount, long sectionFilterLength, int filterCaps, int[] linkCaps,
|
||||
int pcrFilterCount, long sectionFilterLength, int filterCaps,
|
||||
@FilterCapabilities int[] filterCapsList, @FilterCapabilities int[] linkCaps,
|
||||
boolean timeFilter) {
|
||||
mDemuxCount = demuxCount;
|
||||
mRecordCount = recordCount;
|
||||
@@ -71,6 +79,7 @@ public class DemuxCapabilities {
|
||||
mPcrFilterCount = pcrFilterCount;
|
||||
mSectionFilterLength = sectionFilterLength;
|
||||
mFilterCaps = filterCaps;
|
||||
mFilterCapsList = filterCapsList;
|
||||
mLinkCaps = linkCaps;
|
||||
mSupportTimeFilter = timeFilter;
|
||||
}
|
||||
@@ -147,6 +156,24 @@ public class DemuxCapabilities {
|
||||
return mFilterCaps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of filter main type capabilities in bit field.
|
||||
*
|
||||
* <p>Each element in the returned array represents the supported filter main types
|
||||
* represented as bitwise OR of the types in {@link FilterConfiguration}.
|
||||
* <p>Whereas getFilterCapabilities() returns the bitwise OR value of all the supported filter
|
||||
* types in the system, this API returns a list of supported filter types in the system with
|
||||
* each entry representing the supported filter types per demux resource.
|
||||
*
|
||||
* @return an array of supported filter main types for the demux resources in the system
|
||||
* an empty array should be returned for devices with Tuner HAL version 2 and below
|
||||
*/
|
||||
@FilterCapabilities
|
||||
@NonNull
|
||||
public int[] getFilterTypeCapabilityList() {
|
||||
return mFilterCapsList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets link capabilities.
|
||||
*
|
||||
|
||||
54
media/java/android/media/tv/tuner/DemuxInfo.java
Normal file
54
media/java/android/media/tv/tuner/DemuxInfo.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2022 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;
|
||||
|
||||
import android.annotation.SystemApi;
|
||||
import android.media.tv.tuner.DemuxCapabilities.FilterCapabilities;
|
||||
|
||||
/**
|
||||
* This class is used to specify information of a demux.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public class DemuxInfo {
|
||||
// Bitwise OR of filter types
|
||||
private int mFilterTypes;
|
||||
|
||||
public DemuxInfo(@FilterCapabilities int filterTypes) {
|
||||
setFilterTypes(filterTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filter types
|
||||
*
|
||||
* @return the filter types
|
||||
*/
|
||||
@FilterCapabilities
|
||||
public int getFilterTypes() {
|
||||
return mFilterTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the filter types
|
||||
*
|
||||
* @param filterTypes the filter types to set
|
||||
*/
|
||||
public void setFilterTypes(@FilterCapabilities int filterTypes) {
|
||||
mFilterTypes = filterTypes;
|
||||
}
|
||||
}
|
||||
@@ -281,6 +281,7 @@ public class Tuner implements AutoCloseable {
|
||||
private final TunerResourceManager mTunerResourceManager;
|
||||
private final int mClientId;
|
||||
private static int sTunerVersion = TunerVersionChecker.TUNER_VERSION_UNKNOWN;
|
||||
private DemuxInfo mDesiredDemuxInfo = new DemuxInfo(Filter.TYPE_UNDEFINED);
|
||||
|
||||
private Frontend mFrontend;
|
||||
private EventHandler mHandler;
|
||||
@@ -895,12 +896,7 @@ public class Tuner implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseAll() {
|
||||
// release CiCam before frontend because frontend handle is needed to unlink CiCam
|
||||
releaseCiCam();
|
||||
|
||||
releaseFrontend();
|
||||
|
||||
private void closeLnb() {
|
||||
mLnbLock.lock();
|
||||
try {
|
||||
// mLnb will be non-null only for owner tuner
|
||||
@@ -917,8 +913,23 @@ public class Tuner implements AutoCloseable {
|
||||
} finally {
|
||||
mLnbLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseFilters() {
|
||||
synchronized (mFilters) {
|
||||
if (!mFilters.isEmpty()) {
|
||||
for (WeakReference<Filter> weakFilter : mFilters) {
|
||||
Filter filter = weakFilter.get();
|
||||
if (filter != null) {
|
||||
filter.close();
|
||||
}
|
||||
}
|
||||
mFilters.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseDescramblers() {
|
||||
synchronized (mDescramblers) {
|
||||
if (!mDescramblers.isEmpty()) {
|
||||
for (Map.Entry<Integer, WeakReference<Descrambler>> d : mDescramblers.entrySet()) {
|
||||
@@ -931,19 +942,9 @@ public class Tuner implements AutoCloseable {
|
||||
mDescramblers.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mFilters) {
|
||||
if (!mFilters.isEmpty()) {
|
||||
for (WeakReference<Filter> weakFilter : mFilters) {
|
||||
Filter filter = weakFilter.get();
|
||||
if (filter != null) {
|
||||
filter.close();
|
||||
}
|
||||
}
|
||||
mFilters.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseDemux() {
|
||||
mDemuxLock.lock();
|
||||
try {
|
||||
if (mDemuxHandle != null) {
|
||||
@@ -957,9 +958,17 @@ public class Tuner implements AutoCloseable {
|
||||
} finally {
|
||||
mDemuxLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseAll() {
|
||||
// release CiCam before frontend because frontend handle is needed to unlink CiCam
|
||||
releaseCiCam();
|
||||
releaseFrontend();
|
||||
closeLnb();
|
||||
releaseDescramblers();
|
||||
releaseFilters();
|
||||
releaseDemux();
|
||||
mTunerResourceManager.unregisterClientProfile(mClientId);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1025,6 +1034,7 @@ public class Tuner implements AutoCloseable {
|
||||
private native DvrPlayback nativeOpenDvrPlayback(long bufferSize);
|
||||
|
||||
private native DemuxCapabilities nativeGetDemuxCapabilities();
|
||||
private native DemuxInfo nativeGetDemuxInfo(int demuxHandle);
|
||||
|
||||
private native int nativeCloseDemux(int handle);
|
||||
private native int nativeCloseFrontend(int handle);
|
||||
@@ -1865,6 +1875,30 @@ public class Tuner implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets DemuxInfo of the currently held demux
|
||||
*
|
||||
* @return A {@link DemuxInfo} of currently held demux resource.
|
||||
* Returns null if no demux resource is held.
|
||||
*/
|
||||
@Nullable
|
||||
public DemuxInfo getCurrentDemuxInfo() {
|
||||
mDemuxLock.lock();
|
||||
try {
|
||||
if (mDemuxHandle == null) {
|
||||
return null;
|
||||
}
|
||||
return nativeGetDemuxInfo(mDemuxHandle);
|
||||
} finally {
|
||||
mDemuxLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public DemuxInfo getDesiredDemuxInfo() {
|
||||
return mDesiredDemuxInfo;
|
||||
}
|
||||
|
||||
private void onFrontendEvent(int eventType) {
|
||||
Log.d(TAG, "Got event from tuning. Event type: " + eventType + " for " + this);
|
||||
synchronized (mOnTuneEventLock) {
|
||||
@@ -2173,6 +2207,11 @@ public class Tuner implements AutoCloseable {
|
||||
/**
|
||||
* Opens a filter object based on the given types and buffer size.
|
||||
*
|
||||
* <p>For TUNER_VERSION_3_0 and above, configureDemuxInternal() will be called with mainType.
|
||||
* However, unlike when configureDemux() is called directly, the desired filter types will not
|
||||
* be changed when previously set desired filter types are the superset of the newly desired
|
||||
* ones.
|
||||
*
|
||||
* @param mainType the main type of the filter.
|
||||
* @param subType the subtype of the filter.
|
||||
* @param bufferSize the buffer size of the filter to be opened in bytes. The buffer holds the
|
||||
@@ -2188,6 +2227,15 @@ public class Tuner implements AutoCloseable {
|
||||
@Nullable FilterCallback cb) {
|
||||
mDemuxLock.lock();
|
||||
try {
|
||||
int tunerMajorVersion = TunerVersionChecker.getMajorVersion(sTunerVersion);
|
||||
if (sTunerVersion >= TunerVersionChecker.TUNER_VERSION_3_0) {
|
||||
DemuxInfo demuxInfo = new DemuxInfo(mainType);
|
||||
int res = configureDemuxInternal(demuxInfo, false /* reduceDesiredFilterTypes */);
|
||||
if (res != RESULT_SUCCESS) {
|
||||
Log.e(TAG, "openFilter called for unsupported mainType: " + mainType);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (!checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX, mDemuxLock)) {
|
||||
return null;
|
||||
}
|
||||
@@ -2470,10 +2518,109 @@ public class Tuner implements AutoCloseable {
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the desired {@link DemuxInfo}
|
||||
*
|
||||
* <p>The already held demux and filters will be released when desiredDemuxInfo is null or the
|
||||
* desireDemuxInfo.getFilterTypes() is not supported by the already held demux.
|
||||
*
|
||||
* @param desiredDemuxInfo the desired {@link DemuxInfo}, which includes information such as
|
||||
* filterTypes ({@link DemuxFilterMainType}).
|
||||
* @return result status of configure demux operation. {@link #RESULT_UNAVAILABLE} is returned
|
||||
* when a) the desired capabilities are not supported by the system,
|
||||
* b) this API is called on unsupported version, or
|
||||
* c) either getDemuxCapabilities or getFilterTypeCapabilityList()
|
||||
* returns an empty array
|
||||
*/
|
||||
@Result
|
||||
public int configureDemux(@Nullable DemuxInfo desiredDemuxInfo) {
|
||||
int tunerMajorVersion = TunerVersionChecker.getMajorVersion(sTunerVersion);
|
||||
if (sTunerVersion < TunerVersionChecker.TUNER_VERSION_3_0) {
|
||||
Log.e(TAG, "configureDemux() is not supported for tuner version:"
|
||||
+ TunerVersionChecker.getMajorVersion(sTunerVersion) + "."
|
||||
+ TunerVersionChecker.getMinorVersion(sTunerVersion) + ".");
|
||||
return RESULT_UNAVAILABLE;
|
||||
}
|
||||
|
||||
synchronized (mDemuxLock) {
|
||||
return configureDemuxInternal(desiredDemuxInfo, true /* reduceDesiredFilterTypes */);
|
||||
}
|
||||
}
|
||||
|
||||
private int configureDemuxInternal(@Nullable DemuxInfo desiredDemuxInfo,
|
||||
boolean reduceDesiredFilterTypes) {
|
||||
// release the currently held demux if the desired demux info is null
|
||||
if (desiredDemuxInfo == null) {
|
||||
if (mDemuxHandle != null) {
|
||||
releaseFilters();
|
||||
releaseDemux();
|
||||
}
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
int desiredFilterTypes = desiredDemuxInfo.getFilterTypes();
|
||||
|
||||
// just update and return success if the desiredFilterTypes is equal to or a subset of
|
||||
// a previously configured value
|
||||
if ((mDesiredDemuxInfo.getFilterTypes() & desiredFilterTypes)
|
||||
== desiredFilterTypes) {
|
||||
if (reduceDesiredFilterTypes) {
|
||||
mDesiredDemuxInfo.setFilterTypes(desiredFilterTypes);
|
||||
}
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
// check if the desire capability is supported
|
||||
DemuxCapabilities caps = nativeGetDemuxCapabilities();
|
||||
if (caps == null) {
|
||||
Log.e(TAG, "configureDemuxInternal:failed to get DemuxCapabilities");
|
||||
return RESULT_UNAVAILABLE;
|
||||
}
|
||||
|
||||
int[] filterCapsList = caps.getFilterTypeCapabilityList();
|
||||
if (filterCapsList.length <= 0) {
|
||||
Log.e(TAG, "configureDemuxInternal: getFilterTypeCapabilityList()"
|
||||
+ " returned an empty array");
|
||||
return RESULT_UNAVAILABLE;
|
||||
}
|
||||
|
||||
boolean supported = false;
|
||||
for (int filterCaps : filterCapsList) {
|
||||
if ((desiredFilterTypes & filterCaps) == desiredFilterTypes) {
|
||||
supported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!supported) {
|
||||
Log.e(TAG, "configureDemuxInternal: requested caps:" + desiredFilterTypes
|
||||
+ " is not supported by the system");
|
||||
return RESULT_UNAVAILABLE;
|
||||
}
|
||||
|
||||
// close demux if not compatible
|
||||
if (mDemuxHandle != null) {
|
||||
if (desiredFilterTypes != Filter.TYPE_UNDEFINED) {
|
||||
// Release the existing demux only if
|
||||
// the desired caps is not supported
|
||||
DemuxInfo currentDemuxInfo = nativeGetDemuxInfo(mDemuxHandle);
|
||||
if (currentDemuxInfo != null) {
|
||||
if ((desiredFilterTypes & currentDemuxInfo.getFilterTypes())
|
||||
!= desiredFilterTypes) {
|
||||
releaseFilters();
|
||||
releaseDemux();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mDesiredDemuxInfo.setFilterTypes(desiredFilterTypes);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
private boolean requestDemux() {
|
||||
int[] demuxHandle = new int[1];
|
||||
TunerDemuxRequest request = new TunerDemuxRequest();
|
||||
request.clientId = mClientId;
|
||||
request.desiredFilterTypes = mDesiredDemuxInfo.getFilterTypes();
|
||||
boolean granted = mTunerResourceManager.requestDemux(request, demuxHandle);
|
||||
if (granted) {
|
||||
mDemuxHandle = demuxHandle[0];
|
||||
|
||||
@@ -288,6 +288,23 @@ public class TunerResourceManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current TRM of the TunerHAL Demux information.
|
||||
*
|
||||
* <p><strong>Note:</strong> This update must happen before the first
|
||||
* {@link #requestDemux(TunerDemuxRequest, int[])} and
|
||||
* {@link #releaseDemux(int, int)} call.
|
||||
*
|
||||
* @param infos an array of the available {@link TunerDemuxInfo} information.
|
||||
*/
|
||||
public void setDemuxInfoList(@NonNull TunerDemuxInfo[] infos) {
|
||||
try {
|
||||
mService.setDemuxInfoList(infos);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the TRM of the current CAS information.
|
||||
*
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.media.tv.tunerresourcemanager.CasSessionRequest;
|
||||
import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
|
||||
import android.media.tv.tunerresourcemanager.ResourceClientProfile;
|
||||
import android.media.tv.tunerresourcemanager.TunerCiCamRequest;
|
||||
import android.media.tv.tunerresourcemanager.TunerDemuxInfo;
|
||||
import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
|
||||
import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
|
||||
import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
|
||||
@@ -129,6 +130,17 @@ interface ITunerResourceManager {
|
||||
*/
|
||||
void updateCasInfo(in int casSystemId, in int maxSessionNum);
|
||||
|
||||
/*
|
||||
* Updates the available Demux resources information on the current device.
|
||||
*
|
||||
* <p><strong>Note:</strong> This update must happen before the first
|
||||
* {@link #requestDemux(TunerDemux,int[])} and {@link #releaseDemux(int, int)}
|
||||
* call.
|
||||
*
|
||||
* @param infos an array of the available {@link TunerDemux} information.
|
||||
*/
|
||||
void setDemuxInfoList(in TunerDemuxInfo[] infos);
|
||||
|
||||
/*
|
||||
* Updates the available Lnb resource information on the current device.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright 2022, 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.tunerresourcemanager;
|
||||
|
||||
/**
|
||||
* TunerDemuxInfo interface that carries tuner demux information.
|
||||
*
|
||||
* This is used to update the TunerResourceManager demux resources.
|
||||
* @hide
|
||||
*/
|
||||
parcelable TunerDemuxInfo {
|
||||
/**
|
||||
* Demux handle
|
||||
*/
|
||||
int handle;
|
||||
|
||||
/**
|
||||
* Supported filter types (defined in {@link android.media.tv.tuner.filter.Filter})
|
||||
*/
|
||||
int filterTypes;
|
||||
}
|
||||
@@ -23,4 +23,9 @@ package android.media.tv.tunerresourcemanager;
|
||||
*/
|
||||
parcelable TunerDemuxRequest {
|
||||
int clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Desired filter types (defined in {@link android.media.tv.tuner.filter.Filter})
|
||||
*/
|
||||
int desiredFilterTypes;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <aidl/android/hardware/tv/tuner/DemuxFilterSubType.h>
|
||||
#include <aidl/android/hardware/tv/tuner/DemuxFilterTemiEvent.h>
|
||||
#include <aidl/android/hardware/tv/tuner/DemuxFilterTsRecordEvent.h>
|
||||
#include <aidl/android/hardware/tv/tuner/DemuxInfo.h>
|
||||
#include <aidl/android/hardware/tv/tuner/DemuxIpAddress.h>
|
||||
#include <aidl/android/hardware/tv/tuner/DemuxIpFilterSettings.h>
|
||||
#include <aidl/android/hardware/tv/tuner/DemuxIpFilterType.h>
|
||||
@@ -192,6 +193,7 @@ using ::aidl::android::hardware::tv::tuner::DemuxFilterSettings;
|
||||
using ::aidl::android::hardware::tv::tuner::DemuxFilterSubType;
|
||||
using ::aidl::android::hardware::tv::tuner::DemuxFilterTemiEvent;
|
||||
using ::aidl::android::hardware::tv::tuner::DemuxFilterTsRecordEvent;
|
||||
using ::aidl::android::hardware::tv::tuner::DemuxInfo;
|
||||
using ::aidl::android::hardware::tv::tuner::DemuxIpAddress;
|
||||
using ::aidl::android::hardware::tv::tuner::DemuxIpAddressIpAddress;
|
||||
using ::aidl::android::hardware::tv::tuner::DemuxIpFilterSettings;
|
||||
@@ -2068,7 +2070,7 @@ jobject JTuner::getDemuxCaps() {
|
||||
|
||||
JNIEnv *env = AndroidRuntime::getJNIEnv();
|
||||
jclass clazz = env->FindClass("android/media/tv/tuner/DemuxCapabilities");
|
||||
jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIIIIIIJI[IZ)V");
|
||||
jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIIIIIIJI[I[IZ)V");
|
||||
|
||||
jint numDemux = caps->numDemux;
|
||||
jint numRecord = caps->numRecord;
|
||||
@@ -2080,16 +2082,49 @@ jobject JTuner::getDemuxCaps() {
|
||||
jint numPesFilter = caps->numPesFilter;
|
||||
jint numPcrFilter = caps->numPcrFilter;
|
||||
jlong numBytesInSectionFilter = caps->numBytesInSectionFilter;
|
||||
jint filterCaps = caps->filterCaps;
|
||||
jboolean bTimeFilter = caps->bTimeFilter;
|
||||
|
||||
jint filterCaps = caps->filterCaps;
|
||||
jintArray filterCapsList = nullptr;
|
||||
vector<DemuxInfo> demuxInfoList;
|
||||
sTunerClient->getDemuxInfoList(&demuxInfoList);
|
||||
if (demuxInfoList.size() > 0) {
|
||||
vector<int32_t> demuxFilterTypesList;
|
||||
for (int i = 0; i < demuxInfoList.size(); i++) {
|
||||
demuxFilterTypesList.push_back(demuxInfoList[i].filterTypes);
|
||||
}
|
||||
filterCapsList = env->NewIntArray(demuxFilterTypesList.size());
|
||||
env->SetIntArrayRegion(filterCapsList, 0, demuxFilterTypesList.size(),
|
||||
reinterpret_cast<jint *>(&demuxFilterTypesList[0]));
|
||||
} else {
|
||||
filterCapsList = env->NewIntArray(0);
|
||||
}
|
||||
jintArray linkCaps = env->NewIntArray(caps->linkCaps.size());
|
||||
env->SetIntArrayRegion(linkCaps, 0, caps->linkCaps.size(),
|
||||
reinterpret_cast<jint *>(&caps->linkCaps[0]));
|
||||
|
||||
return env->NewObject(clazz, capsInit, numDemux, numRecord, numPlayback, numTsFilter,
|
||||
numSectionFilter, numAudioFilter, numVideoFilter, numPesFilter, numPcrFilter,
|
||||
numBytesInSectionFilter, filterCaps, linkCaps, bTimeFilter);
|
||||
numBytesInSectionFilter, filterCaps, filterCapsList, linkCaps, bTimeFilter);
|
||||
}
|
||||
|
||||
jobject JTuner::getDemuxInfo(int handle) {
|
||||
if (sTunerClient == nullptr) {
|
||||
ALOGE("tuner is not initialized");
|
||||
return nullptr;
|
||||
}
|
||||
shared_ptr<DemuxInfo> demuxInfo = sTunerClient->getDemuxInfo(handle);
|
||||
if (demuxInfo == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JNIEnv *env = AndroidRuntime::getJNIEnv();
|
||||
jclass clazz = env->FindClass("android/media/tv/tuner/DemuxInfo");
|
||||
jmethodID infoInit = env->GetMethodID(clazz, "<init>", "(I)V");
|
||||
|
||||
jint filterTypes = demuxInfo->filterTypes;
|
||||
|
||||
return env->NewObject(clazz, infoInit, filterTypes);
|
||||
}
|
||||
|
||||
jobject JTuner::getFrontendStatus(jintArray types) {
|
||||
@@ -4469,6 +4504,11 @@ static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv* env, jobject thiz)
|
||||
return tuner->getDemuxCaps();
|
||||
}
|
||||
|
||||
static jobject android_media_tv_Tuner_get_demux_info(JNIEnv* env, jobject thiz, jint handle) {
|
||||
sp<JTuner> tuner = getTuner(env, thiz);
|
||||
return tuner->getDemuxInfo(handle);
|
||||
}
|
||||
|
||||
static jint android_media_tv_Tuner_open_demux(JNIEnv* env, jobject thiz, jint handle) {
|
||||
sp<JTuner> tuner = getTuner(env, thiz);
|
||||
return (jint)tuner->openDemux(handle);
|
||||
@@ -4860,6 +4900,8 @@ static const JNINativeMethod gTunerMethods[] = {
|
||||
(void *)android_media_tv_Tuner_open_dvr_playback },
|
||||
{ "nativeGetDemuxCapabilities", "()Landroid/media/tv/tuner/DemuxCapabilities;",
|
||||
(void *)android_media_tv_Tuner_get_demux_caps },
|
||||
{ "nativeGetDemuxInfo", "(I)Landroid/media/tv/tuner/DemuxInfo;",
|
||||
(void *)android_media_tv_Tuner_get_demux_info },
|
||||
{ "nativeOpenDemuxByhandle", "(I)I", (void *)android_media_tv_Tuner_open_demux },
|
||||
{ "nativeClose", "()I", (void *)android_media_tv_Tuner_close_tuner },
|
||||
{ "nativeCloseFrontend", "(I)I", (void *)android_media_tv_Tuner_close_frontend },
|
||||
|
||||
@@ -198,6 +198,7 @@ struct JTuner : public RefBase {
|
||||
jobject openDescrambler();
|
||||
jobject openDvr(DvrType type, jlong bufferSize);
|
||||
jobject getDemuxCaps();
|
||||
jobject getDemuxInfo(int handle);
|
||||
jobject getFrontendStatus(jintArray types);
|
||||
Result openDemux(int handle);
|
||||
jint close();
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#include "TunerClient.h"
|
||||
|
||||
using ::aidl::android::hardware::tv::tuner::FrontendStatusType;
|
||||
using ::aidl::android::hardware::tv::tuner::FrontendType;
|
||||
|
||||
namespace android {
|
||||
@@ -108,6 +107,27 @@ sp<DemuxClient> TunerClient::openDemux(int32_t demuxHandle) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
shared_ptr<DemuxInfo> TunerClient::getDemuxInfo(int32_t demuxHandle) {
|
||||
if (mTunerService != nullptr) {
|
||||
DemuxInfo aidlDemuxInfo;
|
||||
Status s = mTunerService->getDemuxInfo(demuxHandle, &aidlDemuxInfo);
|
||||
if (!s.isOk()) {
|
||||
return nullptr;
|
||||
}
|
||||
return make_shared<DemuxInfo>(aidlDemuxInfo);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TunerClient::getDemuxInfoList(vector<DemuxInfo>* demuxInfoList) {
|
||||
if (mTunerService != nullptr) {
|
||||
Status s = mTunerService->getDemuxInfoList(demuxInfoList);
|
||||
if (!s.isOk()) {
|
||||
demuxInfoList->clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<DemuxCapabilities> TunerClient::getDemuxCaps() {
|
||||
if (mTunerService != nullptr) {
|
||||
DemuxCapabilities aidlCaps;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
using Status = ::ndk::ScopedAStatus;
|
||||
|
||||
using ::aidl::android::hardware::tv::tuner::DemuxCapabilities;
|
||||
using ::aidl::android::hardware::tv::tuner::DemuxInfo;
|
||||
using ::aidl::android::hardware::tv::tuner::FrontendInfo;
|
||||
using ::aidl::android::hardware::tv::tuner::FrontendType;
|
||||
using ::aidl::android::hardware::tv::tuner::Result;
|
||||
@@ -82,6 +83,21 @@ public:
|
||||
*/
|
||||
sp<DemuxClient> openDemux(int32_t demuxHandle);
|
||||
|
||||
/**
|
||||
* Retrieve the DemuxInfo of a specific demux
|
||||
*
|
||||
* @param demuxHandle the handle of the demux to query demux info for
|
||||
* @return the demux info
|
||||
*/
|
||||
shared_ptr<DemuxInfo> getDemuxInfo(int32_t demuxHandle);
|
||||
|
||||
/**
|
||||
* Retrieve a list of demux info
|
||||
*
|
||||
* @return a list of DemuxInfo
|
||||
*/
|
||||
void getDemuxInfoList(vector<DemuxInfo>* demuxInfoList);
|
||||
|
||||
/**
|
||||
* Retrieve the Demux capabilities.
|
||||
*
|
||||
|
||||
@@ -79,6 +79,8 @@ public final class ClientProfile {
|
||||
*/
|
||||
private Set<Integer> mShareFeClientIds = new HashSet<>();
|
||||
|
||||
private Set<Integer> mUsingDemuxHandles = new HashSet<>();
|
||||
|
||||
/**
|
||||
* List of the Lnb handles that are used by the current client.
|
||||
*/
|
||||
@@ -232,6 +234,31 @@ public final class ClientProfile {
|
||||
mPrimaryUsingFrontendHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set when the client starts to use a Demux.
|
||||
*
|
||||
* @param demuxHandle the demux being used.
|
||||
*/
|
||||
public void useDemux(int demuxHandle) {
|
||||
mUsingDemuxHandles.add(demuxHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of demux handles in use.
|
||||
*/
|
||||
public Set<Integer> getInUseDemuxHandles() {
|
||||
return mUsingDemuxHandles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the client released a Demux.
|
||||
*
|
||||
* @param demuxHandle the demux handl being released.
|
||||
*/
|
||||
public void releaseDemux(int demuxHandle) {
|
||||
mUsingDemuxHandles.remove(demuxHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set when the client starts to use an Lnb.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2022 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 com.android.server.tv.tunerresourcemanager;
|
||||
|
||||
/**
|
||||
* A demux resource object used by the Tuner Resource Manager to record the tuner Demux
|
||||
* information.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class DemuxResource extends TunerResourceBasic {
|
||||
|
||||
private final int mFilterTypes;
|
||||
|
||||
private DemuxResource(Builder builder) {
|
||||
super(builder);
|
||||
this.mFilterTypes = builder.mFilterTypes;
|
||||
}
|
||||
|
||||
public int getFilterTypes() {
|
||||
return mFilterTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DemuxResource[handle=" + this.mHandle + ", filterTypes="
|
||||
+ this.mFilterTypes + ", isInUse=" + this.mIsInUse
|
||||
+ ", ownerClientId=" + this.mOwnerClientId + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the desired {@link DemuxFilterMainTypes} is supported.
|
||||
*/
|
||||
public boolean hasSufficientCaps(int desiredCaps) {
|
||||
return desiredCaps == (desiredCaps & mFilterTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of supported {@link DemuxFilterMainTypes}.
|
||||
*/
|
||||
public int getNumOfCaps() {
|
||||
int mask = 1;
|
||||
int numOfCaps = 0;
|
||||
for (int i = 0; i < Integer.SIZE; i++) {
|
||||
if ((mFilterTypes & mask) == mask) {
|
||||
numOfCaps = numOfCaps + 1;
|
||||
}
|
||||
mask = mask << 1;
|
||||
}
|
||||
return numOfCaps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for {@link DemuxResource}.
|
||||
*/
|
||||
public static class Builder extends TunerResourceBasic.Builder {
|
||||
private int mFilterTypes;
|
||||
|
||||
Builder(int handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link DemuxResource}.
|
||||
*
|
||||
* @param filterTypes the supported {@link DemuxFilterMainTypes}
|
||||
*/
|
||||
public Builder filterTypes(int filterTypes) {
|
||||
this.mFilterTypes = filterTypes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a {@link DemuxResource}.
|
||||
*
|
||||
* @return {@link DemuxResource}.
|
||||
*/
|
||||
@Override
|
||||
public DemuxResource build() {
|
||||
DemuxResource demux = new DemuxResource(this);
|
||||
return demux;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.RunningAppProcessInfo;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.tv.tuner.DemuxFilterMainType;
|
||||
import android.media.IResourceManagerService;
|
||||
import android.media.tv.TvInputManager;
|
||||
import android.media.tv.tunerresourcemanager.CasSessionRequest;
|
||||
@@ -29,6 +30,7 @@ import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
|
||||
import android.media.tv.tunerresourcemanager.ITunerResourceManager;
|
||||
import android.media.tv.tunerresourcemanager.ResourceClientProfile;
|
||||
import android.media.tv.tunerresourcemanager.TunerCiCamRequest;
|
||||
import android.media.tv.tunerresourcemanager.TunerDemuxInfo;
|
||||
import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
|
||||
import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
|
||||
import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
|
||||
@@ -96,6 +98,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
private SparseIntArray mFrontendUsedNumsBackup = new SparseIntArray();
|
||||
private SparseIntArray mFrontendExistingNumsBackup = new SparseIntArray();
|
||||
|
||||
// Map of the current available demux resources
|
||||
private Map<Integer, DemuxResource> mDemuxResources = new HashMap<>();
|
||||
// Map of the current available lnb resources
|
||||
private Map<Integer, LnbResource> mLnbResources = new HashMap<>();
|
||||
// Map of the current available Cas resources
|
||||
@@ -248,6 +252,17 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDemuxInfoList(@NonNull TunerDemuxInfo[] infos) throws RemoteException {
|
||||
enforceTrmAccessPermission("setDemuxInfoList");
|
||||
if (infos == null) {
|
||||
throw new RemoteException("TunerDemuxInfo can't be null");
|
||||
}
|
||||
synchronized (mLock) {
|
||||
setDemuxInfoListInternal(infos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCasInfo(int casSystemId, int maxSessionNum) {
|
||||
enforceTrmAccessPermission("updateCasInfo");
|
||||
@@ -294,8 +309,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
|
||||
@Override
|
||||
public boolean setMaxNumberOfFrontends(int frontendType, int maxUsableNum) {
|
||||
enforceTunerAccessPermission("requestFrontend");
|
||||
enforceTrmAccessPermission("requestFrontend");
|
||||
enforceTunerAccessPermission("setMaxNumberOfFrontends");
|
||||
enforceTrmAccessPermission("setMaxNumberOfFrontends");
|
||||
if (maxUsableNum < 0) {
|
||||
Slog.w(TAG, "setMaxNumberOfFrontends failed with maxUsableNum:" + maxUsableNum
|
||||
+ " frontendType:" + frontendType);
|
||||
@@ -308,8 +323,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
|
||||
@Override
|
||||
public int getMaxNumberOfFrontends(int frontendType) {
|
||||
enforceTunerAccessPermission("requestFrontend");
|
||||
enforceTrmAccessPermission("requestFrontend");
|
||||
enforceTunerAccessPermission("getMaxNumberOfFrontends");
|
||||
enforceTrmAccessPermission("getMaxNumberOfFrontends");
|
||||
synchronized (mLock) {
|
||||
return getMaxNumberOfFrontendsInternal(frontendType);
|
||||
}
|
||||
@@ -466,11 +481,33 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseDemux(int demuxHandle, int clientId) {
|
||||
public void releaseDemux(int demuxHandle, int clientId) throws RemoteException {
|
||||
enforceTunerAccessPermission("releaseDemux");
|
||||
enforceTrmAccessPermission("releaseDemux");
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "releaseDemux(demuxHandle=" + demuxHandle + ")");
|
||||
Slog.e(TAG, "releaseDemux(demuxHandle=" + demuxHandle + ")");
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
// For Tuner 2.0 and below or any HW constraint devices that are unable to support
|
||||
// ITuner.openDemuxById(), demux resources are not really managed under TRM and
|
||||
// mDemuxResources.size() will be zero
|
||||
if (mDemuxResources.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!checkClientExists(clientId)) {
|
||||
throw new RemoteException("Release demux for unregistered client:" + clientId);
|
||||
}
|
||||
DemuxResource demux = getDemuxResource(demuxHandle);
|
||||
if (demux == null) {
|
||||
throw new RemoteException("Releasing demux does not exist.");
|
||||
}
|
||||
if (demux.getOwnerClientId() != clientId) {
|
||||
throw new RemoteException("Client is not the current owner "
|
||||
+ "of the releasing demux.");
|
||||
}
|
||||
releaseDemuxInternal(demux);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,6 +666,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
dumpSIA(mFrontendExistingNumsBackup, "FrontendExistingNumsBackup:", ", ", pw);
|
||||
dumpSIA(mFrontendUsedNumsBackup, "FrontendUsedNumsBackup:", ", ", pw);
|
||||
dumpSIA(mFrontendMaxUsableNumsBackup, "FrontendUsedNumsBackup:", ", ", pw);
|
||||
dumpMap(mDemuxResources, "DemuxResource:", "\n", pw);
|
||||
dumpMap(mLnbResources, "LnbResource:", "\n", pw);
|
||||
dumpMap(mCasResources, "CasResource:", "\n", pw);
|
||||
dumpMap(mCiCamResources, "CiCamResource:", "\n", pw);
|
||||
@@ -858,6 +896,41 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void setDemuxInfoListInternal(TunerDemuxInfo[] infos) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "updateDemuxInfo:");
|
||||
for (int i = 0; i < infos.length; i++) {
|
||||
Slog.d(TAG, infos[i].toString());
|
||||
}
|
||||
}
|
||||
|
||||
// A set to record the demuxes pending on updating. Ids will be removed
|
||||
// from this set once its updating finished. Any demux left in this set when all
|
||||
// the updates are done will be removed from mDemuxResources.
|
||||
Set<Integer> updatingDemuxHandles = new HashSet<>(getDemuxResources().keySet());
|
||||
|
||||
// Update demuxResources map and other mappings accordingly
|
||||
for (int i = 0; i < infos.length; i++) {
|
||||
if (getDemuxResource(infos[i].handle) != null) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Demux handle=" + infos[i].handle + "exists.");
|
||||
}
|
||||
updatingDemuxHandles.remove(infos[i].handle);
|
||||
} else {
|
||||
// Add a new demux resource
|
||||
DemuxResource newDemux = new DemuxResource.Builder(infos[i].handle)
|
||||
.filterTypes(infos[i].filterTypes)
|
||||
.build();
|
||||
addDemuxResource(newDemux);
|
||||
}
|
||||
}
|
||||
|
||||
for (int removingHandle : updatingDemuxHandles) {
|
||||
// update the exclusive group id member list
|
||||
removeDemuxResource(removingHandle);
|
||||
}
|
||||
}
|
||||
@VisibleForTesting
|
||||
protected void setLnbInfoListInternal(int[] lnbHandles) {
|
||||
if (DEBUG) {
|
||||
@@ -1291,6 +1364,14 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
clearFrontendAndClientMapping(getClientProfile(clientId));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void releaseDemuxInternal(DemuxResource demux) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "releaseDemux(DemuxHandle=" + demux.getHandle() + ")");
|
||||
}
|
||||
updateDemuxClientMappingOnRelease(demux);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void releaseLnbInternal(LnbResource lnb) {
|
||||
if (DEBUG) {
|
||||
@@ -1320,9 +1401,91 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "requestDemux(request=" + request + ")");
|
||||
}
|
||||
// There are enough Demux resources, so we don't manage Demux in R.
|
||||
demuxHandle[0] = generateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX, 0);
|
||||
return true;
|
||||
|
||||
// For Tuner 2.0 and below or any HW constraint devices that are unable to support
|
||||
// ITuner.openDemuxById(), demux resources are not really managed under TRM and
|
||||
// mDemuxResources.size() will be zero
|
||||
if (mDemuxResources.size() == 0) {
|
||||
// There are enough Demux resources, so we don't manage Demux in R.
|
||||
demuxHandle[0] =
|
||||
generateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
demuxHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
|
||||
ClientProfile requestClient = getClientProfile(request.clientId);
|
||||
|
||||
if (requestClient == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
clientPriorityUpdateOnRequest(requestClient);
|
||||
int grantingDemuxHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
|
||||
int inUseLowestPriorityDrHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
|
||||
// Priority max value is 1000
|
||||
int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
|
||||
// If the desired demux id was specified, we only need to check the demux.
|
||||
boolean hasDesiredDemuxCap = request.desiredFilterTypes
|
||||
!= DemuxFilterMainType.UNDEFINED;
|
||||
int smallestNumOfSupportedCaps = Integer.SIZE + 1;
|
||||
for (DemuxResource dr : getDemuxResources().values()) {
|
||||
if (!hasDesiredDemuxCap || dr.hasSufficientCaps(request.desiredFilterTypes)) {
|
||||
if (!dr.isInUse()) {
|
||||
int numOfSupportedCaps = dr.getNumOfCaps();
|
||||
|
||||
// look for the demux with minimum caps supporting the desired caps
|
||||
if (smallestNumOfSupportedCaps > numOfSupportedCaps) {
|
||||
smallestNumOfSupportedCaps = numOfSupportedCaps;
|
||||
grantingDemuxHandle = dr.getHandle();
|
||||
}
|
||||
} else if (grantingDemuxHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
|
||||
// Record the demux id with the lowest client priority among all the
|
||||
// in use demuxes when no availabledemux has been found.
|
||||
int priority = updateAndGetOwnerClientPriority(dr.getOwnerClientId());
|
||||
if (currentLowestPriority >= priority) {
|
||||
int numOfSupportedCaps = dr.getNumOfCaps();
|
||||
boolean shouldUpdate = false;
|
||||
// update lowest priority
|
||||
if (currentLowestPriority > priority) {
|
||||
currentLowestPriority = priority;
|
||||
shouldUpdate = true;
|
||||
}
|
||||
// update smallest caps
|
||||
if (smallestNumOfSupportedCaps > numOfSupportedCaps) {
|
||||
smallestNumOfSupportedCaps = numOfSupportedCaps;
|
||||
shouldUpdate = true;
|
||||
}
|
||||
if (shouldUpdate) {
|
||||
inUseLowestPriorityDrHandle = dr.getHandle();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Grant demux when there is unused resource.
|
||||
if (grantingDemuxHandle != TunerResourceManager.INVALID_RESOURCE_HANDLE) {
|
||||
demuxHandle[0] = grantingDemuxHandle;
|
||||
updateDemuxClientMappingOnNewGrant(grantingDemuxHandle, request.clientId);
|
||||
return true;
|
||||
}
|
||||
|
||||
// When all the resources are occupied, grant the lowest priority resource if the
|
||||
// request client has higher priority.
|
||||
if (inUseLowestPriorityDrHandle != TunerResourceManager.INVALID_RESOURCE_HANDLE
|
||||
&& (requestClient.getPriority() > currentLowestPriority)) {
|
||||
if (!reclaimResource(
|
||||
getDemuxResource(inUseLowestPriorityDrHandle).getOwnerClientId(),
|
||||
TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX)) {
|
||||
return false;
|
||||
}
|
||||
demuxHandle[0] = inUseLowestPriorityDrHandle;
|
||||
updateDemuxClientMappingOnNewGrant(
|
||||
inUseLowestPriorityDrHandle, request.clientId);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -1673,6 +1836,21 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
ownerProfile.setPrimaryFrontend(grantingHandle);
|
||||
}
|
||||
|
||||
private void updateDemuxClientMappingOnNewGrant(int grantingHandle, int ownerClientId) {
|
||||
DemuxResource grantingDemux = getDemuxResource(grantingHandle);
|
||||
if (grantingDemux != null) {
|
||||
ClientProfile ownerProfile = getClientProfile(ownerClientId);
|
||||
grantingDemux.setOwner(ownerClientId);
|
||||
ownerProfile.useDemux(grantingHandle);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDemuxClientMappingOnRelease(@NonNull DemuxResource releasingDemux) {
|
||||
ClientProfile ownerProfile = getClientProfile(releasingDemux.getOwnerClientId());
|
||||
releasingDemux.removeOwner();
|
||||
ownerProfile.releaseDemux(releasingDemux.getHandle());
|
||||
}
|
||||
|
||||
private void updateLnbClientMappingOnNewGrant(int grantingHandle, int ownerClientId) {
|
||||
LnbResource grantingLnb = getLnbResource(grantingHandle);
|
||||
ClientProfile ownerProfile = getClientProfile(ownerClientId);
|
||||
@@ -1764,6 +1942,17 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
return mFrontendResources;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
protected DemuxResource getDemuxResource(int demuxHandle) {
|
||||
return mDemuxResources.get(demuxHandle);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected Map<Integer, DemuxResource> getDemuxResources() {
|
||||
return mDemuxResources;
|
||||
}
|
||||
|
||||
private boolean setMaxNumberOfFrontendsInternal(int frontendType, int maxUsableNum) {
|
||||
int usedNum = mFrontendUsedNums.get(frontendType, INVALID_FE_COUNT);
|
||||
if (usedNum == INVALID_FE_COUNT || usedNum <= maxUsableNum) {
|
||||
@@ -1887,6 +2076,10 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
|
||||
}
|
||||
|
||||
private void addDemuxResource(DemuxResource newDemux) {
|
||||
mDemuxResources.put(newDemux.getHandle(), newDemux);
|
||||
}
|
||||
|
||||
private void removeFrontendResource(int removingHandle) {
|
||||
FrontendResource fe = getFrontendResource(removingHandle);
|
||||
if (fe == null) {
|
||||
@@ -1907,6 +2100,17 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
mFrontendResources.remove(removingHandle);
|
||||
}
|
||||
|
||||
private void removeDemuxResource(int removingHandle) {
|
||||
DemuxResource demux = getDemuxResource(removingHandle);
|
||||
if (demux == null) {
|
||||
return;
|
||||
}
|
||||
if (demux.isInUse()) {
|
||||
releaseDemuxInternal(demux);
|
||||
}
|
||||
mDemuxResources.remove(removingHandle);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
protected LnbResource getLnbResource(int lnbHandle) {
|
||||
@@ -2062,6 +2266,10 @@ public class TunerResourceManagerService extends SystemService implements IBinde
|
||||
if (profile.getInUseCiCamId() != ClientProfile.INVALID_RESOURCE_ID) {
|
||||
getCiCamResource(profile.getInUseCiCamId()).removeOwner(profile.getId());
|
||||
}
|
||||
// Clear Demux
|
||||
for (Integer demuxHandle : profile.getInUseDemuxHandles()) {
|
||||
getDemuxResource(demuxHandle).removeOwner();
|
||||
}
|
||||
// Clear Frontend
|
||||
clearFrontendAndClientMapping(profile);
|
||||
profile.reclaimAllResources();
|
||||
|
||||
@@ -25,11 +25,13 @@ import android.content.ContextWrapper;
|
||||
import android.media.tv.ITvInputManager;
|
||||
import android.media.tv.TvInputManager;
|
||||
import android.media.tv.TvInputService;
|
||||
import android.media.tv.tuner.filter.Filter;
|
||||
import android.media.tv.tuner.frontend.FrontendSettings;
|
||||
import android.media.tv.tunerresourcemanager.CasSessionRequest;
|
||||
import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
|
||||
import android.media.tv.tunerresourcemanager.ResourceClientProfile;
|
||||
import android.media.tv.tunerresourcemanager.TunerCiCamRequest;
|
||||
import android.media.tv.tunerresourcemanager.TunerDemuxInfo;
|
||||
import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
|
||||
import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
|
||||
import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
|
||||
@@ -806,20 +808,137 @@ public class TunerResourceManagerServiceTest {
|
||||
@Test
|
||||
public void requestDemuxTest() {
|
||||
// Register client
|
||||
ResourceClientProfile profile = resourceClientProfile("0" /*sessionId*/,
|
||||
ResourceClientProfile profile0 = resourceClientProfile("0" /*sessionId*/,
|
||||
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
|
||||
int[] clientId = new int[1];
|
||||
ResourceClientProfile profile1 = resourceClientProfile("1" /*sessionId*/,
|
||||
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
|
||||
int[] clientId0 = new int[1];
|
||||
mTunerResourceManagerService.registerClientProfileInternal(
|
||||
profile, null /*listener*/, clientId);
|
||||
assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||
profile0, null /*listener*/, clientId0);
|
||||
assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||
|
||||
int[] demuxHandle = new int[1];
|
||||
TunerDemuxRequest request = new TunerDemuxRequest();
|
||||
request.clientId = clientId[0];
|
||||
assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle))
|
||||
TunerDemuxInfo[] infos = new TunerDemuxInfo[3];
|
||||
infos[0] = tunerDemuxInfo(0 /* handle */, Filter.TYPE_TS | Filter.TYPE_IP);
|
||||
infos[1] = tunerDemuxInfo(1 /* handle */, Filter.TYPE_TLV);
|
||||
infos[2] = tunerDemuxInfo(2 /* handle */, Filter.TYPE_TS);
|
||||
mTunerResourceManagerService.setDemuxInfoListInternal(infos);
|
||||
|
||||
int[] demuxHandle0 = new int[1];
|
||||
// first with undefined type (should be the first one with least # of caps)
|
||||
TunerDemuxRequest request = tunerDemuxRequest(clientId0[0], Filter.TYPE_UNDEFINED);
|
||||
assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle0))
|
||||
.isTrue();
|
||||
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(demuxHandle[0]))
|
||||
assertThat(demuxHandle0[0]).isEqualTo(1);
|
||||
DemuxResource dr = mTunerResourceManagerService.getDemuxResource(demuxHandle0[0]);
|
||||
mTunerResourceManagerService.releaseDemuxInternal(dr);
|
||||
|
||||
// now with non-supported type (ALP)
|
||||
request.desiredFilterTypes = Filter.TYPE_ALP;
|
||||
demuxHandle0[0] = -1;
|
||||
assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle0))
|
||||
.isFalse();
|
||||
assertThat(demuxHandle0[0]).isEqualTo(-1);
|
||||
|
||||
// now with TS (should be the one with least # of caps that supports TS)
|
||||
request.desiredFilterTypes = Filter.TYPE_TS;
|
||||
assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle0))
|
||||
.isTrue();
|
||||
assertThat(demuxHandle0[0]).isEqualTo(2);
|
||||
|
||||
// request for another TS
|
||||
int[] clientId1 = new int[1];
|
||||
mTunerResourceManagerService.registerClientProfileInternal(
|
||||
profile1, null /*listener*/, clientId1);
|
||||
assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||
int[] demuxHandle1 = new int[1];
|
||||
TunerDemuxRequest request1 = tunerDemuxRequest(clientId1[0], Filter.TYPE_TS);
|
||||
assertThat(mTunerResourceManagerService.requestDemuxInternal(request1, demuxHandle1))
|
||||
.isTrue();
|
||||
assertThat(demuxHandle1[0]).isEqualTo(0);
|
||||
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(demuxHandle1[0]))
|
||||
.isEqualTo(0);
|
||||
|
||||
// release demuxes
|
||||
dr = mTunerResourceManagerService.getDemuxResource(demuxHandle0[0]);
|
||||
mTunerResourceManagerService.releaseDemuxInternal(dr);
|
||||
dr = mTunerResourceManagerService.getDemuxResource(demuxHandle1[0]);
|
||||
mTunerResourceManagerService.releaseDemuxInternal(dr);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestDemuxTest_ResourceReclaim() {
|
||||
// Register clients
|
||||
ResourceClientProfile profile0 = resourceClientProfile("0" /*sessionId*/,
|
||||
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
|
||||
ResourceClientProfile profile1 = resourceClientProfile("1" /*sessionId*/,
|
||||
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN);
|
||||
ResourceClientProfile profile2 = resourceClientProfile("2" /*sessionId*/,
|
||||
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN);
|
||||
int[] clientId0 = new int[1];
|
||||
int[] clientId1 = new int[1];
|
||||
int[] clientId2 = new int[1];
|
||||
TestResourcesReclaimListener listener0 = new TestResourcesReclaimListener();
|
||||
TestResourcesReclaimListener listener1 = new TestResourcesReclaimListener();
|
||||
TestResourcesReclaimListener listener2 = new TestResourcesReclaimListener();
|
||||
|
||||
mTunerResourceManagerService.registerClientProfileInternal(
|
||||
profile0, listener0, clientId0);
|
||||
assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||
mTunerResourceManagerService.registerClientProfileInternal(
|
||||
profile1, listener1, clientId1);
|
||||
assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||
mTunerResourceManagerService.registerClientProfileInternal(
|
||||
profile2, listener2, clientId1);
|
||||
assertThat(clientId2[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||
|
||||
// Init demux resources.
|
||||
TunerDemuxInfo[] infos = new TunerDemuxInfo[2];
|
||||
infos[0] = tunerDemuxInfo(0 /*handle*/, Filter.TYPE_TS | Filter.TYPE_IP);
|
||||
infos[1] = tunerDemuxInfo(1 /*handle*/, Filter.TYPE_TS);
|
||||
mTunerResourceManagerService.setDemuxInfoListInternal(infos);
|
||||
|
||||
// let clientId0(prio:100) request for IP - should succeed
|
||||
TunerDemuxRequest request0 = tunerDemuxRequest(clientId0[0], Filter.TYPE_IP);
|
||||
int[] demuxHandle0 = new int[1];
|
||||
assertThat(mTunerResourceManagerService
|
||||
.requestDemuxInternal(request0, demuxHandle0)).isTrue();
|
||||
assertThat(demuxHandle0[0]).isEqualTo(0);
|
||||
|
||||
// let clientId1(prio:50) request for IP - should fail
|
||||
TunerDemuxRequest request1 = tunerDemuxRequest(clientId1[0], Filter.TYPE_IP);
|
||||
int[] demuxHandle1 = new int[1];
|
||||
demuxHandle1[0] = -1;
|
||||
assertThat(mTunerResourceManagerService
|
||||
.requestDemuxInternal(request1, demuxHandle1)).isFalse();
|
||||
assertThat(listener0.isReclaimed()).isFalse();
|
||||
assertThat(demuxHandle1[0]).isEqualTo(-1);
|
||||
|
||||
// let clientId1(prio:50) request for TS - should succeed
|
||||
request1.desiredFilterTypes = Filter.TYPE_TS;
|
||||
assertThat(mTunerResourceManagerService
|
||||
.requestDemuxInternal(request1, demuxHandle1)).isTrue();
|
||||
assertThat(demuxHandle1[0]).isEqualTo(1);
|
||||
assertThat(listener0.isReclaimed()).isFalse();
|
||||
|
||||
// now release demux for the clientId0 (higher priority) and request demux
|
||||
DemuxResource dr = mTunerResourceManagerService.getDemuxResource(demuxHandle0[0]);
|
||||
mTunerResourceManagerService.releaseDemuxInternal(dr);
|
||||
|
||||
// let clientId2(prio:50) request for TS - should succeed
|
||||
TunerDemuxRequest request2 = tunerDemuxRequest(clientId2[0], Filter.TYPE_TS);
|
||||
int[] demuxHandle2 = new int[1];
|
||||
assertThat(mTunerResourceManagerService
|
||||
.requestDemuxInternal(request2, demuxHandle2)).isTrue();
|
||||
assertThat(demuxHandle2[0]).isEqualTo(0);
|
||||
assertThat(listener1.isReclaimed()).isFalse();
|
||||
|
||||
// let clientId0(prio:100) request for TS - should reclaim from clientId2
|
||||
// , who has the smaller caps
|
||||
request0.desiredFilterTypes = Filter.TYPE_TS;
|
||||
assertThat(mTunerResourceManagerService
|
||||
.requestDemuxInternal(request0, demuxHandle0)).isTrue();
|
||||
assertThat(listener1.isReclaimed()).isFalse();
|
||||
assertThat(listener2.isReclaimed()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1188,4 +1307,18 @@ public class TunerResourceManagerServiceTest {
|
||||
request.ciCamId = ciCamId;
|
||||
return request;
|
||||
}
|
||||
|
||||
private TunerDemuxInfo tunerDemuxInfo(int handle, int supportedFilterTypes) {
|
||||
TunerDemuxInfo info = new TunerDemuxInfo();
|
||||
info.handle = handle;
|
||||
info.filterTypes = supportedFilterTypes;
|
||||
return info;
|
||||
}
|
||||
|
||||
private TunerDemuxRequest tunerDemuxRequest(int clientId, int desiredFilterTypes) {
|
||||
TunerDemuxRequest request = new TunerDemuxRequest();
|
||||
request.clientId = clientId;
|
||||
request.desiredFilterTypes = desiredFilterTypes;
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user