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

Commit a32ea3b4 authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "AudioService: implement TV system volume" into lmp-dev

parents 19412496 212532b5
Loading
Loading
Loading
Loading
+286 −97
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiPlaybackClient;
import android.hardware.hdmi.HdmiTvClient;
import android.hardware.usb.UsbManager;
import android.media.MediaPlayer.OnCompletionListener;
@@ -144,7 +145,23 @@ public class AudioService extends IAudioService.Stub {
    private final Context mContext;
    private final ContentResolver mContentResolver;
    private final AppOpsManager mAppOps;
    private final boolean mVoiceCapable;

    // the platform has no specific capabilities
    private static final int PLATFORM_DEFAULT = 0;
    // the platform is voice call capable (a phone)
    private static final int PLATFORM_VOICE = 1;
    // the platform is a television or a set-top box
    private static final int PLATFORM_TELEVISION = 2;
    // the platform type affects volume and silent mode behavior
    private final int mPlatformType;

    private boolean isPlatformVoice() {
        return mPlatformType == PLATFORM_VOICE;
    }

    private boolean isPlatformTelevision() {
        return mPlatformType == PLATFORM_TELEVISION;
    }

    /** The controller for the volume UI. */
    private final VolumeController mVolumeController = new VolumeController();
@@ -243,9 +260,10 @@ public class AudioService extends IAudioService.Stub {
     * NOTE: do not create loops in aliases!
     * Some streams alias to different streams according to device category (phone or tablet) or
     * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
     *  mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and
     *  STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/
    private final int[] STREAM_VOLUME_ALIAS = new int[] {
     *  mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
     *  (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
     *  STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
    private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
        AudioSystem.STREAM_RING,            // STREAM_RING
@@ -257,7 +275,19 @@ public class AudioService extends IAudioService.Stub {
        AudioSystem.STREAM_RING,            // STREAM_DTMF
        AudioSystem.STREAM_MUSIC            // STREAM_TTS
    };
    private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] {
    private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
        AudioSystem.STREAM_MUSIC,       // STREAM_VOICE_CALL
        AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM
        AudioSystem.STREAM_MUSIC,       // STREAM_RING
        AudioSystem.STREAM_MUSIC,       // STREAM_MUSIC
        AudioSystem.STREAM_MUSIC,       // STREAM_ALARM
        AudioSystem.STREAM_MUSIC,       // STREAM_NOTIFICATION
        AudioSystem.STREAM_MUSIC,       // STREAM_BLUETOOTH_SCO
        AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM_ENFORCED
        AudioSystem.STREAM_MUSIC,       // STREAM_DTMF
        AudioSystem.STREAM_MUSIC        // STREAM_TTS
    };
    private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM
        AudioSystem.STREAM_RING,            // STREAM_RING
@@ -455,9 +485,12 @@ public class AudioService extends IAudioService.Stub {
    public final static int STREAM_REMOTE_MUSIC = -200;

    // Devices for which the volume is fixed and VolumePanel slider should be disabled
    final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
    int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
            AudioSystem.DEVICE_OUT_HDMI_ARC |
            AudioSystem.DEVICE_OUT_SPDIF |
            AudioSystem.DEVICE_OUT_AUX_LINE;

    // TODO merge orientation and rotation
    private final boolean mMonitorOrientation;
@@ -491,8 +524,16 @@ public class AudioService extends IAudioService.Stub {
        mContext = context;
        mContentResolver = context.getContentResolver();
        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
        mVoiceCapable = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_voice_capable);

        if (mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_voice_capable)) {
            mPlatformType = PLATFORM_VOICE;
        } else if (context.getPackageManager().hasSystemFeature(
                                                            PackageManager.FEATURE_TELEVISION)) {
            mPlatformType = PLATFORM_TELEVISION;
        } else {
            mPlatformType = PLATFORM_DEFAULT;
        }

        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
@@ -622,10 +663,15 @@ public class AudioService extends IAudioService.Stub {
                                    BluetoothProfile.A2DP);
        }

        HdmiControlManager hdmiManager =
        mHdmiManager =
                (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
        // Null if device is not Tv.
        mHdmiTvClient = hdmiManager.getTvClient();
        if (mHdmiManager != null) {
            synchronized (mHdmiManager) {
                mHdmiTvClient = mHdmiManager.getTvClient();
                mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
                mHdmiCecSink = false;
            }
        }

        sendMsg(mAudioHandler,
                MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
@@ -670,6 +716,14 @@ public class AudioService extends IAudioService.Stub {
        }
    }

    private void checkAllFixedVolumeDevices()
    {
        int numStreamTypes = AudioSystem.getNumStreamTypes();
        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
            mStreamStates[streamType].checkFixedVolumeDevices();
        }
    }

    private void createStreamStates() {
        int numStreamTypes = AudioSystem.getNumStreamTypes();
        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
@@ -678,6 +732,7 @@ public class AudioService extends IAudioService.Stub {
            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
        }

        checkAllFixedVolumeDevices();
        checkAllAliasStreamVolumes();
    }

@@ -702,19 +757,32 @@ public class AudioService extends IAudioService.Stub {

    private void updateStreamVolumeAlias(boolean updateVolumes) {
        int dtmfStreamAlias;
        if (mVoiceCapable) {
            mStreamVolumeAlias = STREAM_VOLUME_ALIAS;

        switch (mPlatformType) {
        case PLATFORM_VOICE:
            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
            dtmfStreamAlias = AudioSystem.STREAM_RING;
        } else {
            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE;
            break;
        case PLATFORM_TELEVISION:
            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
            break;
        default:
            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
        }

        if (isPlatformTelevision()) {
            mRingerModeAffectedStreams = 0;
        } else {
            if (isInCommunication()) {
                dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
                mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
            } else {
                mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
            }
        }

        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
        if (updateVolumes) {
            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
@@ -768,7 +836,7 @@ public class AudioService extends IAudioService.Stub {
        if (ringerMode != ringerModeFromSettings) {
            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
        }
        if (mUseFixedVolume) {
        if (mUseFixedVolume || isPlatformTelevision()) {
            ringerMode = AudioManager.RINGER_MODE_NORMAL;
        }
        synchronized(mSettingsLock) {
@@ -998,6 +1066,8 @@ public class AudioService extends IAudioService.Stub {

            // Check if volume update should be send to Hdmi system audio.
            int newIndex = mStreamStates[streamType].getIndex(device);
            if (mHdmiManager != null) {
                synchronized (mHdmiManager) {
                    if (mHdmiTvClient != null &&
                        streamTypeAlias == AudioSystem.STREAM_MUSIC &&
                        (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
@@ -1010,6 +1080,19 @@ public class AudioService extends IAudioService.Stub {
                            }
                        }
                    }
                    // mHdmiCecSink true => mHdmiPlaybackClient != null
                    if (mHdmiCecSink &&
                            streamTypeAlias == AudioSystem.STREAM_MUSIC &&
                            oldIndex != newIndex) {
                        synchronized (mHdmiPlaybackClient) {
                            int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
                                                               KeyEvent.KEYCODE_VOLUME_UP;
                            mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
                            mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
                        }
                    }
                }
            }
        }
        int index = mStreamStates[streamType].getIndex(device);
        sendVolumeUpdate(streamType, oldIndex, index, flags);
@@ -1110,6 +1193,8 @@ public class AudioService extends IAudioService.Stub {
                }
            }

            if (mHdmiManager != null) {
                synchronized (mHdmiManager) {
                    if (mHdmiTvClient != null &&
                        streamTypeAlias == AudioSystem.STREAM_MUSIC &&
                        (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
@@ -1122,6 +1207,8 @@ public class AudioService extends IAudioService.Stub {
                            }
                        }
                    }
                }
            }

            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
@@ -1257,7 +1344,7 @@ public class AudioService extends IAudioService.Stub {

    // UI update and Broadcast Intent
    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
        if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) {
        if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
            streamType = AudioSystem.STREAM_NOTIFICATION;
        }

@@ -1346,6 +1433,8 @@ public class AudioService extends IAudioService.Stub {
        }

        if (isStreamAffectedByMute(streamType)) {
            if (mHdmiManager != null) {
                synchronized (mHdmiManager) {
                    if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) {
                        synchronized (mHdmiTvClient) {
                            if (mHdmiSystemAudioSupported) {
@@ -1353,6 +1442,8 @@ public class AudioService extends IAudioService.Stub {
                            }
                        }
                    }
                }
            }
            mStreamStates[streamType].mute(cb, state);
        }
    }
@@ -1472,11 +1563,15 @@ public class AudioService extends IAudioService.Stub {

    /** @see AudioManager#getMasterStreamType()  */
    public int getMasterStreamType() {
        if (mVoiceCapable) {
        switch (mPlatformType) {
            case PLATFORM_VOICE:
                return AudioSystem.STREAM_RING;
        } else {
            return AudioSystem.STREAM_NOTIFICATION;
            case PLATFORM_TELEVISION:
                return AudioSystem.STREAM_MUSIC;
            default:
                break;
        }
        return AudioSystem.STREAM_NOTIFICATION;
    }

    /** @see AudioManager#setMicrophoneMute(boolean) */
@@ -1504,7 +1599,7 @@ public class AudioService extends IAudioService.Stub {

    /** @see AudioManager#setRingerMode(int) */
    public void setRingerMode(int ringerMode) {
        if (mUseFixedVolume) {
        if (mUseFixedVolume || isPlatformTelevision()) {
            return;
        }

@@ -1534,7 +1629,7 @@ public class AudioService extends IAudioService.Stub {
                    ringerMode == AudioManager.RINGER_MODE_NORMAL) {
                    // ring and notifications volume should never be 0 when not silenced
                    // on voice capable devices
                    if (mVoiceCapable &&
                    if (isPlatformVoice() &&
                            mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
                        synchronized (mStreamStates[streamType]) {
                            Set set = mStreamStates[streamType].mIndex.entrySet();
@@ -2041,6 +2136,7 @@ public class AudioService extends IAudioService.Stub {
        // muted by ringer mode have the correct volume
        setRingerModeInt(getRingerMode(), false);

        checkAllFixedVolumeDevices();
        checkAllAliasStreamVolumes();

        synchronized (mSafeMediaVolumeState) {
@@ -2760,11 +2856,18 @@ public class AudioService extends IAudioService.Stub {
                                        (1 << AudioSystem.STREAM_NOTIFICATION)|
                                        (1 << AudioSystem.STREAM_SYSTEM);

        if (mVoiceCapable) {
        switch (mPlatformType) {
            case PLATFORM_VOICE:
                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
        } else {
                break;
            case PLATFORM_TELEVISION:
                ringerModeAffectedStreams = 0;
                break;
            default:
                ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
                break;
        }

        synchronized (mCameraSoundForced) {
            if (mCameraSoundForced) {
                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
@@ -2833,7 +2936,8 @@ public class AudioService extends IAudioService.Stub {
    }

    private int getActiveStreamType(int suggestedStreamType) {
        if (mVoiceCapable) {
        switch (mPlatformType) {
        case PLATFORM_VOICE:
            if (isInCommunication()) {
                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
                        == AudioSystem.FORCE_BT_SCO) {
@@ -2863,12 +2967,26 @@ public class AudioService extends IAudioService.Stub {
                if (DEBUG_VOL)
                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
                return AudioSystem.STREAM_MUSIC;
            } else {
                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
                        + suggestedStreamType);
                return suggestedStreamType;
            }
            break;
        case PLATFORM_TELEVISION:
            if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
                    return AudioSystem.STREAM_MUSIC;
                } else if (mMediaFocusControl.checkUpdateRemoteStateIfActive(
                                                                        AudioSystem.STREAM_MUSIC)) {
                    if (DEBUG_VOL)
                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
                    return STREAM_REMOTE_MUSIC;
                } else {
                    if (DEBUG_VOL) Log.v(TAG,
                            "getActiveStreamType: using STREAM_MUSIC as default");
                    return AudioSystem.STREAM_MUSIC;
                }
            }
            break;
        default:
            if (isInCommunication()) {
                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
                        == AudioSystem.FORCE_BT_SCO) {
@@ -2899,13 +3017,13 @@ public class AudioService extends IAudioService.Stub {
                            "getActiveStreamType: using STREAM_NOTIFICATION as default");
                    return AudioSystem.STREAM_NOTIFICATION;
                }
            } else {
            }
            break;
        }
        if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
                + suggestedStreamType);
        return suggestedStreamType;
    }
        }
    }

    private void broadcastRingerMode(int ringerMode) {
        // Send sticky broadcast
@@ -3098,16 +3216,10 @@ public class AudioService extends IAudioService.Stub {
                        continue;
                    }

                    // ignore settings for fixed volume devices: volume should always be at max or 0
                    if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
                            ((device & mFixedVolumeDevices) != 0)) {
                        mIndex.put(device, (index != 0) ? mIndexMax : 0);
                    } else {
                    mIndex.put(device, getValidIndex(10 * index));
                }
            }
        }
        }

        public void applyDeviceVolume(int device) {
            int index;
@@ -3263,6 +3375,25 @@ public class AudioService extends IAudioService.Stub {
            return mStreamType;
        }

        public void checkFixedVolumeDevices() {
            synchronized (VolumeStreamState.class) {
                // ignore settings for fixed volume devices: volume should always be at max or 0
                if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
                    Set set = mIndex.entrySet();
                    Iterator i = set.iterator();
                    while (i.hasNext()) {
                        Map.Entry entry = (Map.Entry)i.next();
                        int device = ((Integer)entry.getKey()).intValue();
                        int index = ((Integer)entry.getValue()).intValue();
                        if (((device & mFixedVolumeDevices) != 0) && index != 0) {
                            entry.setValue(mIndexMax);
                        }
                        applyDeviceVolume(device);
                    }
                }
            }
        }

        private int getValidIndex(int index) {
            if (index < 0) {
                return 0;
@@ -3469,6 +3600,9 @@ public class AudioService extends IAudioService.Stub {
            if (mUseFixedVolume) {
                return;
            }
            if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
                return;
            }
            System.putIntForUser(mContentResolver,
                      streamState.getSettingNameForDevice(device),
                      (streamState.getIndex(device) + 5)/ 10,
@@ -3825,11 +3959,13 @@ public class AudioService extends IAudioService.Stub {
                                mDockAudioMediaEnabled ?
                                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
                    }

                    if (mHdmiManager != null) {
                        synchronized (mHdmiManager) {
                            if (mHdmiTvClient != null) {
                                setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
                            }

                        }
                    }
                    // indicate the end of reconfiguration phase to audio HAL
                    AudioSystem.setParameters("restarting=false");
                    break;
@@ -4275,6 +4411,27 @@ public class AudioService extends IAudioService.Stub {
                            null,
                            MUSIC_ACTIVE_POLL_PERIOD_MS);
                }
                // Television devices without CEC service apply software volume on HDMI output
                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
                    mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
                    checkAllFixedVolumeDevices();
                    if (mHdmiManager != null) {
                        synchronized (mHdmiManager) {
                            if (mHdmiPlaybackClient != null) {
                                mHdmiCecSink = false;
                                mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
                            }
                        }
                    }
                }
            } else {
                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
                    if (mHdmiManager != null) {
                        synchronized (mHdmiManager) {
                            mHdmiCecSink = false;
                        }
                    }
                }
            }
            if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
                sendDeviceConnectionIntent(device, state, name);
@@ -4577,6 +4734,7 @@ public class AudioService extends IAudioService.Stub {
                    if (cameraSoundForced != mCameraSoundForced) {
                        mCameraSoundForced = cameraSoundForced;

                        if (!isPlatformTelevision()) {
                            VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
                            if (cameraSoundForced) {
                                s.setAllIndexesToMax();
@@ -4589,6 +4747,7 @@ public class AudioService extends IAudioService.Stub {
                            }
                            // take new state into account for streams muted by ringer mode
                            setRingerModeInt(getRingerMode(), false);
                        }

                        sendMsg(mAudioHandler,
                                MSG_SET_FORCE_USE,
@@ -4804,27 +4963,57 @@ public class AudioService extends IAudioService.Stub {
    // to HdmiControlService so that audio recevier can handle volume change.
    //==========================================================================================

    private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
        public void onComplete(int status) {
            if (mHdmiManager != null) {
                synchronized (mHdmiManager) {
                    mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
                    // Television devices without CEC service apply software volume on HDMI output
                    if (isPlatformTelevision() && !mHdmiCecSink) {
                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
                    }
                    checkAllFixedVolumeDevices();
                }
            }
        }
    };

    // If HDMI-CEC system audio is supported
    private boolean mHdmiSystemAudioSupported = false;
    // Set only when device is tv.
    private HdmiTvClient mHdmiTvClient;
    // true if the device has system feature PackageManager.FEATURE_TELEVISION.
    // cached HdmiControlManager interface
    private HdmiControlManager mHdmiManager;
    // Set only when device is a set-top box.
    private HdmiPlaybackClient mHdmiPlaybackClient;
    // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
    private boolean mHdmiCecSink;

    private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();

    @Override
    public int setHdmiSystemAudioSupported(boolean on) {
        int device = AudioSystem.DEVICE_NONE;
        if (mHdmiManager != null) {
            synchronized (mHdmiManager) {
                if (mHdmiTvClient == null) {
                    Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
            return AudioSystem.DEVICE_NONE;
                    return device;
                }

                synchronized (mHdmiTvClient) {
            if (mHdmiSystemAudioSupported == on) {
                return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
            }
                    if (mHdmiSystemAudioSupported != on) {
                        mHdmiSystemAudioSupported = on;
                        AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
                    on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : AudioSystem.FORCE_NONE);
                                on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
                                     AudioSystem.FORCE_NONE);
                    }
                    device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
                }
        return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
            }
        }
        return device;
    }

    //==========================================================================================