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

Commit a3172500 authored by Santiago Seifert's avatar Santiago Seifert
Browse files

Publish MR2 system media session APIs

Also, pass parameters in a dedicated Params class, to enable future
extensibility without adding overloads, which will presumably be needed
for video.

Bug: b/362507305
Test: atest CtsMediaBetterTogetherTestCases:android.media.router.cts.SystemMediaRoutingTest
Flag: com.android.media.flags.enable_mirroring_in_media_router_2
Change-Id: I0936feefb4c92fe46212ad6bd71ed2b544286cbd
parent 36fe7e72
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -25038,8 +25038,10 @@ package android.media {
    method public final void notifySessionCreated(long, @NonNull android.media.RoutingSessionInfo);
    method public final void notifySessionReleased(@NonNull String);
    method public final void notifySessionUpdated(@NonNull android.media.RoutingSessionInfo);
    method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") @Nullable @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public final android.media.MediaRoute2ProviderService.MediaStreams notifySystemRoutingSessionCreated(long, @NonNull android.media.RoutingSessionInfo, @NonNull android.media.MediaRoute2ProviderService.MediaStreamsFormats);
    method @CallSuper @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
    method public abstract void onCreateSession(long, @NonNull String, @NonNull String, @Nullable android.os.Bundle);
    method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public void onCreateSystemRoutingSession(long, @NonNull String, @NonNull android.media.MediaRoute2ProviderService.SystemRoutingSessionParams);
    method public abstract void onDeselectRoute(long, @NonNull String, @NonNull String);
    method public void onDiscoveryPreferenceChanged(@NonNull android.media.RouteDiscoveryPreference);
    method public abstract void onReleaseSession(long, @NonNull String);
@@ -25047,15 +25049,44 @@ package android.media {
    method public abstract void onSetRouteVolume(long, @NonNull String, int);
    method public abstract void onSetSessionVolume(long, @NonNull String, int);
    method public abstract void onTransferToRoute(long, @NonNull String, @NonNull String);
    field @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final String CATEGORY_SYSTEM_MEDIA = "android.media.MediaRoute2ProviderService.SYSTEM_MEDIA";
    field @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final int REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA = 6; // 0x6
    field public static final int REASON_INVALID_COMMAND = 4; // 0x4
    field public static final int REASON_NETWORK_ERROR = 2; // 0x2
    field public static final int REASON_REJECTED = 1; // 0x1
    field public static final int REASON_ROUTE_NOT_AVAILABLE = 3; // 0x3
    field @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final int REASON_UNIMPLEMENTED = 5; // 0x5
    field public static final int REASON_UNKNOWN_ERROR = 0; // 0x0
    field public static final long REQUEST_ID_NONE = 0L; // 0x0L
    field public static final String SERVICE_INTERFACE = "android.media.MediaRoute2ProviderService";
  }
  @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final class MediaRoute2ProviderService.MediaStreams {
    method @Nullable public android.media.AudioRecord getAudioRecord();
  }
  @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final class MediaRoute2ProviderService.MediaStreamsFormats {
    method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") @Nullable public android.media.AudioFormat getAudioFormat();
  }
  @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final class MediaRoute2ProviderService.MediaStreamsFormats.Builder {
    ctor public MediaRoute2ProviderService.MediaStreamsFormats.Builder();
    method @NonNull public android.media.MediaRoute2ProviderService.MediaStreamsFormats build();
    method @NonNull public android.media.MediaRoute2ProviderService.MediaStreamsFormats.Builder setAudioFormat(@NonNull android.media.AudioFormat);
  }
  @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public static final class MediaRoute2ProviderService.SystemRoutingSessionParams {
    method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") @NonNull public android.os.Bundle getExtras();
    method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") @NonNull public String getPackageName();
  }
  public static final class MediaRoute2ProviderService.SystemRoutingSessionParams.Builder {
    ctor public MediaRoute2ProviderService.SystemRoutingSessionParams.Builder();
    method @NonNull public android.media.MediaRoute2ProviderService.SystemRoutingSessionParams build();
    method @NonNull public android.media.MediaRoute2ProviderService.SystemRoutingSessionParams.Builder setExtras(@NonNull android.os.Bundle);
    method @NonNull public android.media.MediaRoute2ProviderService.SystemRoutingSessionParams.Builder setPackageName(@NonNull String);
  }
  public class MediaRouter {
    method public void addCallback(int, android.media.MediaRouter.Callback);
    method public void addCallback(int, android.media.MediaRouter.Callback, int);
+116 −51
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;

/**
@@ -96,12 +97,10 @@ public abstract class MediaRoute2ProviderService extends Service {
     * system media, as described by {@link MediaRoute2Info#getSupportedRoutingTypes()}.
     *
     * @see #onCreateSystemRoutingSession
     * @hide
     */
    // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
    @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
    @SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY)
    public static final String SERVICE_INTERFACE_SYSTEM_MEDIA =
    public static final String CATEGORY_SYSTEM_MEDIA =
            "android.media.MediaRoute2ProviderService.SYSTEM_MEDIA";

    /**
@@ -165,9 +164,7 @@ public abstract class MediaRoute2ProviderService extends Service {
     * The request has failed because the requested operation is not implemented by the provider.
     *
     * @see #notifyRequestFailed
     * @hide
     */
    // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
    @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
    public static final int REASON_UNIMPLEMENTED = 5;

@@ -175,9 +172,7 @@ public abstract class MediaRoute2ProviderService extends Service {
     * The request has failed because the provider has failed to route system media.
     *
     * @see #notifyRequestFailed
     * @hide
     */
    // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
    @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
    public static final int REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA = 6;

@@ -217,7 +212,7 @@ public abstract class MediaRoute2ProviderService extends Service {
     * package (for example, if they affect the entire system).
     */
    @GuardedBy("mRequestIdsLock")
    private final LongSparseArray<Integer> mSystemMediaSessionCreationRequests =
    private final LongSparseArray<Integer> mSystemRoutingSessionCreationRequests =
            new LongSparseArray<>();

    @GuardedBy("mSessionLock")
@@ -350,7 +345,7 @@ public abstract class MediaRoute2ProviderService extends Service {
    /**
     * Notifies the system of the successful creation of a system media routing session.
     *
     * <p>This method can only be called as the result of a prior call to {@link
     * <p>This method must only be called as the result of a prior call to {@link
     * #onCreateSystemRoutingSession}.
     *
     * @param requestId the ID of the {@link #onCreateSystemRoutingSession} request which this call
@@ -365,13 +360,13 @@ public abstract class MediaRoute2ProviderService extends Service {
     *     where you can clean up this session. {@link AudioRecord#startRecording()} must be called
     *     immediately on {@link MediaStreams#getAudioRecord()} after calling this method, in order
     *     to start streaming audio to the receiver.
     * @hide
     * @throws IllegalStateException If the provided {@code requestId} doesn't correspond to a
     *     previous call to {@link #onCreateSystemRoutingSession}.
     */
    // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
    @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
    @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
    @Nullable
    public final MediaStreams notifySystemMediaSessionCreated(
    public final MediaStreams notifySystemRoutingSessionCreated(
            long requestId,
            @NonNull RoutingSessionInfo sessionInfo,
            @NonNull MediaStreamsFormats formats) {
@@ -380,7 +375,7 @@ public abstract class MediaRoute2ProviderService extends Service {
        if (DEBUG) {
            Log.d(
                    TAG,
                    "notifySystemMediaSessionCreated: Creating a session. requestId="
                    "notifySystemRoutingSessionCreated: Creating a session. requestId="
                            + requestId
                            + ", sessionInfo="
                            + sessionInfo);
@@ -388,8 +383,8 @@ public abstract class MediaRoute2ProviderService extends Service {

        Integer uid;
        synchronized (mRequestIdsLock) {
            uid = mSystemMediaSessionCreationRequests.get(requestId);
            mSystemMediaSessionCreationRequests.remove(requestId);
            uid = mSystemRoutingSessionCreationRequests.get(requestId);
            mSystemRoutingSessionCreationRequests.remove(requestId);
        }

        if (uid == null) {
@@ -656,37 +651,34 @@ public abstract class MediaRoute2ProviderService extends Service {
    /**
     * Called when the service receives a request to create a system routing session.
     *
     * <p>This method will only be called for routes that support routing of the system media, as
     * described by {@link MediaRoute2Info#getSupportedRoutingTypes()}.
     * <p>This method must be overridden by subclasses that support routes that support routing
     * {@link MediaRoute2Info#getSupportedRoutingTypes() system media}. The provided {@code routeId}
     * will always correspond to a route that supports routing of the system media, as per {@link
     * MediaRoute2Info#getSupportedRoutingTypes()}.
     *
     * <p>Implementors of this method must call {@link #notifySystemMediaSessionCreated} with the
     * <p>Implementors of this method must call {@link #notifySystemRoutingSessionCreated} with the
     * given {@code requestId} to indicate a successful session creation. If the session creation
     * fails (for example, if the connection to the receiver device fails), the implementor must
     * call {@link #notifyRequestFailed}, passing the {@code requestId}.
     *
     * <p>Unlike {@link #onCreateSession}, system sessions route the system media (for example,
     * audio and/or video) which is to be retrieved by calling {@link
     * #notifySystemMediaSessionCreated}.
     * #notifySystemRoutingSessionCreated}.
     *
     * <p>Changes to the session can be notified by calling {@link #notifySessionUpdated}.
     *
     * @param requestId the ID of this request
     * @param packageName the package name of the application whose media to route.
     * @param routeId the ID of the route initially being {@link
     *     RoutingSessionInfo#getSelectedRoutes() selected}.
     * @param sessionHints an optional bundle of arguments sent by {@link MediaRouter2}, or null if
     *     none.
     * @param parameters {@link SystemRoutingSessionParams} for the session creation.
     * @see RoutingSessionInfo.Builder
     * @see #notifySystemMediaSessionCreated
     * @hide
     * @see #notifySystemRoutingSessionCreated
     */
    // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
    @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
    public void onCreateSystemRoutingSession(
            long requestId,
            @NonNull String packageName,
            @NonNull String routeId,
            @Nullable Bundle sessionHints) {
            @NonNull SystemRoutingSessionParams parameters) {
        mHandler.post(() -> notifyRequestFailed(requestId, REASON_UNIMPLEMENTED));
    }

@@ -974,24 +966,29 @@ public abstract class MediaRoute2ProviderService extends Service {
                int uid,
                String packageName,
                String routeId,
                @Nullable Bundle sessionHints) {
            if (!checkCallerIsSystem()) {
                @Nullable Bundle extras) {
            if (!Flags.enableMirroringInMediaRouter2() || !checkCallerIsSystem()) {
                return;
            }
            if (!checkRouteIdIsValid(routeId, "requestCreateSession")) {
                return;
            }
            synchronized (mRequestIdsLock) {
                mSystemMediaSessionCreationRequests.put(requestId, uid);
                mSystemRoutingSessionCreationRequests.put(requestId, uid);
            }
            var sessionParamsBuilder =
                    new SystemRoutingSessionParams.Builder().setPackageName(packageName);
            if (extras != null) {
                sessionParamsBuilder.setExtras(extras);
            }
            var sessionParams = sessionParamsBuilder.build();
            mHandler.sendMessage(
                    obtainMessage(
                            MediaRoute2ProviderService::onCreateSystemRoutingSession,
                            MediaRoute2ProviderService.this,
                            requestId,
                            packageName,
                            routeId,
                            sessionHints));
                            sessionParams));
        }

        @Override
@@ -1072,14 +1069,12 @@ public abstract class MediaRoute2ProviderService extends Service {
    }

    /**
     * Holds the streams to be routed as part of a system media routing session.
     *
     * <p>The encoded data format matches the {@link MediaStreamsFormats} passed to {@link
     * #notifySystemMediaSessionCreated}.
     * Holds the streams to be routed as part of a {@link #onCreateSystemRoutingSession system media
     * routing session}.
     *
     * @hide
     * <p>The encoded data format will match the {@link MediaStreamsFormats} passed to {@link
     * #notifySystemRoutingSessionCreated}.
     */
    // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
    @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
    public static final class MediaStreams {

@@ -1088,8 +1083,6 @@ public abstract class MediaRoute2ProviderService extends Service {

        /**
         * Holds the last {@link RoutingSessionInfo} associated with these streams.
         *
         * @hide
         */
        @NonNull
        // Access guarded by mSessionsLock, but it's not convenient to enforce through @GuardedBy.
@@ -1147,15 +1140,91 @@ public abstract class MediaRoute2ProviderService extends Service {
        }
    }

    /**
     * Holds parameters associated with a {@link #onCreateSystemRoutingSession session creation
     * request}.
     */
    @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
    public static final class SystemRoutingSessionParams {

        private final String mPackageName;
        private final Bundle mExtras;

        private SystemRoutingSessionParams(Builder builder) {
            this.mPackageName = builder.mPackageName;
            this.mExtras = builder.mExtras;
        }

        /**
         * Returns the name of the package associated with the session, or an empty string if not
         * applicable.
         *
         * <p>The package name is not applicable if the session is not associated with a specific
         * package, for example is the session affects the entire system.
         */
        @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
        @NonNull
        public String getPackageName() {
            return mPackageName;
        }

        /** Returns a bundle provided by the client that triggered the session creation request. */
        @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
        @NonNull
        public Bundle getExtras() {
            return mExtras;
        }

        /** A builder for {@link SystemRoutingSessionParams}. */
        public static final class Builder {
            private String mPackageName;
            private Bundle mExtras;

            /** Constructor. */
            public Builder() {
                mPackageName = "";
                mExtras = Bundle.EMPTY;
            }

            /**
             * Sets the {@link #getExtras() extras}.
             *
             * <p>The default value is an empty {@link Bundle}.
             *
             * <p>Note that this bundle is not copied, so avoiding mutating the given {@link Bundle}
             * after passing it to this method.
             */
            @NonNull
            public Builder setExtras(@NonNull Bundle extras) {
                mExtras = Objects.requireNonNull(extras);
                return this;
            }

            /**
             * Sets the {@link #getPackageName()}.
             *
             * <p>The default value is an empty string.
             */
            @NonNull
            public Builder setPackageName(@NonNull String packageName) {
                mPackageName = Objects.requireNonNull(packageName);
                return this;
            }

            /** Returns a new {@link SystemRoutingSessionParams} instance. */
            @NonNull
            public SystemRoutingSessionParams build() {
                return new SystemRoutingSessionParams(this);
            }
        }
    }

    /**
     * Holds the formats to encode media data to be read from {@link MediaStreams}.
     *
     * @see MediaStreams
     * @see #notifySystemMediaSessionCreated
     * @hide
     * @see #notifySystemRoutingSessionCreated
     */
    // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
    @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
    public static final class MediaStreamsFormats {

@@ -1169,29 +1238,25 @@ public abstract class MediaRoute2ProviderService extends Service {

        /**
         * Returns the audio format to use for creating the {@link MediaStreams#getAudioRecord} to
         * return from {@link #notifySystemMediaSessionCreated}.
         *
         * @hide
         * return from {@link #notifySystemRoutingSessionCreated}. May be null if the session
         * doesn't support system audio.
         */
        // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
        @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
        @Nullable
        public AudioFormat getAudioFormat() {
            return mAudioFormat;
        }

        /**
         * Builder for {@link MediaStreamsFormats}
         *
         * @hide
         */
        // TODO: b/362507305 - Unhide once the implementation and CTS are in place.
        @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2)
        public static final class Builder {
            private AudioFormat mAudioFormat;

            /**
             * Sets the audio format to use for creating the {@link MediaStreams#getAudioRecord} to
             * return from {@link #notifySystemMediaSessionCreated}.
             * return from {@link #notifySystemRoutingSessionCreated}.
             *
             * @param audioFormat the audio format
             * @return this builder
+1 −2
Original line number Diff line number Diff line
@@ -141,8 +141,7 @@ final class MediaRoute2ProviderWatcher {
                        isSelfScanOnlyProvider |=
                                MediaRoute2ProviderService.CATEGORY_SELF_SCAN_ONLY.equals(category);
                        supportsSystemMediaRouting |=
                                MediaRoute2ProviderService.SERVICE_INTERFACE_SYSTEM_MEDIA.equals(
                                        category);
                                MediaRoute2ProviderService.CATEGORY_SYSTEM_MEDIA.equals(category);
                    }
                }
                int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);