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

Commit f7d063c3 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Enable capability based demux management"

parents 270ae216 318fe684
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -7503,6 +7503,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();
@@ -7515,6 +7516,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();
@@ -7567,6 +7574,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();
@@ -7574,6 +7582,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