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

Commit 802818fa authored by Alexandr Shabalin's avatar Alexandr Shabalin Committed by Android (Google) Code Review
Browse files

Merge "Revert "[OutputSwitcher] Support select and deselect Le Audio devices...

Merge "Revert "[OutputSwitcher] Support select and deselect Le Audio devices for Le Audio Sharing"" into main
parents f0f63541 382bb281
Loading
Loading
Loading
Loading
+14 −98
Original line number Diff line number Diff line
@@ -47,7 +47,6 @@ import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.server.media.BluetoothRouteController.NoOpBluetoothRouteController;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -117,7 +116,7 @@ import java.util.concurrent.CopyOnWriteArrayList;

    @GuardedBy("this")
    @NonNull
    private final List<MediaRoute2Info> mSelectedRoutes = new ArrayList<>();
    private MediaRoute2Info mSelectedRoute;

    // A singleton AudioManagerRouteController.
    private static AudioManagerRouteController mInstance;
@@ -244,27 +243,10 @@ import java.util.concurrent.CopyOnWriteArrayList;
        // TODO(b/385672684): impl release system session
    }

    @RequiresPermission(
            anyOf = {
                Manifest.permission.MODIFY_AUDIO_ROUTING,
                Manifest.permission.QUERY_AUDIO_STATE
            })
    @Override
    public int getAudioDeviceType() {
        List<AudioDeviceAttributes> audioDevices =
                mAudioManager.getDevicesForAttributes(
                        new AudioAttributes.Builder()
                                .setUsage(AudioAttributes.USAGE_MEDIA)
                                .build());
        return audioDevices.isEmpty()
                ? AudioDeviceInfo.TYPE_UNKNOWN
                : audioDevices.getFirst().getType();
    }

    @Override
    @NonNull
    public synchronized List<MediaRoute2Info> getSelectedRoutes() {
        return mSelectedRoutes;
    public synchronized MediaRoute2Info getSelectedRoute() {
        return mSelectedRoute;
    }

    @Override
@@ -314,39 +296,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
        mHandler.post(guardedTransferAction);
    }

    @Override
    public void selectRoute(String routeId) {
        if (isBroadcasting()) {
            // Currently we do not allow selecting route when already broadcasting,
            // Ui should block user from select route as well.
            Slog.e(TAG, "Unable to select route: already broadcasting");
            return;
        }

        // Construct the list of routeIds
        List<String> routeIdListForBroadcast =
                new ArrayList<>(getSelectedRoutes().stream().map(MediaRoute2Info::getId).toList());
        routeIdListForBroadcast.add(routeId);

        // Then start private broadcast
        mHandler.post(
                () -> mBluetoothRouteController.startPrivateBroadcast(routeIdListForBroadcast));
    }

    @Override
    public synchronized void deselectRoute() {
        if (!isBroadcasting()) {
            // Unexpected result.
            Slog.e(TAG, "Unable to deselect route: no broadcasting");
            return;
        }

        // TODO: b/414535608 - Handle PAS with 3+ devices
        // Currently only max 2 devices are supported for audio sharing, deselecting one means stop
        // broadcasting and transfer to audio to the only not being deselected.
        mHandler.post(mBluetoothRouteController::stopBroadcast);
    }

    @RequiresPermission(
            anyOf = {
                Manifest.permission.MODIFY_AUDIO_ROUTING,
@@ -469,32 +418,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
            int musicMaxVolume,
            boolean isVolumeFixed) {
        mRouteIdToAvailableDeviceRoutes.clear();
        mSelectedRoutes.clear();
        List<MediaRoute2InfoHolder> newSelectedRouteHolders = new ArrayList<>();

        // When do audio sharing, the audioDeviceInfos obtains from AudioManager is not reliable.
        // Special handling is needed.
        if (com.android.media.flags.Flags.enableOutputSwitcherPersonalAudioSharing()) {
            if (selectedDeviceAttributesType == AudioDeviceInfo.TYPE_BLE_BROADCAST) {
                for (MediaRoute2Info mediaRoute2Info :
                        mBluetoothRouteController.getBroadcastingDeviceRoutes()) {
                    // Need to reconstruct MediaRoute2Info from BluetoothDeviceRoutesController
                    MediaRoute2InfoHolder newHolder =
                            MediaRoute2InfoHolder.createForAudioManagerRoute(
                                    mediaRoute2Info, AudioDeviceInfo.TYPE_BLE_HEADSET);
                    mRouteIdToAvailableDeviceRoutes.put(mediaRoute2Info.getId(), newHolder);
                    newSelectedRouteHolders.add(newHolder);
                }
            }
        }

        MediaRoute2InfoHolder newSelectedRouteHolder = null;
        for (AudioDeviceInfo audioDeviceInfo : audioDeviceInfos) {
            if (com.android.media.flags.Flags.enableOutputSwitcherPersonalAudioSharing()) {
                if (audioDeviceInfo.getType() == AudioDeviceInfo.TYPE_BLE_BROADCAST) {
                    // Handled previously
                    continue;
                }
            }
            MediaRoute2Info mediaRoute2Info =
                    createMediaRoute2InfoFromAudioDeviceInfo(audioDeviceInfo);
            // Null means audioDeviceInfo is not a supported media output, like a phone's builtin
@@ -506,7 +431,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
                                mediaRoute2Info, audioDeviceInfoType);
                mRouteIdToAvailableDeviceRoutes.put(mediaRoute2Info.getId(), newHolder);
                if (selectedDeviceAttributesType == audioDeviceInfoType) {
                    newSelectedRouteHolders.add(newHolder);
                    newSelectedRouteHolder = newHolder;
                }
            }
        }
