From 8d7c28fe8339fc28b38f62d3d4fba6512a8e7dd4 Mon Sep 17 00:00:00 2001
From: amerhifi <amer@highfidelity.io>
Date: Thu, 19 Sep 2019 14:19:43 -0700
Subject: [PATCH] fixed audio switching issues. removed risky access to
 properties. adressing comments

---
 libraries/audio-client/src/AudioClient.cpp    | 104 ++++++------------
 libraries/audio-client/src/AudioClient.h      |   7 +-
 .../audio-client/src/HifiAudioDeviceInfo.h    |  10 +-
 3 files changed, 41 insertions(+), 80 deletions(-)

diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index 570a7c6c92..a8a627ffab 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -119,38 +119,19 @@ void AudioClient::checkDevices() {
 
     auto inputDevices = getAvailableDevices(QAudio::AudioInput);
     auto outputDevices = getAvailableDevices(QAudio::AudioOutput);
+  
+    auto defInput = defaultAudioDeviceForMode(QAudio::AudioInput);
+    defInput.setIsDefault(true);
 
-    {
-        
-        //is the current device the default?, if so has the underlying QAudioDeviceInfo changed from the os call
-        if (_inputDeviceInfo.isDefault()) {
-            auto defInput = defaultAudioDeviceForMode(QAudio::AudioInput);
-            
-            //Has the default device changed
-            if (_defaultInputDevice.getDevice() != defInput.getDevice()) {
-                qDebug() << "Changing Current Default device  " << _defaultInputDevice.deviceName();
-                _defaultInputDevice.setDevice(defInput.getDevice());
-                qDebug() << "NEW Default device  " << _defaultInputDevice.deviceName();
-                QMetaObject::invokeMethod(this, "switchAudioDevice", Qt::DirectConnection, Q_ARG(QAudio::Mode, QAudio::AudioInput),   Q_ARG(const HifiAudioDeviceInfo&, _defaultInputDevice));
-            }
-        }
-        
-        //is the current device the default?, if so has the underlying QAudioDeviceInfo changed from the os call
-        if (_outputDeviceInfo.isDefault() && _outputDeviceInfo == _defaultOutputDevice) {
-            auto defOutput = defaultAudioDeviceForMode(QAudio::AudioOutput);
-
-            if (_defaultOutputDevice.getDevice() != defOutput.getDevice()) {
-                qDebug() << "Changing Current Default device  " << _defaultOutputDevice.deviceName();
-                _defaultOutputDevice.setDevice(defOutput.getDevice());
-                qDebug() << "NEW Default device  " << _defaultOutputDevice.deviceName();
-                QMetaObject::invokeMethod(this, "switchAudioDevice",Qt::DirectConnection, Q_ARG(QAudio::Mode, QAudio::AudioOutput), Q_ARG(const HifiAudioDeviceInfo&, _defaultOutputDevice));
-            }
-        }
-    }
-
+    auto defOutput = defaultAudioDeviceForMode(QAudio::AudioOutput);
+    defOutput.setIsDefault(true);
+   
     //add the pseudo device to the list of devices
-    inputDevices.push_front(_defaultInputDevice);
-    outputDevices.push_front(_defaultOutputDevice);
+    inputDevices.push_front(defInput);
+    outputDevices.push_front(defOutput);
+
+    QMetaObject::invokeMethod(this, "changeDefault",  Q_ARG(HifiAudioDeviceInfo, defInput), Q_ARG(QAudio::Mode, QAudio::AudioInput));
+    QMetaObject::invokeMethod(this, "changeDefault",  Q_ARG(HifiAudioDeviceInfo, defOutput), Q_ARG(QAudio::Mode, QAudio::AudioOutput));
 
     Lock lock(_deviceMutex);
     if (inputDevices != _inputDevices) {
@@ -371,14 +352,6 @@ AudioClient::AudioClient() :
 
     connect(&_receivedAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioClient::handleMismatchAudioFormat);
 
-    _defaultOutputDevice = defaultAudioDeviceForMode(QAudio::AudioOutput);
-    _defaultOutputDevice.setIsDefault(true);
-    _defaultOutputDevice.setMode(QAudio::AudioOutput);
-
-    _defaultInputDevice = defaultAudioDeviceForMode(QAudio::AudioInput);
-    _defaultInputDevice.setIsDefault(true);
-    _defaultInputDevice.setMode(QAudio::AudioInput);
- 
     // initialize wasapi; if getAvailableDevices is called from the CheckDevicesThread before this, it will crash
     getAvailableDevices(QAudio::AudioInput);
     getAvailableDevices(QAudio::AudioOutput);
@@ -481,19 +454,6 @@ void AudioClient::setAudioPaused(bool pause) {
     }
 }
 
-
-HifiAudioDeviceInfo AudioClient::getNamedAudioDevice(QAudio::Mode mode, const QString& deviceName) {
-    HifiAudioDeviceInfo result;
-
-    foreach(HifiAudioDeviceInfo audioDevice, getAudioDevices(mode)) {
-        if (audioDevice.deviceName().trimmed() == deviceName.trimmed()) {
-            result = audioDevice;
-            break;
-        }
-    }
-    return result;
-}
-
 HifiAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) {
     HifiAudioDeviceInfo result;
     foreach (HifiAudioDeviceInfo audioDevice, getAvailableDevices(mode)) {
@@ -1041,13 +1001,15 @@ void AudioClient::selectAudioFormat(const QString& selectedCodecName) {
 
 }
 
+void AudioClient::changeDefault(HifiAudioDeviceInfo newDefault, QAudio::Mode mode) {
+    HifiAudioDeviceInfo currentDevice = mode == QAudio::AudioInput ? _inputDeviceInfo : _outputDeviceInfo;
+    if (currentDevice.isDefault() && currentDevice.getDevice() != newDefault.getDevice()) {
+        switchAudioDevice(mode, newDefault);
+    }
+}
+
 bool AudioClient::switchAudioDevice(QAudio::Mode mode, const HifiAudioDeviceInfo& deviceInfo) {
     auto device = deviceInfo;
-
-   if (device.getDevice().isNull()) {
-        device = defaultAudioDeviceForMode(mode);
-    }
-
     if (mode == QAudio::AudioInput) {
         return switchInputToAudioDevice(device);
     } else {
@@ -1055,10 +1017,6 @@ bool AudioClient::switchAudioDevice(QAudio::Mode mode, const HifiAudioDeviceInfo
     }
 }
 
-bool AudioClient::switchAudioDevice(QAudio::Mode mode, const QString& deviceName) {
-    return switchAudioDevice(mode, getNamedAudioDevice(mode, deviceName));
-}
-
 void AudioClient::configureReverb() {
     ReverbParameters p;
 
@@ -1864,7 +1822,7 @@ void AudioClient::outputFormatChanged() {
 bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDeviceInfo, bool isShutdownRequest) {
     Q_ASSERT_X(QThread::currentThread() == thread(), Q_FUNC_INFO, "Function invoked on wrong thread");
 
-    qCDebug(audioclient) << __FUNCTION__ << "inputDeviceInfo: [" << inputDeviceInfo.deviceName() <<"----"<<inputDeviceInfo.getDevice().deviceName() << "]";
+    qCDebug(audioclient) << __FUNCTION__ << "inputDeviceInfo: [" << _inputDeviceInfo.deviceName() <<"----"<<inputDeviceInfo.getDevice().deviceName() << "]";
     bool supportedFormat = false;
 
     // NOTE: device start() uses the Qt internal device list
@@ -1885,8 +1843,6 @@ bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDevice
         _audioInput->deleteLater();
         _audioInput = NULL;
         _numInputCallbackBytes = 0;
-
-        _inputDeviceInfo = HifiAudioDeviceInfo();
     }
 
     if (_dummyAudioInput) {
@@ -1919,10 +1875,14 @@ bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDevice
 
     if (!inputDeviceInfo.getDevice().isNull()) {
         qCDebug(audioclient) << "The audio input device " << inputDeviceInfo.deviceName() << "is available.";
+      
+        bool doEmit = _inputDeviceInfo.deviceName() != inputDeviceInfo.deviceName();
         _inputDeviceInfo = inputDeviceInfo;
-        emit deviceChanged(QAudio::AudioInput, _inputDeviceInfo);
+        if (doEmit) {
+            emit deviceChanged(QAudio::AudioInput, _inputDeviceInfo);
+        }
 
-        if (adjustedFormatForAudioDevice(inputDeviceInfo.getDevice(), _desiredInputFormat, _inputFormat)) {
+        if (adjustedFormatForAudioDevice(_inputDeviceInfo.getDevice(), _desiredInputFormat, _inputFormat)) {
             qCDebug(audioclient) << "The format to be used for audio input is" << _inputFormat;
 
             // we've got the best we can get for input
@@ -1947,7 +1907,7 @@ bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDevice
 
             // if the user wants stereo but this device can't provide then bail
             if (!_isStereoInput || _inputFormat.channelCount() == 2) {
-                _audioInput = new QAudioInput(inputDeviceInfo.getDevice(), _inputFormat, this);
+                _audioInput = new QAudioInput(_inputDeviceInfo.getDevice(), _inputFormat, this);
                 _numInputCallbackBytes = calculateNumberOfInputCallbackBytes(_inputFormat);
                 _audioInput->setBufferSize(_numInputCallbackBytes);
                 // different audio input devices may have different volumes
@@ -2124,9 +2084,6 @@ bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDevi
 
         delete[] _localOutputMixBuffer;
         _localOutputMixBuffer = NULL;
-
-        _outputDeviceInfo = HifiAudioDeviceInfo();
-        _outputDeviceInfo.setDevice(QAudioDeviceInfo());
     }
 
     // cleanup any resamplers
@@ -2152,10 +2109,13 @@ bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDevi
 
     if (!outputDeviceInfo.getDevice().isNull()) {
         qCDebug(audioclient) << "The audio output device " << outputDeviceInfo.deviceName() << "is available.";
+        bool doEmit = _outputDeviceInfo.deviceName() != outputDeviceInfo.deviceName();
         _outputDeviceInfo = outputDeviceInfo;
-        emit deviceChanged(QAudio::AudioOutput, _outputDeviceInfo);
+        if (doEmit) {
+            emit deviceChanged(QAudio::AudioOutput, _outputDeviceInfo);
+        }
 
-        if (adjustedFormatForAudioDevice(outputDeviceInfo.getDevice(), _desiredOutputFormat, _outputFormat)) {
+        if (adjustedFormatForAudioDevice(_outputDeviceInfo.getDevice(), _desiredOutputFormat, _outputFormat)) {
             qCDebug(audioclient) << "The format to be used for audio output is" << _outputFormat;
 
             // we've got the best we can get for input
@@ -2177,7 +2137,7 @@ bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDevi
             outputFormatChanged();
 
             // setup our general output device for audio-mixer audio
-            _audioOutput = new QAudioOutput(outputDeviceInfo.getDevice(), _outputFormat, this);
+            _audioOutput = new QAudioOutput(_outputDeviceInfo.getDevice(), _outputFormat, this);
 
             int deviceChannelCount = _outputFormat.channelCount();
             int frameSize = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * deviceChannelCount * _outputFormat.sampleRate()) / _desiredOutputFormat.sampleRate();
diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h
index 038914d639..de3e98420d 100644
--- a/libraries/audio-client/src/AudioClient.h
+++ b/libraries/audio-client/src/AudioClient.h
@@ -126,8 +126,6 @@ public:
 
     const MixedProcessedAudioStream& getReceivedAudioStream() const { return _receivedAudioStream; }
     MixedProcessedAudioStream& getReceivedAudioStream() { return _receivedAudioStream; }
-    
-    HifiAudioDeviceInfo getNamedAudioDevice(QAudio::Mode mode, const QString& deviceName);
 
     const QAudioFormat& getOutputFormat() const { return _outputFormat; }
 
@@ -236,10 +234,10 @@ public slots:
     int setOutputBufferSize(int numFrames, bool persist = true);
 
     bool shouldLoopbackInjectors() override { return _shouldEchoToServer; }
+    Q_INVOKABLE void changeDefault(HifiAudioDeviceInfo newDefault, QAudio::Mode mode);
 
     // calling with a null QAudioDevice will use the system default
     bool switchAudioDevice(QAudio::Mode mode, const HifiAudioDeviceInfo& deviceInfo = HifiAudioDeviceInfo());
-    bool switchAudioDevice(QAudio::Mode mode, const QString& deviceName);
 
     // Qt opensles plugin is not able to detect when the headset is plugged in
     void setHeadsetPluggedIn(bool pluggedIn);
@@ -465,9 +463,6 @@ private:
     HifiAudioDeviceInfo _inputDeviceInfo;
     HifiAudioDeviceInfo _outputDeviceInfo;
 
-    HifiAudioDeviceInfo _defaultInputDevice;
-    HifiAudioDeviceInfo _defaultOutputDevice;
-
     QList<HifiAudioDeviceInfo> _inputDevices;
     QList<HifiAudioDeviceInfo> _outputDevices;
 
diff --git a/libraries/audio-client/src/HifiAudioDeviceInfo.h b/libraries/audio-client/src/HifiAudioDeviceInfo.h
index 74fe2b37d0..d923b4231c 100644
--- a/libraries/audio-client/src/HifiAudioDeviceInfo.h
+++ b/libraries/audio-client/src/HifiAudioDeviceInfo.h
@@ -38,9 +38,15 @@ public:
 
     void setMode(QAudio::Mode mode) { _mode = mode; }
     void setIsDefault(bool isDefault = false) { _isDefault = isDefault; }
-   
     void setDevice(QAudioDeviceInfo devInfo);
-    QString deviceName() const { return _audioDeviceInfo.deviceName(); }
+    QString deviceName() const {
+        if (_isDefault) {
+            return "default";
+        }
+        else {
+            return _audioDeviceInfo.deviceName();
+        }
+    }
     QAudioDeviceInfo getDevice() const { return _audioDeviceInfo; }
     bool isDefault() const { return _isDefault; }
     QAudio::Mode getMode() const { return _mode; }