diff --git a/interface/resources/qml/hifi/Audio.qml b/interface/resources/qml/hifi/Audio.qml index d0c3122100..66760ff290 100644 --- a/interface/resources/qml/hifi/Audio.qml +++ b/interface/resources/qml/hifi/Audio.qml @@ -35,11 +35,6 @@ Rectangle { property string title: "Audio Options" signal sendToScript(var message); - //set models after Components is shown - Component.onCompleted: { - refreshTimer.start() - refreshTimerOutput.start() - } Component { id: separator @@ -84,7 +79,7 @@ Rectangle { } Connections { - target: AvatarInputs + target: AvatarInputs !== undefined ? AvatarInputs : null onShowAudioToolsChanged: { audioTools.checkbox.checked = showAudioTools } @@ -105,10 +100,12 @@ Rectangle { id: audioTools width: parent.width anchors { left: parent.left; right: parent.right; leftMargin: 30 } - checkbox.checked: AvatarInputs.showAudioTools + checkbox.checked: AvatarInputs !== undefined ? AvatarInputs.showAudioTools : false text.text: qsTr("Show audio level meter") onCheckBoxClicked: { - AvatarInputs.showAudioTools = checked + if (AvatarInputs !== undefined) { + AvatarInputs.showAudioTools = checked + } } } @@ -138,30 +135,34 @@ Rectangle { } ListView { - Timer { - id: refreshTimer - interval: 1 - repeat: false - onTriggered: { - //refresh model - inputAudioListView.model = undefined - inputAudioListView.model = AudioDevice.inputAudioDevices - } - } id: inputAudioListView anchors { left: parent.left; right: parent.right; leftMargin: 70 } height: 125 - spacing: 16 + spacing: 0 clip: true snapMode: ListView.SnapToItem - delegate: AudioCheckbox { + model: AudioDevice + delegate: Item { width: parent.width - checkbox.checked: (modelData === AudioDevice.getInputDevice()) - text.text: modelData - onCheckBoxClicked: { - if (checked) { - AudioDevice.setInputDevice(modelData) - refreshTimer.start() + visible: devicemode === 0 + height: visible ? 36 : 0 + + AudioCheckbox { + id: cbin + anchors.verticalCenter: parent.verticalCenter + Binding { + target: cbin.checkbox + property: 'checked' + value: devicechecked + } + + width: parent.width + cbchecked: devicechecked + text.text: devicename + onCheckBoxClicked: { + if (checked) { + AudioDevice.setInputDeviceAsync(devicename) + } } } } @@ -191,31 +192,33 @@ Rectangle { text: qsTr("CHOOSE OUTPUT DEVICE") } } + ListView { id: outputAudioListView - Timer { - id: refreshTimerOutput - interval: 1 - repeat: false - onTriggered: { - //refresh model - outputAudioListView.model = undefined - outputAudioListView.model = AudioDevice.outputAudioDevices - } - } anchors { left: parent.left; right: parent.right; leftMargin: 70 } height: 250 - spacing: 16 + spacing: 0 clip: true snapMode: ListView.SnapToItem - delegate: AudioCheckbox { + model: AudioDevice + delegate: Item { width: parent.width - checkbox.checked: (modelData === AudioDevice.getOutputDevice()) - text.text: modelData - onCheckBoxClicked: { - if (checked) { - AudioDevice.setOutputDevice(modelData) - refreshTimerOutput.start() + visible: devicemode === 1 + height: visible ? 36 : 0 + AudioCheckbox { + id: cbout + width: parent.width + anchors.verticalCenter: parent.verticalCenter + Binding { + target: cbout.checkbox + property: 'checked' + value: devicechecked + } + text.text: devicename + onCheckBoxClicked: { + if (checked) { + AudioDevice.setOutputDeviceAsync(devicename) + } } } } diff --git a/interface/resources/qml/hifi/components/AudioCheckbox.qml b/interface/resources/qml/hifi/components/AudioCheckbox.qml index a8e0441e0a..b037fe4c7d 100644 --- a/interface/resources/qml/hifi/components/AudioCheckbox.qml +++ b/interface/resources/qml/hifi/components/AudioCheckbox.qml @@ -8,6 +8,7 @@ Row { id: row spacing: 16 property alias checkbox: cb + property alias cbchecked: cb.checked property alias text: txt signal checkBoxClicked(bool checked) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d3a690b020..32f6d9554e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2053,6 +2053,8 @@ void Application::initializeUi() { rootContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor()); + rootContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance()); + if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { rootContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get())); } diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.cpp b/interface/src/scripting/AudioDeviceScriptingInterface.cpp index cbb08c0af0..05168b0d4c 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.cpp +++ b/interface/src/scripting/AudioDeviceScriptingInterface.cpp @@ -11,21 +11,19 @@ #include "AudioClient.h" #include "AudioDeviceScriptingInterface.h" - +#include "SettingsScriptingInterface.h" AudioDeviceScriptingInterface* AudioDeviceScriptingInterface::getInstance() { static AudioDeviceScriptingInterface sharedInstance; return &sharedInstance; } -QStringList AudioDeviceScriptingInterface::inputAudioDevices() const -{ - return DependencyManager::get()->getDeviceNames(QAudio::AudioInput).toList();; +QStringList AudioDeviceScriptingInterface::inputAudioDevices() const { + return _inputAudioDevices; } -QStringList AudioDeviceScriptingInterface::outputAudioDevices() const -{ - return DependencyManager::get()->getDeviceNames(QAudio::AudioOutput).toList();; +QStringList AudioDeviceScriptingInterface::outputAudioDevices() const { + return _outputAudioDevices; } bool AudioDeviceScriptingInterface::muted() @@ -33,11 +31,27 @@ bool AudioDeviceScriptingInterface::muted() return getMuted(); } -AudioDeviceScriptingInterface::AudioDeviceScriptingInterface() { +AudioDeviceScriptingInterface::AudioDeviceScriptingInterface(): QAbstractListModel(nullptr) { connect(DependencyManager::get().data(), &AudioClient::muteToggled, this, &AudioDeviceScriptingInterface::muteToggled); connect(DependencyManager::get().data(), &AudioClient::deviceChanged, - this, &AudioDeviceScriptingInterface::deviceChanged); + this, &AudioDeviceScriptingInterface::onDeviceChanged, Qt::QueuedConnection); + connect(DependencyManager::get().data(), &AudioClient::currentInputDeviceChanged, + this, &AudioDeviceScriptingInterface::onCurrentInputDeviceChanged, Qt::QueuedConnection); + connect(DependencyManager::get().data(), &AudioClient::currentOutputDeviceChanged, + this, &AudioDeviceScriptingInterface::onCurrentOutputDeviceChanged, Qt::QueuedConnection); + //fill up model + onDeviceChanged(); + //set up previously saved device + SettingsScriptingInterface* settings = SettingsScriptingInterface::getInstance(); + const QString inDevice = settings->getValue("audio_input_device").toString(); + if (inDevice != _currentInputDevice) { + setInputDeviceAsync(inDevice); + } + const QString outDevice = settings->getValue("audio_output_device").toString(); + if (outDevice != _currentOutputDevice) { + setOutputDeviceAsync(outDevice); + } } bool AudioDeviceScriptingInterface::setInputDevice(const QString& deviceName) { @@ -58,6 +72,43 @@ bool AudioDeviceScriptingInterface::setOutputDevice(const QString& deviceName) { return result; } +bool AudioDeviceScriptingInterface::setDeviceFromMenu(const QString& deviceMenuName) { + QAudio::Mode mode; + + if (deviceMenuName.indexOf("for Output") != -1) { + mode = QAudio::AudioOutput; + } else if (deviceMenuName.indexOf("for Input") != -1) { + mode = QAudio::AudioInput; + } else { + return false; + } + + for (ScriptingAudioDeviceInfo di: _devices) { + if (mode == di.mode && deviceMenuName.contains(di.name)) { + if (mode == QAudio::AudioOutput) { + setOutputDeviceAsync(di.name); + } else { + setInputDeviceAsync(di.name); + } + return true; + } + } + + return false; +} + +void AudioDeviceScriptingInterface::setInputDeviceAsync(const QString& deviceName) { + QMetaObject::invokeMethod(DependencyManager::get().data(), "switchInputToAudioDevice", + Qt::QueuedConnection, + Q_ARG(const QString&, deviceName)); +} + +void AudioDeviceScriptingInterface::setOutputDeviceAsync(const QString& deviceName) { + QMetaObject::invokeMethod(DependencyManager::get().data(), "switchOutputToAudioDevice", + Qt::QueuedConnection, + Q_ARG(const QString&, deviceName)); +} + QString AudioDeviceScriptingInterface::getInputDevice() { return DependencyManager::get()->getDeviceName(QAudio::AudioInput); } @@ -116,3 +167,105 @@ void AudioDeviceScriptingInterface::setMuted(bool muted) bool AudioDeviceScriptingInterface::getMuted() { return DependencyManager::get()->isMuted(); } + +QVariant AudioDeviceScriptingInterface::data(const QModelIndex& index, int role) const { + //sanity + if (!index.isValid() || index.row() >= _devices.size()) + return QVariant(); + + + if (role == Qt::DisplayRole || role == DisplayNameRole) { + return _devices.at(index.row()).name; + } else if (role == SelectedRole) { + return _devices.at(index.row()).selected; + } else if (role == AudioModeRole) { + return (int)_devices.at(index.row()).mode; + } + return QVariant(); +} + +int AudioDeviceScriptingInterface::rowCount(const QModelIndex& parent) const { + Q_UNUSED(parent) + return _devices.size(); +} + +QHash AudioDeviceScriptingInterface::roleNames() const { + QHash roles; + roles.insert(DisplayNameRole, "devicename"); + roles.insert(SelectedRole, "devicechecked"); + roles.insert(AudioModeRole, "devicemode"); + return roles; +} + +void AudioDeviceScriptingInterface::onDeviceChanged() +{ + beginResetModel(); + _outputAudioDevices.clear(); + _devices.clear(); + _currentOutputDevice = getOutputDevice(); + for (QString name: getOutputDevices()) { + ScriptingAudioDeviceInfo di; + di.name = name; + di.selected = (name == _currentOutputDevice); + di.mode = QAudio::AudioOutput; + _devices.append(di); + _outputAudioDevices.append(name); + } + emit outputAudioDevicesChanged(_outputAudioDevices); + + _inputAudioDevices.clear(); + _currentInputDevice = getInputDevice(); + for (QString name: getInputDevices()) { + ScriptingAudioDeviceInfo di; + di.name = name; + di.selected = (name == _currentInputDevice); + di.mode = QAudio::AudioInput; + _devices.append(di); + _inputAudioDevices.append(name); + } + emit inputAudioDevicesChanged(_inputAudioDevices); + + endResetModel(); + emit deviceChanged(); +} + +void AudioDeviceScriptingInterface::onCurrentInputDeviceChanged(const QString& name) +{ + currentDeviceUpdate(name, QAudio::AudioInput); + //we got a signal that device changed. Save it now + SettingsScriptingInterface* settings = SettingsScriptingInterface::getInstance(); + settings->setValue("audio_input_device", name); + emit currentInputDeviceChanged(name); +} + +void AudioDeviceScriptingInterface::onCurrentOutputDeviceChanged(const QString& name) +{ + currentDeviceUpdate(name, QAudio::AudioOutput); + //we got a signal that device changed. Save it now + SettingsScriptingInterface* settings = SettingsScriptingInterface::getInstance(); + settings->setValue("audio_output_device", name); + emit currentOutputDeviceChanged(name); +} + +void AudioDeviceScriptingInterface::currentDeviceUpdate(const QString& name, QAudio::Mode mode) +{ + QVector role; + role.append(SelectedRole); + + for (int i = 0; i < _devices.size(); i++) { + ScriptingAudioDeviceInfo di = _devices.at(i); + if (di.mode != mode) { + continue; + } + if (di.selected && di.name != name ) { + di.selected = false; + _devices[i] = di; + emit dataChanged(index(i, 0), index(i, 0), role); + } + if (di.name == name) { + di.selected = true; + _devices[i] = di; + emit dataChanged(index(i, 0), index(i, 0), role); + } + } +} diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.h b/interface/src/scripting/AudioDeviceScriptingInterface.h index 4d1d47dcba..f912c35288 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.h +++ b/interface/src/scripting/AudioDeviceScriptingInterface.h @@ -15,10 +15,18 @@ #include #include #include +#include +#include class AudioEffectOptions; -class AudioDeviceScriptingInterface : public QObject { +struct ScriptingAudioDeviceInfo { + QString name; + bool selected; + QAudio::Mode mode; +}; + +class AudioDeviceScriptingInterface : public QAbstractListModel { Q_OBJECT Q_PROPERTY(QStringList inputAudioDevices READ inputAudioDevices NOTIFY inputAudioDevicesChanged) @@ -32,9 +40,26 @@ public: QStringList outputAudioDevices() const; bool muted(); + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QHash roleNames() const override; + + enum Roles { + DisplayNameRole = Qt::UserRole, + SelectedRole, + AudioModeRole + }; + +private slots: + void onDeviceChanged(); + void onCurrentInputDeviceChanged(const QString& name); + void onCurrentOutputDeviceChanged(const QString& name); + void currentDeviceUpdate(const QString& name, QAudio::Mode mode); + public slots: bool setInputDevice(const QString& deviceName); bool setOutputDevice(const QString& deviceName); + bool setDeviceFromMenu(const QString& deviceMenuName); QString getInputDevice(); QString getOutputDevice(); @@ -55,15 +80,28 @@ public slots: void setMuted(bool muted); + void setInputDeviceAsync(const QString& deviceName); + void setOutputDeviceAsync(const QString& deviceName); private: AudioDeviceScriptingInterface(); signals: void muteToggled(); void deviceChanged(); + void currentInputDeviceChanged(const QString& name); + void currentOutputDeviceChanged(const QString& name); void mutedChanged(bool muted); void inputAudioDevicesChanged(QStringList inputAudioDevices); void outputAudioDevicesChanged(QStringList outputAudioDevices); + +private: + QVector _devices; + + QStringList _inputAudioDevices; + QStringList _outputAudioDevices; + + QString _currentInputDevice; + QString _currentOutputDevice; }; #endif // hifi_AudioDeviceScriptingInterface_h diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index dae37ffc4b..1282dbb2dc 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -799,7 +799,8 @@ QString AudioClient::getDefaultDeviceName(QAudio::Mode mode) { QVector AudioClient::getDeviceNames(QAudio::Mode mode) { QVector deviceNames; - foreach(QAudioDeviceInfo audioDevice, getAvailableDevices(mode)) { + const QList &availableDevice = getAvailableDevices(mode); + foreach(const QAudioDeviceInfo &audioDevice, availableDevice) { deviceNames << audioDevice.deviceName().trimmed(); } return deviceNames; @@ -1402,7 +1403,7 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn _audioInput->stop(); _inputDevice = NULL; - delete _audioInput; + _audioInput->deleteLater(); _audioInput = NULL; _numInputCallbackBytes = 0; @@ -1418,6 +1419,7 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn if (!inputDeviceInfo.isNull()) { qCDebug(audioclient) << "The audio input device " << inputDeviceInfo.deviceName() << "is available."; _inputAudioDeviceName = inputDeviceInfo.deviceName().trimmed(); + emit currentInputDeviceChanged(_inputAudioDeviceName); if (adjustedFormatForAudioDevice(inputDeviceInfo, _desiredInputFormat, _inputFormat)) { qCDebug(audioclient) << "The format to be used for audio input is" << _inputFormat; @@ -1506,11 +1508,13 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice if (_audioOutput) { _audioOutput->stop(); - delete _audioOutput; + //must be deleted in next eventloop cycle when its called from notify() + _audioOutput->deleteLater(); _audioOutput = NULL; _loopbackOutputDevice = NULL; - delete _loopbackAudioOutput; + //must be deleted in next eventloop cycle when its called from notify() + _loopbackAudioOutput->deleteLater(); _loopbackAudioOutput = NULL; delete[] _outputMixBuffer; @@ -1535,6 +1539,7 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice if (!outputDeviceInfo.isNull()) { qCDebug(audioclient) << "The audio output device " << outputDeviceInfo.deviceName() << "is available."; _outputAudioDeviceName = outputDeviceInfo.deviceName().trimmed(); + emit currentOutputDeviceChanged(_outputAudioDeviceName); if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) { qCDebug(audioclient) << "The format to be used for audio output is" << _outputFormat; diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 0e5363e0ff..47808767b3 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -222,6 +222,9 @@ signals: void muteEnvironmentRequested(glm::vec3 position, float radius); + void currentOutputDeviceChanged(const QString& name); + void currentInputDeviceChanged(const QString& name); + protected: AudioClient(); ~AudioClient(); diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index e97bc329c6..5ec8ce4b12 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -24,6 +24,7 @@ class AudioScriptingInterface : public QObject, public Dependency { SINGLETON_DEPENDENCY public: + virtual ~AudioScriptingInterface() {} void setLocalAudioInterface(AbstractAudioInterface* audioInterface) { _localAudioInterface = audioInterface; } protected: diff --git a/scripts/system/selectAudioDevice.js b/scripts/system/selectAudioDevice.js index 2dd426932f..2d40795692 100644 --- a/scripts/system/selectAudioDevice.js +++ b/scripts/system/selectAudioDevice.js @@ -17,32 +17,22 @@ const INPUT = "Input"; const OUTPUT = "Output"; -function parseMenuItem(item) { - const USE = "Use "; - const FOR_INPUT = " for " + INPUT; - const FOR_OUTPUT = " for " + OUTPUT; - if (item.slice(0, USE.length) == USE) { - if (item.slice(-FOR_INPUT.length) == FOR_INPUT) { - return { device: item.slice(USE.length, -FOR_INPUT.length), mode: INPUT }; - } else if (item.slice(-FOR_OUTPUT.length) == FOR_OUTPUT) { - return { device: item.slice(USE.length, -FOR_OUTPUT.length), mode: OUTPUT }; - } - } -} - +const SELECT_AUDIO_SCRIPT_STARTUP_TIMEOUT = 300; // // VAR DEFINITIONS // var debugPrintStatements = true; const INPUT_DEVICE_SETTING = "audio_input_device"; const OUTPUT_DEVICE_SETTING = "audio_output_device"; -var audioDevicesList = []; +var audioDevicesList = []; // placeholder for menu items var wasHmdActive = false; // assume it's not active to start var switchedAudioInputToHMD = false; var switchedAudioOutputToHMD = false; var previousSelectedInputAudioDevice = ""; var previousSelectedOutputAudioDevice = ""; -var skipMenuEvents = true; + +var interfaceInputDevice = ""; +var interfaceOutputDevice = ""; // // BEGIN FUNCTION DEFINITIONS @@ -56,56 +46,37 @@ function debug() { function setupAudioMenus() { // menu events can be triggered asynchronously; skip them for 200ms to avoid recursion and false switches - skipMenuEvents = true; - Script.setTimeout(function() { skipMenuEvents = false; }, 200); - removeAudioMenus(); // Setup audio input devices Menu.addSeparator("Audio", "Input Audio Device"); - var inputDevices = AudioDevice.getInputDevices(); - for (var i = 0; i < inputDevices.length; i++) { - var audioDeviceMenuString = "Use " + inputDevices[i] + " for Input"; + var currentInputDevice = AudioDevice.getInputDevice() + for (var i = 0; i < AudioDevice.inputAudioDevices.length; i++) { + var audioDeviceMenuString = "Use " + AudioDevice.inputAudioDevices[i] + " for Input"; Menu.addMenuItem({ menuName: "Audio", menuItemName: audioDeviceMenuString, isCheckable: true, - isChecked: inputDevices[i] == AudioDevice.getInputDevice() + isChecked: AudioDevice.inputAudioDevices[i] == currentInputDevice }); audioDevicesList.push(audioDeviceMenuString); } // Setup audio output devices Menu.addSeparator("Audio", "Output Audio Device"); - var outputDevices = AudioDevice.getOutputDevices(); - for (var i = 0; i < outputDevices.length; i++) { - var audioDeviceMenuString = "Use " + outputDevices[i] + " for Output"; + var currentOutputDevice = AudioDevice.getOutputDevice() + for (var i = 0; i < AudioDevice.outputAudioDevices.length; i++) { + var audioDeviceMenuString = "Use " + AudioDevice.outputAudioDevices[i] + " for Output"; Menu.addMenuItem({ menuName: "Audio", menuItemName: audioDeviceMenuString, isCheckable: true, - isChecked: outputDevices[i] == AudioDevice.getOutputDevice() + isChecked: AudioDevice.outputAudioDevices[i] == currentOutputDevice }); audioDevicesList.push(audioDeviceMenuString); } } -function checkDeviceMismatch() { - var inputDeviceSetting = Settings.getValue(INPUT_DEVICE_SETTING); - var interfaceInputDevice = AudioDevice.getInputDevice(); - if (interfaceInputDevice != inputDeviceSetting) { - debug("Input Setting & Device mismatch! Input SETTING: " + inputDeviceSetting + "Input DEVICE IN USE: " + interfaceInputDevice); - switchAudioDevice("Use " + inputDeviceSetting + " for Input"); - } - - var outputDeviceSetting = Settings.getValue(OUTPUT_DEVICE_SETTING); - var interfaceOutputDevice = AudioDevice.getOutputDevice(); - if (interfaceOutputDevice != outputDeviceSetting) { - debug("Output Setting & Device mismatch! Output SETTING: " + outputDeviceSetting + "Output DEVICE IN USE: " + interfaceOutputDevice); - switchAudioDevice("Use " + outputDeviceSetting + " for Output"); - } -} - function removeAudioMenus() { Menu.removeSeparator("Audio", "Input Audio Device"); Menu.removeSeparator("Audio", "Output Audio Device"); @@ -124,67 +95,28 @@ function removeAudioMenus() { function onDevicechanged() { debug("System audio devices changed. Removing and replacing Audio Menus..."); setupAudioMenus(); - checkDeviceMismatch(); } function onMenuEvent(audioDeviceMenuString) { - if (!skipMenuEvents) { - switchAudioDevice(audioDeviceMenuString); + if (Menu.isOptionChecked(audioDeviceMenuString) && + (audioDeviceMenuString !== interfaceInputDevice && + audioDeviceMenuString !== interfaceOutputDevice)) { + AudioDevice.setDeviceFromMenu(audioDeviceMenuString) } } -function switchAudioDevice(audioDeviceMenuString) { - // if the device is not plugged in, short-circuit - if (!~audioDevicesList.indexOf(audioDeviceMenuString)) { - return; - } - - var selection = parseMenuItem(audioDeviceMenuString); - if (!selection) { - debug("Invalid Audio audioDeviceMenuString! Doesn't end with 'for Input' or 'for Output'"); - return; - } - - // menu events can be triggered asynchronously; skip them for 200ms to avoid recursion and false switches - skipMenuEvents = true; - Script.setTimeout(function() { skipMenuEvents = false; }, 200); - - var selectedDevice = selection.device; - if (selection.mode == INPUT) { - var currentInputDevice = AudioDevice.getInputDevice(); - if (selectedDevice != currentInputDevice) { - debug("Switching audio INPUT device from " + currentInputDevice + " to " + selectedDevice); - Menu.setIsOptionChecked("Use " + currentInputDevice + " for Input", false); - if (AudioDevice.setInputDevice(selectedDevice)) { - Settings.setValue(INPUT_DEVICE_SETTING, selectedDevice); - Menu.setIsOptionChecked(audioDeviceMenuString, true); - } else { - debug("Error setting audio input device!") - Menu.setIsOptionChecked(audioDeviceMenuString, false); - } +function onCurrentDeviceChanged() { + debug("System audio device switched. "); + interfaceInputDevice = "Use " + AudioDevice.getInputDevice() + " for Input"; + interfaceOutputDevice = "Use " + AudioDevice.getOutputDevice() + " for Output"; + for (var index = 0; index < audioDevicesList.length; index++) { + if (audioDevicesList[index] === interfaceInputDevice || + audioDevicesList[index] === interfaceOutputDevice) { + if (Menu.isOptionChecked(audioDevicesList[index]) === false) + Menu.setIsOptionChecked(audioDevicesList[index], true); } else { - debug("Selected input device is the same as the current input device!") - Settings.setValue(INPUT_DEVICE_SETTING, selectedDevice); - Menu.setIsOptionChecked(audioDeviceMenuString, true); - AudioDevice.setInputDevice(selectedDevice); // Still try to force-set the device (in case the user's trying to forcefully debug an issue) - } - } else if (selection.mode == OUTPUT) { - var currentOutputDevice = AudioDevice.getOutputDevice(); - if (selectedDevice != currentOutputDevice) { - debug("Switching audio OUTPUT device from " + currentOutputDevice + " to " + selectedDevice); - Menu.setIsOptionChecked("Use " + currentOutputDevice + " for Output", false); - if (AudioDevice.setOutputDevice(selectedDevice)) { - Settings.setValue(OUTPUT_DEVICE_SETTING, selectedDevice); - Menu.setIsOptionChecked(audioDeviceMenuString, true); - } else { - debug("Error setting audio output device!") - Menu.setIsOptionChecked(audioDeviceMenuString, false); - } - } else { - debug("Selected output device is the same as the current output device!") - Settings.setValue(OUTPUT_DEVICE_SETTING, selectedDevice); - Menu.setIsOptionChecked(audioDeviceMenuString, true); - AudioDevice.setOutputDevice(selectedDevice); // Still try to force-set the device (in case the user's trying to forcefully debug an issue) + if (Menu.isOptionChecked(audioDevicesList[index]) === true) + Menu.setIsOptionChecked(audioDevicesList[index], false); } } } @@ -192,12 +124,12 @@ function switchAudioDevice(audioDeviceMenuString) { function restoreAudio() { if (switchedAudioInputToHMD) { debug("Switching back from HMD preferred audio input to: " + previousSelectedInputAudioDevice); - switchAudioDevice("Use " + previousSelectedInputAudioDevice + " for Input"); + AudioDevice.setInputDeviceAsync(previousSelectedInputAudioDevice) switchedAudioInputToHMD = false; } if (switchedAudioOutputToHMD) { debug("Switching back from HMD preferred audio output to: " + previousSelectedOutputAudioDevice); - switchAudioDevice("Use " + previousSelectedOutputAudioDevice + " for Output"); + AudioDevice.setOutputDeviceAsync(previousSelectedOutputAudioDevice) switchedAudioOutputToHMD = false; } } @@ -224,7 +156,7 @@ function checkHMDAudio() { debug("previousSelectedInputAudioDevice: " + previousSelectedInputAudioDevice); if (hmdPreferredAudioInput != previousSelectedInputAudioDevice) { switchedAudioInputToHMD = true; - switchAudioDevice("Use " + hmdPreferredAudioInput + " for Input"); + AudioDevice.setInputDeviceAsync(hmdPreferredAudioInput) } } if (hmdPreferredAudioOutput !== "") { @@ -233,7 +165,7 @@ function checkHMDAudio() { debug("previousSelectedOutputAudioDevice: " + previousSelectedOutputAudioDevice); if (hmdPreferredAudioOutput != previousSelectedOutputAudioDevice) { switchedAudioOutputToHMD = true; - switchAudioDevice("Use " + hmdPreferredAudioOutput + " for Output"); + AudioDevice.setOutputDeviceAsync(hmdPreferredAudioOutput) } } } else { @@ -255,14 +187,15 @@ function checkHMDAudio() { Script.setTimeout(function () { debug("Connecting deviceChanged(), displayModeChanged(), and switchAudioDevice()..."); AudioDevice.deviceChanged.connect(onDevicechanged); + AudioDevice.currentInputDeviceChanged.connect(onCurrentDeviceChanged); + AudioDevice.currentOutputDeviceChanged.connect(onCurrentDeviceChanged); HMD.displayModeChanged.connect(checkHMDAudio); Menu.menuItemEvent.connect(onMenuEvent); debug("Setting up Audio I/O menu for the first time..."); setupAudioMenus(); - checkDeviceMismatch(); debug("Checking HMD audio status...") checkHMDAudio(); -}, 3000); +}, SELECT_AUDIO_SCRIPT_STARTUP_TIMEOUT); debug("Connecting scriptEnding()"); Script.scriptEnding.connect(function () { @@ -270,6 +203,8 @@ Script.scriptEnding.connect(function () { removeAudioMenus(); Menu.menuItemEvent.disconnect(onMenuEvent); HMD.displayModeChanged.disconnect(checkHMDAudio); + AudioDevice.currentInputDeviceChanged.disconnect(onCurrentDeviceChanged); + AudioDevice.currentOutputDeviceChanged.disconnect(onCurrentDeviceChanged); AudioDevice.deviceChanged.disconnect(onDevicechanged); });