@@ -522,7 +447,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
            mRouteIdToAvailableDeviceRoutes.put(placeholderRouteId, placeholderRouteHolder);
        }

        if (newSelectedRouteHolders.isEmpty()) {
        if (newSelectedRouteHolder == null) {
            Slog.e(
                    TAG,
                    "Could not map this selected device attribute type to an available route: "
@@ -533,20 +458,15 @@ import java.util.concurrent.CopyOnWriteArrayList;
                                            .map(AudioDeviceInfo::getType)
                                            .toArray()));
            // We know mRouteIdToAvailableDeviceRoutes is not empty.
            newSelectedRouteHolders.add(mRouteIdToAvailableDeviceRoutes.values().iterator().next());
            newSelectedRouteHolder = mRouteIdToAvailableDeviceRoutes.values().iterator().next();
        }

        for (MediaRoute2InfoHolder newSelectedRouteHolder : newSelectedRouteHolders) {
        MediaRoute2InfoHolder selectedRouteHolderWithUpdatedVolumeInfo =
                newSelectedRouteHolder.copyWithVolumeInfo(
                        musicVolume, musicMaxVolume, isVolumeFixed);

        mRouteIdToAvailableDeviceRoutes.put(
                newSelectedRouteHolder.mMediaRoute2Info.getId(),
                selectedRouteHolderWithUpdatedVolumeInfo);

            mSelectedRoutes.add(selectedRouteHolderWithUpdatedVolumeInfo.mMediaRoute2Info);
        }
        mSelectedRoute = selectedRouteHolderWithUpdatedVolumeInfo.mMediaRoute2Info;

        // We only add those BT routes that we have not already obtained from audio manager (which
        // are active).
