mirror of
https://github.com/JulianGro/overte.git
synced 2025-08-13 18:55:46 +02:00
Merge pull request #12704 from ElderOrb/FB13057
Improve audio devices selection logic
This commit is contained in:
commit
ff6c9f3127
2 changed files with 140 additions and 26 deletions
|
@ -10,6 +10,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <shared/QtHelpers.h>
|
#include <shared/QtHelpers.h>
|
||||||
#include <plugins/DisplayPlugin.h>
|
#include <plugins/DisplayPlugin.h>
|
||||||
|
@ -182,7 +183,6 @@ void AudioDeviceList::resetDevice(bool contextIsHMD) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD) {
|
void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD) {
|
||||||
auto oldDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice;
|
|
||||||
QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice;
|
QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice;
|
||||||
selectedDevice = device;
|
selectedDevice = device;
|
||||||
|
|
||||||
|
@ -200,32 +200,137 @@ void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD
|
||||||
emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0));
|
emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDeviceList::onDevicesChanged(const QList<QAudioDeviceInfo>& devices, bool isHMD) {
|
// Function returns 'strings similarity' as a number. The lesser number - the more similar strings are. Absolutely equal strings should return 0.
|
||||||
QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice;
|
// Optimized version kindly provided by Ken
|
||||||
|
int levenshteinDistance(const QString& s1, const QString& s2) {
|
||||||
|
const int m = s1.size();
|
||||||
|
const int n = s2.size();
|
||||||
|
|
||||||
const QString& savedDeviceName = isHMD ? _hmdSavedDeviceName : _desktopSavedDeviceName;
|
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<scripting::AudioDevice> getSimilarDevice(const QString& deviceName, const QList<std::shared_ptr<scripting::AudioDevice>>& 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<QAudioDeviceInfo>& devices) {
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|
||||||
_devices.clear();
|
QList<std::shared_ptr<AudioDevice>> 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) {
|
foreach(const QAudioDeviceInfo& deviceInfo, devices) {
|
||||||
AudioDevice device;
|
AudioDevice device;
|
||||||
bool &isSelected = isHMD ? device.selectedHMD : device.selectedDesktop;
|
|
||||||
device.info = deviceInfo;
|
device.info = deviceInfo;
|
||||||
device.display = device.info.deviceName()
|
device.display = device.info.deviceName()
|
||||||
.replace("High Definition", "HD")
|
.replace("High Definition", "HD")
|
||||||
.remove("Device")
|
.remove("Device")
|
||||||
.replace(" )", ")");
|
.replace(" )", ")");
|
||||||
if (!selectedDevice.isNull()) {
|
|
||||||
isSelected = (device.info == selectedDevice);
|
for (bool isHMD : {false, true}) {
|
||||||
} else {
|
QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice;
|
||||||
//no selected device for context. fallback to saved
|
bool &isSelected = isHMD ? device.selectedHMD : device.selectedDesktop;
|
||||||
isSelected = (device.info.deviceName() == savedDeviceName);
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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;
|
qDebug() << "adding audio device:" << device.display << device.selectedDesktop << device.selectedHMD << _mode;
|
||||||
_devices.push_back(newDevice(device));
|
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();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,12 +376,10 @@ AudioDevices::AudioDevices(bool& contextIsHMD) : _contextIsHMD(contextIsHMD) {
|
||||||
// connections are made after client is initialized, so we must also fetch the devices
|
// connections are made after client is initialized, so we must also fetch the devices
|
||||||
const QList<QAudioDeviceInfo>& devicesInput = client->getAudioDevices(QAudio::AudioInput);
|
const QList<QAudioDeviceInfo>& devicesInput = client->getAudioDevices(QAudio::AudioInput);
|
||||||
const QList<QAudioDeviceInfo>& devicesOutput = client->getAudioDevices(QAudio::AudioOutput);
|
const QList<QAudioDeviceInfo>& devicesOutput = client->getAudioDevices(QAudio::AudioOutput);
|
||||||
//setup HMD devices
|
|
||||||
_inputs.onDevicesChanged(devicesInput, true);
|
//setup devices
|
||||||
_outputs.onDevicesChanged(devicesOutput, true);
|
_inputs.onDevicesChanged(devicesInput);
|
||||||
//setup Desktop devices
|
_outputs.onDevicesChanged(devicesOutput);
|
||||||
_inputs.onDevicesChanged(devicesInput, false);
|
|
||||||
_outputs.onDevicesChanged(devicesOutput, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDevices::~AudioDevices() {}
|
AudioDevices::~AudioDevices() {}
|
||||||
|
@ -375,11 +478,19 @@ void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList<QAudioDeviceI
|
||||||
|
|
||||||
//set devices for both contexts
|
//set devices for both contexts
|
||||||
if (mode == QAudio::AudioInput) {
|
if (mode == QAudio::AudioInput) {
|
||||||
_inputs.onDevicesChanged(devices, _contextIsHMD);
|
_inputs.onDevicesChanged(devices);
|
||||||
_inputs.onDevicesChanged(devices, !_contextIsHMD);
|
|
||||||
|
static std::once_flag onceAfterInputDevicesChanged;
|
||||||
|
std::call_once(onceAfterInputDevicesChanged, [&] { // we only want 'selectedDevicePlugged' signal to be handled after initial list of input devices was populated
|
||||||
|
connect(&_inputs, &AudioDeviceList::selectedDevicePlugged, this, &AudioDevices::chooseInputDevice);
|
||||||
|
});
|
||||||
} else { // if (mode == QAudio::AudioOutput)
|
} else { // if (mode == QAudio::AudioOutput)
|
||||||
_outputs.onDevicesChanged(devices, _contextIsHMD);
|
_outputs.onDevicesChanged(devices);
|
||||||
_outputs.onDevicesChanged(devices, !_contextIsHMD);
|
|
||||||
|
static std::once_flag onceAfterOutputDevicesChanged;
|
||||||
|
std::call_once(onceAfterOutputDevicesChanged, [&] { // we only want 'selectedDevicePlugged' signal to be handled after initial list of output devices was populated
|
||||||
|
connect(&_outputs, &AudioDeviceList::selectedDevicePlugged, this, &AudioDevices::chooseOutputDevice);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,10 +51,11 @@ public:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void deviceChanged(const QAudioDeviceInfo& device);
|
void deviceChanged(const QAudioDeviceInfo& device);
|
||||||
|
void selectedDevicePlugged(const QAudioDeviceInfo& device, bool isHMD);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD);
|
void onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD);
|
||||||
void onDevicesChanged(const QList<QAudioDeviceInfo>& devices, bool isHMD);
|
void onDevicesChanged(const QList<QAudioDeviceInfo>& devices);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class AudioDevices;
|
friend class AudioDevices;
|
||||||
|
@ -64,6 +65,8 @@ protected:
|
||||||
const QAudio::Mode _mode;
|
const QAudio::Mode _mode;
|
||||||
QAudioDeviceInfo _selectedDesktopDevice;
|
QAudioDeviceInfo _selectedDesktopDevice;
|
||||||
QAudioDeviceInfo _selectedHMDDevice;
|
QAudioDeviceInfo _selectedHMDDevice;
|
||||||
|
QString _backupSelectedDesktopDeviceName;
|
||||||
|
QString _backupSelectedHMDDeviceName;
|
||||||
QList<std::shared_ptr<AudioDevice>> _devices;
|
QList<std::shared_ptr<AudioDevice>> _devices;
|
||||||
QString _hmdSavedDeviceName;
|
QString _hmdSavedDeviceName;
|
||||||
QString _desktopSavedDeviceName;
|
QString _desktopSavedDeviceName;
|
||||||
|
@ -117,13 +120,13 @@ public:
|
||||||
AudioDevices(bool& contextIsHMD);
|
AudioDevices(bool& contextIsHMD);
|
||||||
virtual ~AudioDevices();
|
virtual ~AudioDevices();
|
||||||
|
|
||||||
void chooseInputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
|
||||||
void chooseOutputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void nop();
|
void nop();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void chooseInputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
||||||
|
void chooseOutputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
||||||
|
|
||||||
void onContextChanged(const QString& context);
|
void onContextChanged(const QString& context);
|
||||||
void onDeviceSelected(QAudio::Mode mode, const QAudioDeviceInfo& device,
|
void onDeviceSelected(QAudio::Mode mode, const QAudioDeviceInfo& device,
|
||||||
const QAudioDeviceInfo& previousDevice, bool isHMD);
|
const QAudioDeviceInfo& previousDevice, bool isHMD);
|
||||||
|
|
Loading…
Reference in a new issue