Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 318fe684 authored by Kensuke Miyagi's avatar Kensuke Miyagi
Browse files

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
parent 613dc260
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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();
+31 −4
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
/*
 * 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;
    }
}
+166 −19
Original line number Diff line number Diff line
@@ -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];
+17 −0
Original line number Diff line number Diff line
@@ -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.
     *
Loading