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

Commit 3d0fb881 authored by Mike Lockwood's avatar Mike Lockwood Committed by Android (Google) Code Review
Browse files

Merge "Replace broadcasts with calls to...

Merge "Replace broadcasts with calls to IAudioService.setWiredDeviceConnectionState() to report USB device status"
parents 2ef9d1af 2e343414
Loading
Loading
Loading
Loading
+0 −32
Original line number Diff line number Diff line
@@ -295,38 +295,6 @@ public class AudioManager {
     */
    public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";

    /**
     * Broadcast Action: A USB audio accessory was plugged in or unplugged.
     *
     * <p>The intent will have the following extra values:
     * <ul>
     *   <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
     *   <li><em>card</em> - ALSA card number (integer) </li>
     *   <li><em>device</em> - ALSA device number (integer) </li>
     * </ul>
     * </ul>
     * @hide
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_USB_AUDIO_ACCESSORY_PLUG =
            "android.media.action.USB_AUDIO_ACCESSORY_PLUG";

    /**
     * Broadcast Action: A USB audio device was plugged in or unplugged.
     *
     * <p>The intent will have the following extra values:
     * <ul>
     *   <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
     *   <li><em>card</em> - ALSA card number (integer) </li>
     *   <li><em>device</em> - ALSA device number (integer) </li>
     * </ul>
     * </ul>
     * @hide
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_USB_AUDIO_DEVICE_PLUG =
            "android.media.action.USB_AUDIO_DEVICE_PLUG";

    /** The audio stream for phone calls */
    public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
    /** The audio stream for system sounds */
+0 −52
Original line number Diff line number Diff line
@@ -634,8 +634,6 @@ public class AudioService extends IAudioService.Stub {
                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
        intentFilter.addAction(AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG);
        intentFilter.addAction(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG);
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
@@ -4955,56 +4953,6 @@ public class AudioService extends IAudioService.Stub {
                        }
                    }
                }
            } else if (action.equals(AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
                state = intent.getIntExtra("state", 0);

                int alsaCard = intent.getIntExtra("card", -1);
                int alsaDevice = intent.getIntExtra("device", -1);

                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
                                    : "card=" + alsaCard + ";device=" + alsaDevice);

                // Playback Device
                outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
                setWiredDeviceConnectionState(outDevice, state, params);
            } else if (action.equals(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG)) {
                // FIXME Does not yet handle the case where the setting is changed
                // after device connection.  Ideally we should handle the settings change
                // in SettingsObserver. Here we should log that a USB device is connected
                // and disconnected with its address (card , device) and force the
                // connection or disconnection when the setting changes.
                int isDisabled = Settings.Secure.getInt(mContentResolver,
                        Settings.Secure.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED, 0);
                if (isDisabled != 0) {
                    return;
                }

                state = intent.getIntExtra("state", 0);

                int alsaCard = intent.getIntExtra("card", -1);
                int alsaDevice = intent.getIntExtra("device", -1);
                boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
                boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
                boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
                int deviceClass = intent.getIntExtra("class", 0);

                String params = (alsaCard == -1 && alsaDevice == -1
                        ? ""
                        : "card=" + alsaCard +
                          ";device=" + alsaDevice +
                          ";class=" + Integer.toHexString(deviceClass));

                // Playback Device
                if (hasPlayback) {
                    outDevice = AudioSystem.DEVICE_OUT_USB_DEVICE;
                    setWiredDeviceConnectionState(outDevice, state, params);
                }

                // Capture Device
                if (hasCapture) {
                    inDevice = AudioSystem.DEVICE_IN_USB_DEVICE;
                    setWiredDeviceConnectionState(inDevice, state, params);
                }
            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
                boolean broadcast = false;
                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
+82 −27
Original line number Diff line number Diff line
@@ -23,12 +23,15 @@ import android.content.Intent;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbInterface;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.os.FileObserver;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;

import libcore.io.IoUtils;
@@ -49,6 +52,7 @@ public final class UsbAlsaManager {
    private static final String ALSA_DIRECTORY = "/dev/snd/";

    private final Context mContext;
    private IAudioService mAudioService;

    private final AlsaCardsParser mCardsParser = new AlsaCardsParser();
    private final AlsaDevicesParser mDevicesParser = new AlsaDevicesParser();
@@ -65,6 +69,8 @@ public final class UsbAlsaManager {
    private final HashMap<String,AlsaDevice>
        mAlsaDevices = new HashMap<String,AlsaDevice>();

    private UsbAudioDevice mAccessoryAudioDevice = null;

    private UsbAudioDevice mSelectedAudioDevice = null;

    private final class AlsaDevice {
@@ -123,6 +129,9 @@ public final class UsbAlsaManager {
    }

    public void systemReady() {
        mAudioService = IAudioService.Stub.asInterface(
                        ServiceManager.getService(Context.AUDIO_SERVICE));

        mAlsaObserver.startWatching();

        // add existing alsa devices
@@ -132,27 +141,59 @@ public final class UsbAlsaManager {
        }
    }

    // Broadcasts the arrival/departure of a USB audio interface
    // audioDevice - the UsbAudioDevice that was added or removed
    // Notifies AudioService when a device is added or removed
    // audioDevice - the AudioDevice that was added or removed
    // enabled - if true, we're connecting a device (it's arrived), else disconnecting
    private void sendDeviceNotification(UsbAudioDevice audioDevice, boolean enabled) {
    private void notifyDeviceState(UsbAudioDevice audioDevice, boolean enabled) {
       if (DEBUG) {
            Slog.d(TAG, "sendDeviceNotification(enabled:" + enabled +
                    " c:" + audioDevice.mCard +
                    " d:" + audioDevice.mDevice + ")");
            Slog.d(TAG, "notifyDeviceState " + enabled + " " + audioDevice);
        }

        if (mAudioService == null) {
            Slog.e(TAG, "no AudioService");
            return;
        }

        // send a sticky broadcast containing current USB state
        Intent intent = new Intent(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG);
        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        intent.putExtra("state", enabled ? 1 : 0);
        intent.putExtra("card", audioDevice.mCard);
        intent.putExtra("device", audioDevice.mDevice);
        intent.putExtra("hasPlayback", audioDevice.mHasPlayback);
        intent.putExtra("hasCapture", audioDevice.mHasCapture);
        intent.putExtra("class", audioDevice.mDeviceClass);
        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
        // FIXME Does not yet handle the case where the setting is changed
        // after device connection.  Ideally we should handle the settings change
        // in SettingsObserver. Here we should log that a USB device is connected
        // and disconnected with its address (card , device) and force the
        // connection or disconnection when the setting changes.
        int isDisabled = Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED, 0);
        if (isDisabled != 0) {
            return;
        }

        int state = (enabled ? 1 : 0);
        int alsaCard = audioDevice.mCard;
        int alsaDevice = audioDevice.mDevice;
        if (alsaCard < 0 || alsaDevice < 0) {
            Slog.e(TAG, "Invalid alsa card or device alsaCard: " + alsaCard +
                        " alsaDevice: " + alsaDevice);
            return;
        }
        String params = ("card=" + alsaCard + ";device=" + alsaDevice);

        try {
            // Playback Device
            if (audioDevice.mHasPlayback) {
                int device = (audioDevice == mAccessoryAudioDevice ?
                        AudioSystem.DEVICE_OUT_USB_ACCESSORY :
                        AudioSystem.DEVICE_OUT_USB_DEVICE);
                mAudioService.setWiredDeviceConnectionState(device, state, params);
            }

            // Capture Device
            if (audioDevice.mHasCapture) {
               int device = (audioDevice == mAccessoryAudioDevice ?
                        AudioSystem.DEVICE_IN_USB_ACCESSORY :
                        AudioSystem.DEVICE_IN_USB_DEVICE);
                mAudioService.setWiredDeviceConnectionState(device, state, params);
            }
        } catch (RemoteException e) {
            Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
        }
    }

    private AlsaDevice waitForAlsaDevice(int card, int device, int type) {
@@ -249,7 +290,7 @@ public final class UsbAlsaManager {
                return false;
            }
            // "disconnect" the AudioPolicyManager from the previously selected device.
            sendDeviceNotification(mSelectedAudioDevice, false);
            notifyDeviceState(mSelectedAudioDevice, false);
            mSelectedAudioDevice = null;
        }

@@ -284,7 +325,7 @@ public final class UsbAlsaManager {
        mSelectedAudioDevice.mDeviceDescription =
                mCardsParser.getCardRecordFor(card).mCardDescription;

        sendDeviceNotification(mSelectedAudioDevice, true);
        notifyDeviceState(mSelectedAudioDevice, true);

        return true;
    }
@@ -297,9 +338,9 @@ public final class UsbAlsaManager {
        return selectAudioCard(mCardsParser.getDefaultCard());
    }

    /* package */ void deviceAdded(UsbDevice usbDevice) {
    /* package */ void usbDeviceAdded(UsbDevice usbDevice) {
       if (DEBUG) {
          Slog.d(TAG, "deviceAdded(): " + usbDevice);
          Slog.d(TAG, "usbDeviceAdded(): " + usbDevice);
        }

        // Is there an audio interface in there?
@@ -360,7 +401,7 @@ public final class UsbAlsaManager {
        }
    }

    /* package */ void deviceRemoved(UsbDevice usbDevice) {
    /* package */ void usbDeviceRemoved(UsbDevice usbDevice) {
       if (DEBUG) {
          Slog.d(TAG, "deviceRemoved(): " + usbDevice);
        }
@@ -368,7 +409,7 @@ public final class UsbAlsaManager {
        UsbAudioDevice audioDevice = mAudioDevices.remove(usbDevice);
        if (audioDevice != null) {
            if (audioDevice.mHasPlayback || audioDevice.mHasPlayback) {
                sendDeviceNotification(audioDevice, false);
                notifyDeviceState(audioDevice, false);
            }
        }
        UsbMidiDevice usbMidiDevice = mMidiDevices.remove(usbDevice);
@@ -382,6 +423,20 @@ public final class UsbAlsaManager {
        selectDefaultDevice();
    }

   /* package */ void setAccessoryAudioState(boolean enabled, int card, int device) {
       if (DEBUG) {
            Slog.d(TAG, "setAccessoryAudioState " + enabled + " " + card + " " + device);
        }
        if (enabled) {
            mAccessoryAudioDevice = new UsbAudioDevice(card, device, true, false,
                    UsbAudioDevice.kAudioDeviceClass_External);
            notifyDeviceState(mAccessoryAudioDevice, true);
        } else if (mAccessoryAudioDevice != null) {
            notifyDeviceState(mAccessoryAudioDevice, false);
            mAccessoryAudioDevice = null;
        }
    }

    //
    // Devices List
    //
+9 −11
Original line number Diff line number Diff line
@@ -127,6 +127,7 @@ public class UsbDeviceManager {
    private Map<String, List<Pair<String, String>>> mOemModeMap;
    private String[] mAccessoryStrings;
    private UsbDebuggingManager mDebuggingManager;
    private final UsbAlsaManager mUsbAlsaManager;

    private class AdbSettingsObserver extends ContentObserver {
        public AdbSettingsObserver() {
@@ -159,8 +160,9 @@ public class UsbDeviceManager {
        }
    };

    public UsbDeviceManager(Context context) {
    public UsbDeviceManager(Context context, UsbAlsaManager alsaManager) {
        mContext = context;
        mUsbAlsaManager = alsaManager;
        mContentResolver = context.getContentResolver();
        PackageManager pm = mContext.getPackageManager();
        mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
@@ -594,19 +596,15 @@ public class UsbDeviceManager {
            boolean enabled = containsFunction(mCurrentFunctions,
                    UsbManager.USB_FUNCTION_AUDIO_SOURCE);
            if (enabled != mAudioSourceEnabled) {
                // send a sticky broadcast containing current USB state
                Intent intent = new Intent(AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG);
                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                intent.putExtra("state", (enabled ? 1 : 0));
                int card = -1;
                int device = -1;

                if (enabled) {
                    Scanner scanner = null;
                    try {
                        scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
                        int card = scanner.nextInt();
                        int device = scanner.nextInt();
                        intent.putExtra("card", card);
                        intent.putExtra("device", device);
                        card = scanner.nextInt();
                        device = scanner.nextInt();
                    } catch (FileNotFoundException e) {
                        Slog.e(TAG, "could not open audio source PCM file", e);
                    } finally {
@@ -615,7 +613,7 @@ public class UsbDeviceManager {
                        }
                    }
                }
                mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
                mUsbAlsaManager.setAccessoryAudioState(enabled, card, device);
                mAudioSourceEnabled = enabled;
            }
        }
+5 −8
Original line number Diff line number Diff line
@@ -60,16 +60,16 @@ public class UsbHostManager {
    private ArrayList<UsbInterface> mNewInterfaces;
    private ArrayList<UsbEndpoint> mNewEndpoints;

    private UsbAlsaManager mUsbAlsaManager;
    private final UsbAlsaManager mUsbAlsaManager;

    @GuardedBy("mLock")
    private UsbSettingsManager mCurrentSettings;

    public UsbHostManager(Context context) {
    public UsbHostManager(Context context, UsbAlsaManager alsaManager) {
        mContext = context;
        mHostBlacklist = context.getResources().getStringArray(
                com.android.internal.R.array.config_usbHostBlacklist);
        mUsbAlsaManager = new UsbAlsaManager(context);
        mUsbAlsaManager = alsaManager;
    }

    public void setCurrentSettings(UsbSettingsManager settings) {
@@ -222,7 +222,7 @@ public class UsbHostManager {
                mDevices.put(mNewDevice.getDeviceName(), mNewDevice);
                Slog.d(TAG, "Added device " + mNewDevice);
                getCurrentSettings().deviceAttached(mNewDevice);
                mUsbAlsaManager.deviceAdded(mNewDevice);
                mUsbAlsaManager.usbDeviceAdded(mNewDevice);
            } else {
                Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded");
            }
@@ -238,15 +238,13 @@ public class UsbHostManager {
        synchronized (mLock) {
            UsbDevice device = mDevices.remove(deviceName);
            if (device != null) {
                mUsbAlsaManager.deviceRemoved(device);
                mUsbAlsaManager.usbDeviceRemoved(device);
                getCurrentSettings().deviceDetached(device);
            }
        }
    }

    public void systemReady() {
        mUsbAlsaManager.systemReady();

        synchronized (mLock) {
            // Create a thread to call into native code to wait for USB host events.
            // This thread will call us back on usbDeviceAdded and usbDeviceRemoved.
@@ -292,7 +290,6 @@ public class UsbHostManager {
                pw.println("    " + name + ": " + mDevices.get(name));
            }
        }
        mUsbAlsaManager.dump(fd, pw);
    }

    private native void monitorUsbHostBus();
Loading