10a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean/*
20a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean * Copyright (C) 2014 The Android Open Source Project
30a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean *
40a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean * Licensed under the Apache License, Version 2.0 (the "License");
50a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean * you may not use this file except in compliance with the License.
60a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean * You may obtain a copy of the License at
70a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean *
80a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean *      http://www.apache.org/licenses/LICENSE-2.0
90a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean *
100a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean * Unless required by applicable law or agreed to in writing, software
110a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean * distributed under the License is distributed on an "AS IS" BASIS,
120a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1350c00924d8483ea04ab64bc1d9775d6147afb591Paul McLean * See the License for the specific language governing permissions and
140a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean * limitations under the License.
150a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean */
160a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean
170a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLeanpackage com.android.server.usb;
180a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean
19371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmannimport android.annotation.NonNull;
2007a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chantimport android.media.AudioSystem;
2107a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chantimport android.media.IAudioService;
2207a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chantimport android.os.RemoteException;
23371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmannimport android.service.usb.UsbAlsaDeviceProto;
2454b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chantimport android.util.Slog;
25371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann
26371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmannimport com.android.internal.util.dump.DualDumpOutputStream;
2754b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chantimport com.android.server.audio.AudioService;
28371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann
2950c00924d8483ea04ab64bc1d9775d6147afb591Paul McLean/**
3016d7913d982dd74bc4309128c4562c816e683bd7Paul McLean * Represents the ALSA specification, and attributes of an ALSA device.
3150c00924d8483ea04ab64bc1d9775d6147afb591Paul McLean */
3250c00924d8483ea04ab64bc1d9775d6147afb591Paul McLeanpublic final class UsbAlsaDevice {
3350c00924d8483ea04ab64bc1d9775d6147afb591Paul McLean    private static final String TAG = "UsbAlsaDevice";
340a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean    protected static final boolean DEBUG = false;
350a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean
3616d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    private final int mCardNum;
3716d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    private final int mDeviceNum;
3807a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    private final String mDeviceAddress;
3954b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant    private final boolean mHasOutput;
4054b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant    private final boolean mHasInput;
4116d7913d982dd74bc4309128c4562c816e683bd7Paul McLean
4216d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    private final boolean mIsInputHeadset;
4316d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    private final boolean mIsOutputHeadset;
4416d7913d982dd74bc4309128c4562c816e683bd7Paul McLean
4507a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    private boolean mSelected = false;
4607a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    private int mOutputState;
4707a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    private int mInputState;
4807a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    private UsbAlsaJackDetector mJackDetector;
4907a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    private IAudioService mAudioService;
500a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean
5120137dc1481e8efec47d45d8ee0828623b5af8f9Glenn Kasten    private String mDeviceName = "";
5220137dc1481e8efec47d45d8ee0828623b5af8f9Glenn Kasten    private String mDeviceDescription = "";
530a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean
5407a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    public UsbAlsaDevice(IAudioService audioService, int card, int device, String deviceAddress,
5554b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant            boolean hasOutput, boolean hasInput,
5616d7913d982dd74bc4309128c4562c816e683bd7Paul McLean            boolean isInputHeadset, boolean isOutputHeadset) {
5707a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        mAudioService = audioService;
5816d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        mCardNum = card;
5916d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        mDeviceNum = device;
6016d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        mDeviceAddress = deviceAddress;
6154b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant        mHasOutput = hasOutput;
6254b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant        mHasInput = hasInput;
6316d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        mIsInputHeadset = isInputHeadset;
6416d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        mIsOutputHeadset = isOutputHeadset;
6516d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    }
6616d7913d982dd74bc4309128c4562c816e683bd7Paul McLean
6716d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    /**
6816d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     * @returns the ALSA card number associated with this peripheral.
6916d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     */
7016d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    public int getCardNum() {
7116d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        return mCardNum;
7216d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    }
7316d7913d982dd74bc4309128c4562c816e683bd7Paul McLean
7416d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    /**
7516d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     * @returns the ALSA device number associated with this peripheral.
7616d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     */
7716d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    public int getDeviceNum() {
7816d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        return mDeviceNum;
7916d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    }
8016d7913d982dd74bc4309128c4562c816e683bd7Paul McLean
8116d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    /**
8216d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     * @returns the USB device device address associated with this peripheral.
8316d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     */
8416d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    public String getDeviceAddress() {
8516d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        return mDeviceAddress;
8616d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    }
8716d7913d982dd74bc4309128c4562c816e683bd7Paul McLean
8816d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    /**
8954b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant     * @returns the ALSA card/device address string.
9016d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     */
9154b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant    public String getAlsaCardDeviceString() {
9254b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant        if (mCardNum < 0 || mDeviceNum < 0) {
9354b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant            Slog.e(TAG, "Invalid alsa card or device alsaCard: " + mCardNum
9454b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant                        + " alsaDevice: " + mDeviceNum);
9554b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant            return null;
9654b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant        }
9754b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant        return AudioService.makeAlsaAddressString(mCardNum, mDeviceNum);
9854b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant    }
9954b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant
10054b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant    /**
10154b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant     * @returns true if the device supports output.
10254b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant     */
10354b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant    public boolean hasOutput() {
10454b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant        return mHasOutput;
10516d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    }
10616d7913d982dd74bc4309128c4562c816e683bd7Paul McLean
10716d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    /**
10854b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant     * @returns true if the device supports input (recording).
10916d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     */
11054b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant    public boolean hasInput() {
11154b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant        return mHasInput;
11216d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    }
11316d7913d982dd74bc4309128c4562c816e683bd7Paul McLean
11416d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    /**
11554b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant     * @returns true if the device is a headset for purposes of input.
11616d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     */
11716d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    public boolean isInputHeadset() {
11816d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        return mIsInputHeadset;
11916d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    }
12016d7913d982dd74bc4309128c4562c816e683bd7Paul McLean
12116d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    /**
12254b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant     * @returns true if the device is a headset for purposes of output.
12316d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     */
12416d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    public boolean isOutputHeadset() {
12516d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        return mIsOutputHeadset;
1260a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean    }
1270a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean
12850c00924d8483ea04ab64bc1d9775d6147afb591Paul McLean    /**
12907a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant     * @returns true if input jack is detected or jack detection is not supported.
13007a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant     */
13107a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    private synchronized boolean isInputJackConnected() {
13207a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        if (mJackDetector == null) {
13307a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant            return true;  // If jack detect isn't supported, say it's connected.
13407a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        }
13507a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        return mJackDetector.isInputJackConnected();
13607a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    }
13707a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant
13807a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    /**
13907a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant     * @returns true if input jack is detected or jack detection is not supported.
14007a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant     */
14107a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    private synchronized boolean isOutputJackConnected() {
14207a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        if (mJackDetector == null) {
14307a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant            return true;  // if jack detect isn't supported, say it's connected.
14407a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        }
14507a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        return mJackDetector.isOutputJackConnected();
14607a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    }
14707a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant
14807a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    /** Begins a jack-detection thread. */
14907a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    private synchronized void startJackDetect() {
15007a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        // If no jack detect capabilities exist, mJackDetector will be null.
15107a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        mJackDetector = UsbAlsaJackDetector.startJackDetect(this);
15207a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    }
15307a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant
15407a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    /** Stops a jack-detection thread. */
15507a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    private synchronized void stopJackDetect() {
15607a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        if (mJackDetector != null) {
15707a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant            mJackDetector.pleaseStop();
15807a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        }
15907a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        mJackDetector = null;
16007a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    }
16107a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant
16207a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    /** Start using this device as the selected USB Audio Device. */
16307a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    public synchronized void start() {
16407a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        mSelected = true;
16507a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        mInputState = 0;
16607a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        mOutputState = 0;
16707a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        startJackDetect();
16807a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        updateWiredDeviceConnectionState(true);
16907a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    }
17007a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant
17107a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    /** Stop using this device as the selected USB Audio Device. */
17207a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    public synchronized void stop() {
17307a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        stopJackDetect();
17407a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        updateWiredDeviceConnectionState(false);
17507a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        mSelected = false;
17607a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    }
17707a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant
17807a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    /** Updates AudioService with the connection state of the alsaDevice.
17907a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant     *  Checks ALSA Jack state for inputs and outputs before reporting.
18007a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant     */
18107a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    public synchronized void updateWiredDeviceConnectionState(boolean enable) {
18207a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        if (!mSelected) {
18307a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant            Slog.e(TAG, "updateWiredDeviceConnectionState on unselected AlsaDevice!");
18407a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant            return;
18507a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        }
18607a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        String alsaCardDeviceString = getAlsaCardDeviceString();
18707a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        if (alsaCardDeviceString == null) {
18807a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant            return;
18907a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        }
19007a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        try {
19107a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant            // Output Device
19207a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant            if (mHasOutput) {
19307a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                int device = mIsOutputHeadset
19407a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                        ? AudioSystem.DEVICE_OUT_USB_HEADSET
19507a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                        : AudioSystem.DEVICE_OUT_USB_DEVICE;
19607a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                if (DEBUG) {
19707a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                    Slog.d(TAG, "pre-call device:0x" + Integer.toHexString(device)
19807a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                            + " addr:" + alsaCardDeviceString
19907a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                            + " name:" + mDeviceName);
20007a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                }
20107a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                boolean connected = isOutputJackConnected();
20207a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                Slog.i(TAG, "OUTPUT JACK connected: " + connected);
20307a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                int outputState = (enable && connected) ? 1 : 0;
20407a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                if (outputState != mOutputState) {
20507a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                    mOutputState = outputState;
20607a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                    mAudioService.setWiredDeviceConnectionState(device, outputState,
20707a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                                                                alsaCardDeviceString,
20807a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                                                                mDeviceName, TAG);
20907a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                }
21007a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant            }
21107a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant
21207a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant            // Input Device
21307a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant            if (mHasInput) {
21407a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                int device = mIsInputHeadset ? AudioSystem.DEVICE_IN_USB_HEADSET
21507a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                        : AudioSystem.DEVICE_IN_USB_DEVICE;
21607a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                boolean connected = isInputJackConnected();
21707a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                Slog.i(TAG, "INPUT JACK connected: " + connected);
21807a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                int inputState = (enable && connected) ? 1 : 0;
21907a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                if (inputState != mInputState) {
22007a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                    mInputState = inputState;
22107a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                    mAudioService.setWiredDeviceConnectionState(
22207a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                            device, inputState, alsaCardDeviceString,
22307a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                            mDeviceName, TAG);
22407a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant                }
22507a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant            }
22607a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        } catch (RemoteException e) {
22707a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant            Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
22807a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant        }
22907a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    }
23007a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant
23107a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant
23207a97da51fc7d43db9903d793d614340b1cf3b67Andrew Chant    /**
23350c00924d8483ea04ab64bc1d9775d6147afb591Paul McLean     * @Override
23416d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     * @returns a string representation of the object.
23550c00924d8483ea04ab64bc1d9775d6147afb591Paul McLean     */
23654b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant    public synchronized String toString() {
23716d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        return "UsbAlsaDevice: [card: " + mCardNum
23816d7913d982dd74bc4309128c4562c816e683bd7Paul McLean            + ", device: " + mDeviceNum
23916d7913d982dd74bc4309128c4562c816e683bd7Paul McLean            + ", name: " + mDeviceName
24054b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant            + ", hasOutput: " + mHasOutput
24154b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant            + ", hasInput: " + mHasInput + "]";
2420a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean    }
2430a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean
244371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann    /**
245371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann     * Write a description of the device to a dump stream.
246371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann     */
24754b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant    public synchronized void dump(@NonNull DualDumpOutputStream dump, String idName, long id) {
248371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann        long token = dump.start(idName, id);
249371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann
250371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann        dump.write("card", UsbAlsaDeviceProto.CARD, mCardNum);
251371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann        dump.write("device", UsbAlsaDeviceProto.DEVICE, mDeviceNum);
252371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann        dump.write("name", UsbAlsaDeviceProto.NAME, mDeviceName);
25354b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant        dump.write("has_output", UsbAlsaDeviceProto.HAS_PLAYBACK, mHasOutput);
25454b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant        dump.write("has_input", UsbAlsaDeviceProto.HAS_CAPTURE, mHasInput);
255371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann        dump.write("address", UsbAlsaDeviceProto.ADDRESS, mDeviceAddress);
256371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann
257371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann        dump.end(token);
258371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann    }
259371a3b879ba82bbe5a4d914328a20659131d0220Philip P. Moltmann
26019d6c7a9cd8c3a623fe76e3239be583ad0014b6fGlenn Kasten    // called by logDevices
26154b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant    synchronized String toShortString() {
26216d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        return "[card:" + mCardNum + " device:" + mDeviceNum + " " + mDeviceName + "]";
2630a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean    }
26420137dc1481e8efec47d45d8ee0828623b5af8f9Glenn Kasten
26554b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant    synchronized String getDeviceName() {
26620137dc1481e8efec47d45d8ee0828623b5af8f9Glenn Kasten        return mDeviceName;
26720137dc1481e8efec47d45d8ee0828623b5af8f9Glenn Kasten    }
26820137dc1481e8efec47d45d8ee0828623b5af8f9Glenn Kasten
26954b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant    synchronized void setDeviceNameAndDescription(String deviceName, String deviceDescription) {
27020137dc1481e8efec47d45d8ee0828623b5af8f9Glenn Kasten        mDeviceName = deviceName;
27120137dc1481e8efec47d45d8ee0828623b5af8f9Glenn Kasten        mDeviceDescription = deviceDescription;
27220137dc1481e8efec47d45d8ee0828623b5af8f9Glenn Kasten    }
27320137dc1481e8efec47d45d8ee0828623b5af8f9Glenn Kasten
27416d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    /**
27516d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     * @Override
27616d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     * @returns true if the objects are equivalent.
27716d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     */
27816d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    public boolean equals(Object obj) {
27916d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        if (!(obj instanceof UsbAlsaDevice)) {
28016d7913d982dd74bc4309128c4562c816e683bd7Paul McLean            return false;
28116d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        }
28216d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        UsbAlsaDevice other = (UsbAlsaDevice) obj;
28316d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        return (mCardNum == other.mCardNum
28416d7913d982dd74bc4309128c4562c816e683bd7Paul McLean                && mDeviceNum == other.mDeviceNum
28554b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant                && mHasOutput == other.mHasOutput
28654b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant                && mHasInput == other.mHasInput
28716d7913d982dd74bc4309128c4562c816e683bd7Paul McLean                && mIsInputHeadset == other.mIsInputHeadset
28816d7913d982dd74bc4309128c4562c816e683bd7Paul McLean                && mIsOutputHeadset == other.mIsOutputHeadset);
28916d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    }
29016d7913d982dd74bc4309128c4562c816e683bd7Paul McLean
29116d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    /**
29216d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     * @Override
29316d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     * @returns a hash code generated from the object contents.
29416d7913d982dd74bc4309128c4562c816e683bd7Paul McLean     */
29516d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    public int hashCode() {
29616d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        final int prime = 31;
29716d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        int result = 1;
29816d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        result = prime * result + mCardNum;
29916d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        result = prime * result + mDeviceNum;
30054b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant        result = prime * result + (mHasOutput ? 0 : 1);
30154b15e98cdb40969929fa23ce42e6817a4b8392cAndrew Chant        result = prime * result + (mHasInput ? 0 : 1);
30216d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        result = prime * result + (mIsInputHeadset ? 0 : 1);
30316d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        result = prime * result + (mIsOutputHeadset ? 0 : 1);
30416d7913d982dd74bc4309128c4562c816e683bd7Paul McLean
30516d7913d982dd74bc4309128c4562c816e683bd7Paul McLean        return result;
30616d7913d982dd74bc4309128c4562c816e683bd7Paul McLean    }
3070a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean}
3080a8f06922f288bfa4a22a7cd45dd5b89a9563e54Paul McLean
309