@@ -637,10 +557,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
        return builder.build();
    }

    private boolean isBroadcasting() {
        return getAudioDeviceType() == AudioDeviceInfo.TYPE_BLE_BROADCAST;
    }

    /**
     * Holds a {@link MediaRoute2Info} and associated information that we don't want to put in the
     * {@link MediaRoute2Info} class because it's solely necessary for the implementation of this
+0 −48
Original line number Diff line number Diff line
@@ -215,54 +215,6 @@ import java.util.stream.Collectors;
        return routes;
    }

    /**
     * Trigger {@link BluetoothProfileMonitor} to start broadcast.
     *
     * @param targetRouteIds routes ids that broadcast targeting to
     */
    protected void startPrivateBroadcast(List<String> targetRouteIds) {
        if (targetRouteIds.size() <= 1) {
            Log.e(TAG, "Unable to start broadcast, incorrect number of routes.");
            return;
        }

        // Filter the list to only contains items with matching route ids, then
        // Map the list to BluetoothDevice list to start the broadcast.
        List<BluetoothDevice> deviceListForBroadcast = new ArrayList<>();

        // Check if routeInfo are in the target list, and
        // Prevent duplicated entries
        for (BluetoothRouteInfo routeInfo : mBluetoothRoutes.values()) {
            if (targetRouteIds.contains(routeInfo.mRoute.getId())
                    && !deviceListForBroadcast.contains(routeInfo.mBtDevice)) {
                deviceListForBroadcast.add(routeInfo.mBtDevice);
            }
        }

        mBluetoothProfileMonitor.startPrivateBroadcast(deviceListForBroadcast);
    }

    /** Trigger {@link BluetoothProfileMonitor} to stop broadcast. */
    protected void stopBroadcast() {
        mBluetoothProfileMonitor.stopPrivateBroadcast();
    }

    /**
     * Obtains a list of selected bluetooth route infos.
     *
     * @return list of selected bluetooth route infos.
     */
    public List<MediaRoute2Info> getBroadcastingDeviceRoutes() {
        // Use HashSet to check and avoid duplicates devices with same routeId
        Set<String> routeIdSet = new HashSet<>();

        // Convert List<BluetoothDevice> to List<MediaRoute2Info>
        return mBluetoothProfileMonitor.getBroadcastingDevices().stream()
                .map(device -> createBluetoothRoute(device).mRoute)
                .filter(routeInfo -> routeIdSet.add(routeInfo.getId()))
                .toList();
    }

    private void notifyBluetoothRoutesUpdated() {
        mListener.onBluetoothRoutesUpdated();
    }
+0 −393

File changed.

Preview size limit exceeded, changes collapsed.

+4 −4
Original line number Diff line number Diff line
@@ -80,8 +80,8 @@ import java.util.Objects;
     *
     * @return the selected route or {@code null} if there are no active routes.
     */
    @NonNull
    List<MediaRoute2Info> getSelectedRoutes();
    @Nullable
    MediaRoute2Info getSelectedRoute();

    /**
     * Returns transferable routes.
@@ -144,9 +144,9 @@ import java.util.Objects;
        }

        @Override
        public List<MediaRoute2Info> getSelectedRoutes() {
        public MediaRoute2Info getSelectedRoute() {
            // no op
            return Collections.emptyList();
            return null;
        }

        @Override
+4 −11
Original line number Diff line number Diff line
@@ -104,17 +104,17 @@ import java.util.List;
        }
    }

    /** Returns the currently selected device (built-in, wired or bluetooth) route. */
    /** Returns the currently selected device (built-in or wired) route. */
    @NonNull
    List<MediaRoute2Info> getSelectedRoutes();
    MediaRoute2Info getSelectedRoute();

    /**
     * Returns all available routes.
     *
     * <p>Note that this method returns available routes including the selected route because (a)
     * this interface doesn't guarantee that the internal state of the controller won't change
     * between calls to {@link #getSelectedRoutes()} and this method and (b) {@link
     * #getSelectedRoutes()} may be treated as a transferable route (not a selected route) if the
     * between calls to {@link #getSelectedRoute()} and this method and (b) {@link
     * #getSelectedRoute()} may be treated as a transferable route (not a selected route) if the
     * selected route is from {@link BluetoothRouteController}.
     */
    List<MediaRoute2Info> getAvailableRoutes();
@@ -128,10 +128,6 @@ import java.util.List;
     */
    void transferTo(@Nullable String routeId);

    void selectRoute(String routeId);

    void deselectRoute();

    /**
     * Updates device route volume.
     *
@@ -159,9 +155,6 @@ import java.util.List;
    /** Releases the routing session. */
    void releaseRoutingSession();

    /** Return the first audio device's type. */
    int getAudioDeviceType();

    /**
     * Interface for receiving events when device route has changed.
     */
Loading