From f6bbdec90277bb06c0b48182d4b1d51b60810fb7 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Fri, 23 Mar 2018 20:20:40 +0300 Subject: [PATCH 1/4] remove 'isHMD' from input parameters of AudioDeviceList::onDevicesChanged note: having 'isHMD' as a parameter doesn't make sense because function rebuilds model which is used by both HMD and Desktop --- interface/src/scripting/AudioDevices.cpp | 42 +++++++++++++----------- interface/src/scripting/AudioDevices.h | 2 +- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index a130b46877..1b6b71a947 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -200,28 +200,34 @@ void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0)); } -void AudioDeviceList::onDevicesChanged(const QList& devices, bool isHMD) { - QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; - - const QString& savedDeviceName = isHMD ? _hmdSavedDeviceName : _desktopSavedDeviceName; +void AudioDeviceList::onDevicesChanged(const QList& devices) { beginResetModel(); _devices.clear(); foreach(const QAudioDeviceInfo& deviceInfo, devices) { AudioDevice device; - bool &isSelected = isHMD ? device.selectedHMD : device.selectedDesktop; device.info = deviceInfo; device.display = device.info.deviceName() .replace("High Definition", "HD") .remove("Device") .replace(" )", ")"); - if (!selectedDevice.isNull()) { - isSelected = (device.info == selectedDevice); - } else { - //no selected device for context. fallback to saved - isSelected = (device.info.deviceName() == savedDeviceName); + + for (bool isHMD : {false, true}) + { + QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; + bool &isSelected = isHMD ? device.selectedHMD : device.selectedDesktop; + + if (!selectedDevice.isNull()) { + isSelected = (device.info == selectedDevice); + } + else { + //no selected device for context. fallback to saved + const QString& savedDeviceName = isHMD ? _hmdSavedDeviceName : _desktopSavedDeviceName; + isSelected = (device.info.deviceName() == savedDeviceName); + } } + qDebug() << "adding audio device:" << device.display << device.selectedDesktop << device.selectedHMD << _mode; _devices.push_back(newDevice(device)); } @@ -271,12 +277,10 @@ AudioDevices::AudioDevices(bool& contextIsHMD) : _contextIsHMD(contextIsHMD) { // connections are made after client is initialized, so we must also fetch the devices const QList& devicesInput = client->getAudioDevices(QAudio::AudioInput); const QList& devicesOutput = client->getAudioDevices(QAudio::AudioOutput); - //setup HMD devices - _inputs.onDevicesChanged(devicesInput, true); - _outputs.onDevicesChanged(devicesOutput, true); - //setup Desktop devices - _inputs.onDevicesChanged(devicesInput, false); - _outputs.onDevicesChanged(devicesOutput, false); + + //setup devices + _inputs.onDevicesChanged(devicesInput); + _outputs.onDevicesChanged(devicesOutput); } AudioDevices::~AudioDevices() {} @@ -375,11 +379,9 @@ void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList& devices, bool isHMD); + void onDevicesChanged(const QList& devices); protected: friend class AudioDevices; From 3c45f17d709a1ffd04a958e2d55992cb1cb84645 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Sun, 25 Mar 2018 12:52:55 +0300 Subject: [PATCH 2/4] remove unused code --- interface/src/scripting/AudioDevices.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index 1b6b71a947..dbdbe778b2 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -182,7 +182,6 @@ void AudioDeviceList::resetDevice(bool contextIsHMD) { } void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD) { - auto oldDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; selectedDevice = device; From 8e551f4dc0fd9d93765fe54742273cce973b55f6 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Sun, 25 Mar 2018 13:49:59 +0300 Subject: [PATCH 3/4] re-select re-plugged device --- interface/src/scripting/AudioDevices.cpp | 31 +++++++++++++++++++++--- interface/src/scripting/AudioDevices.h | 7 +++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index dbdbe778b2..327f9dab9f 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -202,8 +202,7 @@ void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD void AudioDeviceList::onDevicesChanged(const QList& devices) { beginResetModel(); - _devices.clear(); - + QList> newDevices; foreach(const QAudioDeviceInfo& deviceInfo, devices) { AudioDevice device; device.info = deviceInfo; @@ -225,12 +224,28 @@ void AudioDeviceList::onDevicesChanged(const QList& devices) { const QString& savedDeviceName = isHMD ? _hmdSavedDeviceName : _desktopSavedDeviceName; isSelected = (device.info.deviceName() == savedDeviceName); } + + if (isSelected) { + // check if this device *is not* in old devices list - it means it was just re-plugged so needs to be selected explicitly + bool isNewDevice = true; + for (auto& oldDevice : _devices) { + if (oldDevice->info.deviceName() == device.info.deviceName()) { + isNewDevice = false; + break; + } + } + + if (isNewDevice) { + emit selectedDevicePlugged(device.info, isHMD); + } + } } qDebug() << "adding audio device:" << device.display << device.selectedDesktop << device.selectedHMD << _mode; - _devices.push_back(newDevice(device)); + newDevices.push_back(newDevice(device)); } + _devices.swap(newDevices); endResetModel(); } @@ -379,8 +394,18 @@ void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList Date: Mon, 26 Mar 2018 01:05:05 +0300 Subject: [PATCH 4/4] temporarily select 'similar-by-title' device if previously selected one was unlplugged; re-select originally selected device if it was re-plugged --- interface/src/scripting/AudioDevices.cpp | 89 +++++++++++++++++++++++- interface/src/scripting/AudioDevices.h | 2 + 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index 327f9dab9f..34a3630b78 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include @@ -199,10 +200,74 @@ void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0)); } +// Function returns 'strings similarity' as a number. The lesser number - the more similar strings are. Absolutely equal strings should return 0. +// Optimized version kindly provided by Ken +int levenshteinDistance(const QString& s1, const QString& s2) { + const int m = s1.size(); + const int n = s2.size(); + + if (m == 0) { + return n; + } + if (n == 0) { + return m; + } + + auto cost = (int*)alloca((n + 1) * sizeof(int)); + + for (int j = 0; j <= n; j++) { + cost[j] = j; + } + + for (int i = 0; i < m; i++) { + + int prev = i; + cost[0] = i + 1; + + for (int j = 0; j < n; j++) { + + int temp = cost[j + 1]; + cost[j + 1] = (s1[i] == s2[j]) ? prev : std::min(cost[j], std::min(temp, prev)) + 1; + prev = temp; + } + } + return cost[n]; +} + +std::shared_ptr getSimilarDevice(const QString& deviceName, const QList>& devices) { + + int minDistance = INT_MAX; + int minDistanceIndex = 0; + + for (auto i = 0; i < devices.length(); ++i) { + auto distance = levenshteinDistance(deviceName, devices[i]->info.deviceName()); + if (distance < minDistance) { + minDistance = distance; + minDistanceIndex = i; + } + } + + return devices[minDistanceIndex]; +} + void AudioDeviceList::onDevicesChanged(const QList& devices) { beginResetModel(); QList> newDevices; + bool hmdIsSelected = false; + bool desktopIsSelected = false; + + foreach(const QAudioDeviceInfo& deviceInfo, devices) { + for (bool isHMD : {false, true}) { + auto &backupSelectedDeviceName = isHMD ? _backupSelectedHMDDeviceName : _backupSelectedDesktopDeviceName; + if (deviceInfo.deviceName() == backupSelectedDeviceName) { + QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; + selectedDevice = deviceInfo; + backupSelectedDeviceName.clear(); + } + } + } + foreach(const QAudioDeviceInfo& deviceInfo, devices) { AudioDevice device; device.info = deviceInfo; @@ -211,8 +276,7 @@ void AudioDeviceList::onDevicesChanged(const QList& devices) { .remove("Device") .replace(" )", ")"); - for (bool isHMD : {false, true}) - { + for (bool isHMD : {false, true}) { QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; bool &isSelected = isHMD ? device.selectedHMD : device.selectedDesktop; @@ -226,6 +290,12 @@ void AudioDeviceList::onDevicesChanged(const QList& devices) { } if (isSelected) { + if (isHMD) { + hmdIsSelected = isSelected; + } else { + desktopIsSelected = isSelected; + } + // check if this device *is not* in old devices list - it means it was just re-plugged so needs to be selected explicitly bool isNewDevice = true; for (auto& oldDevice : _devices) { @@ -245,6 +315,21 @@ void AudioDeviceList::onDevicesChanged(const QList& devices) { newDevices.push_back(newDevice(device)); } + if (!newDevices.isEmpty()) { + if (!hmdIsSelected) { + _backupSelectedHMDDeviceName = !_selectedHMDDevice.isNull() ? _selectedHMDDevice.deviceName() : _hmdSavedDeviceName; + auto device = getSimilarDevice(_backupSelectedHMDDeviceName, newDevices); + device->selectedHMD = true; + emit selectedDevicePlugged(device->info, true); + } + if (!desktopIsSelected) { + _backupSelectedDesktopDeviceName = !_selectedDesktopDevice.isNull() ? _selectedDesktopDevice.deviceName() : _desktopSavedDeviceName; + auto device = getSimilarDevice(_backupSelectedDesktopDeviceName, newDevices); + device->selectedDesktop = true; + emit selectedDevicePlugged(device->info, false); + } + } + _devices.swap(newDevices); endResetModel(); } diff --git a/interface/src/scripting/AudioDevices.h b/interface/src/scripting/AudioDevices.h index 72d5fccedb..3d12f93113 100644 --- a/interface/src/scripting/AudioDevices.h +++ b/interface/src/scripting/AudioDevices.h @@ -65,6 +65,8 @@ protected: const QAudio::Mode _mode; QAudioDeviceInfo _selectedDesktopDevice; QAudioDeviceInfo _selectedHMDDevice; + QString _backupSelectedDesktopDeviceName; + QString _backupSelectedHMDDeviceName; QList> _devices; QString _hmdSavedDeviceName; QString _desktopSavedDeviceName;