mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 18:50:00 +02:00
expose Audio.devices.input/output
This commit is contained in:
parent
4a3f2e1d09
commit
954e4979f8
8 changed files with 322 additions and 79 deletions
|
@ -13,6 +13,7 @@
|
||||||
#define hifi_scripting_Audio_h
|
#define hifi_scripting_Audio_h
|
||||||
|
|
||||||
#include "AudioScriptingInterface.h"
|
#include "AudioScriptingInterface.h"
|
||||||
|
#include "AudioDevices.h"
|
||||||
|
|
||||||
namespace scripting {
|
namespace scripting {
|
||||||
|
|
||||||
|
@ -22,14 +23,21 @@ class Audio : public AudioScriptingInterface {
|
||||||
|
|
||||||
// TODO: Q_PROPERTY(bool mute)
|
// TODO: Q_PROPERTY(bool mute)
|
||||||
// TODO: Q_PROPERTY(bool noiseReduction)
|
// TODO: Q_PROPERTY(bool noiseReduction)
|
||||||
|
// TODO: Q_PROPERTY(bool reverb)
|
||||||
|
// TODO: Q_PROPERTY(float inputVolume)
|
||||||
// TODO: Q_PROPERTY(bool showMicLevel)
|
// TODO: Q_PROPERTY(bool showMicLevel)
|
||||||
// TODO: Q_PROPERTY(? devices)
|
// TODO: Q_PROPERTY(QString context)
|
||||||
|
Q_PROPERTY(AudioDevices* devices READ getDevices)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~Audio() {}
|
virtual ~Audio() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Audio() {}
|
Audio() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AudioDevices* getDevices() { return &_devices; }
|
||||||
|
AudioDevices _devices;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "AudioClient.h"
|
#include "AudioClient.h"
|
||||||
|
/*
|
||||||
#include "AudioDeviceScriptingInterface.h"
|
#include "AudioDeviceScriptingInterface.h"
|
||||||
#include "SettingsScriptingInterface.h"
|
#include "SettingsScriptingInterface.h"
|
||||||
|
|
||||||
|
@ -269,3 +270,4 @@ void AudioDeviceScriptingInterface::currentDeviceUpdate(const QString& name, QAu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#ifndef hifi_AudioDeviceScriptingInterface_h
|
#ifndef hifi_AudioDeviceScriptingInterface_h
|
||||||
#define hifi_AudioDeviceScriptingInterface_h
|
#define hifi_AudioDeviceScriptingInterface_h
|
||||||
|
|
||||||
|
/*
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
@ -103,5 +104,6 @@ private:
|
||||||
QString _currentInputDevice;
|
QString _currentInputDevice;
|
||||||
QString _currentOutputDevice;
|
QString _currentOutputDevice;
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
#endif // hifi_AudioDeviceScriptingInterface_h
|
#endif // hifi_AudioDeviceScriptingInterface_h
|
||||||
|
|
146
interface/src/scripting/AudioDevices.cpp
Normal file
146
interface/src/scripting/AudioDevices.cpp
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
//
|
||||||
|
// AudioDevices.cpp
|
||||||
|
// interface/src/scripting
|
||||||
|
//
|
||||||
|
// Created by Zach Pomerantz on 28/5/2017.
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AudioDevices.h"
|
||||||
|
#include "AudioClient.h"
|
||||||
|
|
||||||
|
using namespace scripting;
|
||||||
|
|
||||||
|
QHash<int, QByteArray> AudioDeviceList::_roles {
|
||||||
|
{ Qt::DisplayRole, "display" },
|
||||||
|
{ Qt::CheckStateRole, "selected" }
|
||||||
|
};
|
||||||
|
Qt::ItemFlags AudioDeviceList::_flags { Qt::ItemIsSelectable | Qt::ItemIsEnabled };
|
||||||
|
|
||||||
|
AudioDeviceList::AudioDeviceList(QAudio::Mode mode) : _mode(mode) {
|
||||||
|
}
|
||||||
|
|
||||||
|
int AudioDeviceList::rowCount(const QModelIndex& parent) const {
|
||||||
|
Q_UNUSED(parent);
|
||||||
|
return _devices.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant AudioDeviceList::data(const QModelIndex& index, int role) const {
|
||||||
|
if (!index.isValid() || index.row() >= _devices.size()) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
return _devices.at(index.row()).name;
|
||||||
|
} else if (role == Qt::CheckStateRole) {
|
||||||
|
return _devices.at(index.row()).selected;
|
||||||
|
} else {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> AudioDeviceList::roleNames() const {
|
||||||
|
return _roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags AudioDeviceList::flags(const QModelIndex& index) const {
|
||||||
|
return _flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioDeviceList::setData(const QModelIndex& index, const QVariant &value, int role) {
|
||||||
|
if (!index.isValid() || index.row() >= _devices.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
if (role == Qt::CheckStateRole) {
|
||||||
|
auto selected = value.toBool();
|
||||||
|
auto& device = _devices[index.row()];
|
||||||
|
|
||||||
|
// only allow switching to a new device, not deactivating an in-use device
|
||||||
|
if (selected
|
||||||
|
// skip if already selected
|
||||||
|
&& selected != device.selected) {
|
||||||
|
|
||||||
|
auto client = DependencyManager::get<AudioClient>();
|
||||||
|
bool success;
|
||||||
|
QMetaObject::invokeMethod(client.data(), "switchAudioDevice", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(bool, success),
|
||||||
|
Q_ARG(QAudio::Mode, _mode),
|
||||||
|
Q_ARG(const QAudioDeviceInfo&, device.info));
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
device.selected = true;
|
||||||
|
emit dataChanged(index, index, { Qt::CheckStateRole });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioDeviceList::setDevice(const QAudioDeviceInfo& device) {
|
||||||
|
_selectedDevice = device;
|
||||||
|
|
||||||
|
for (auto i = 0; i < _devices.size(); ++i) {
|
||||||
|
AudioDevice& device = _devices[i];
|
||||||
|
|
||||||
|
if (device.selected && device.info != _selectedDevice) {
|
||||||
|
device.selected = false;
|
||||||
|
auto index = createIndex(i , 0);
|
||||||
|
emit dataChanged(index, index, { Qt::CheckStateRole });
|
||||||
|
} else if (!device.selected && device.info == _selectedDevice) {
|
||||||
|
device.selected = true;
|
||||||
|
auto index = createIndex(i , 0);
|
||||||
|
emit dataChanged(index, index, { Qt::CheckStateRole });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioDeviceList::populate(const QList<QAudioDeviceInfo>& devices) {
|
||||||
|
beginResetModel();
|
||||||
|
|
||||||
|
_devices.clear();
|
||||||
|
foreach(const QAudioDeviceInfo& deviceInfo, devices) {
|
||||||
|
AudioDevice device;
|
||||||
|
device.info = deviceInfo;
|
||||||
|
device.name = device.info.deviceName();
|
||||||
|
device.selected = (device.info == _selectedDevice);
|
||||||
|
_devices.push_back(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioDevices::AudioDevices() {
|
||||||
|
auto client = DependencyManager::get<AudioClient>();
|
||||||
|
// connections are made after client is initialized, so we must also fetch the devices
|
||||||
|
|
||||||
|
connect(client.data(), &AudioClient::deviceChanged, this, &AudioDevices::onDeviceChanged, Qt::QueuedConnection);
|
||||||
|
_inputs.setDevice(client->getActiveAudioDevice(QAudio::AudioInput));
|
||||||
|
_outputs.setDevice(client->getActiveAudioDevice(QAudio::AudioOutput));
|
||||||
|
|
||||||
|
connect(client.data(), &AudioClient::devicesChanged, this, &AudioDevices::onDevicesChanged, Qt::QueuedConnection);
|
||||||
|
_inputs.populate(client->getAudioDevices(QAudio::AudioInput));
|
||||||
|
_outputs.populate(client->getAudioDevices(QAudio::AudioOutput));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioDevices::onDeviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& device) {
|
||||||
|
if (mode == QAudio::AudioInput) {
|
||||||
|
_inputs.setDevice(device);
|
||||||
|
} else { // if (mode == QAudio::AudioOutput)
|
||||||
|
_outputs.setDevice(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList<QAudioDeviceInfo>& devices) {
|
||||||
|
if (mode == QAudio::AudioInput) {
|
||||||
|
_inputs.populate(devices);
|
||||||
|
} else { // if (mode == QAudio::AudioOutput)
|
||||||
|
_outputs.populate(devices);
|
||||||
|
}
|
||||||
|
}
|
76
interface/src/scripting/AudioDevices.h
Normal file
76
interface/src/scripting/AudioDevices.h
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
//
|
||||||
|
// AudioDeviceScriptingInterface.h
|
||||||
|
// interface/src/scripting
|
||||||
|
//
|
||||||
|
// Created by Zach Pomerantz on 28/5/2017.
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_scripting_AudioDevices_h
|
||||||
|
#define hifi_scripting_AudioDevices_h
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QAudioDeviceInfo>
|
||||||
|
|
||||||
|
namespace scripting {
|
||||||
|
|
||||||
|
class AudioDevice {
|
||||||
|
public:
|
||||||
|
QAudioDeviceInfo info;
|
||||||
|
QString name;
|
||||||
|
bool selected { false };
|
||||||
|
};
|
||||||
|
|
||||||
|
class AudioDeviceList : public QAbstractListModel {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
AudioDeviceList(QAudio::Mode mode);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex& parent) const override;
|
||||||
|
QVariant data(const QModelIndex& index, int role) const override;
|
||||||
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||||
|
bool setData(const QModelIndex& index, const QVariant &value, int role) override;
|
||||||
|
|
||||||
|
void setDevice(const QAudioDeviceInfo& device);
|
||||||
|
void populate(const QList<QAudioDeviceInfo>& devices);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static QHash<int, QByteArray> _roles;
|
||||||
|
static Qt::ItemFlags _flags;
|
||||||
|
|
||||||
|
QAudio::Mode _mode;
|
||||||
|
QAudioDeviceInfo _selectedDevice;
|
||||||
|
QList<AudioDevice> _devices;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AudioDevices : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(AudioDeviceList* input READ getInputList)
|
||||||
|
Q_PROPERTY(AudioDeviceList* output READ getOutputList)
|
||||||
|
|
||||||
|
public:
|
||||||
|
AudioDevices();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onDeviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& device);
|
||||||
|
void onDevicesChanged(QAudio::Mode mode, const QList<QAudioDeviceInfo>& devices);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AudioDeviceList* getInputList() { return &_inputs; }
|
||||||
|
AudioDeviceList* getOutputList() { return &_outputs; }
|
||||||
|
|
||||||
|
AudioDeviceList _inputs { QAudio::AudioInput };
|
||||||
|
AudioDeviceList _outputs { QAudio::AudioOutput };
|
||||||
|
|
||||||
|
bool tester;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_scripting_AudioDevices_h
|
|
@ -76,6 +76,13 @@ using Mutex = std::mutex;
|
||||||
using Lock = std::unique_lock<Mutex>;
|
using Lock = std::unique_lock<Mutex>;
|
||||||
static Mutex _deviceMutex;
|
static Mutex _deviceMutex;
|
||||||
|
|
||||||
|
// thread-safe
|
||||||
|
QList<QAudioDeviceInfo> getAvailableDevices(QAudio::Mode mode) {
|
||||||
|
// NOTE: availableDevices() clobbers the Qt internal device list
|
||||||
|
Lock lock(_deviceMutex);
|
||||||
|
return QAudioDeviceInfo::availableDevices(mode);
|
||||||
|
}
|
||||||
|
|
||||||
class BackgroundThread : public QThread {
|
class BackgroundThread : public QThread {
|
||||||
public:
|
public:
|
||||||
BackgroundThread(AudioClient* client) : QThread((QObject*)client), _client(client) {}
|
BackgroundThread(AudioClient* client) : QThread((QObject*)client), _client(client) {}
|
||||||
|
@ -115,6 +122,45 @@ private:
|
||||||
std::condition_variable _joinCondition;
|
std::condition_variable _joinCondition;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// now called from a background thread, to keep blocking operations off the audio thread
|
||||||
|
void AudioClient::checkDevices() {
|
||||||
|
auto inputDevices = getAvailableDevices(QAudio::AudioInput);
|
||||||
|
auto outputDevices = getAvailableDevices(QAudio::AudioOutput);
|
||||||
|
|
||||||
|
Lock lock(_deviceMutex);
|
||||||
|
|
||||||
|
if (inputDevices != _inputDevices) {
|
||||||
|
_inputDevices.swap(inputDevices);
|
||||||
|
emit devicesChanged(QAudio::AudioInput, _inputDevices);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outputDevices != _outputDevices) {
|
||||||
|
_outputDevices.swap(outputDevices);
|
||||||
|
emit devicesChanged(QAudio::AudioOutput, _outputDevices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QAudioDeviceInfo AudioClient::getActiveAudioDevice(QAudio::Mode mode) const {
|
||||||
|
Lock lock(_deviceMutex);
|
||||||
|
|
||||||
|
if (mode == QAudio::AudioInput) {
|
||||||
|
return _inputDeviceInfo;
|
||||||
|
} else { // if (mode == QAudio::AudioOutput)
|
||||||
|
return _outputDeviceInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QAudioDeviceInfo> AudioClient::getAudioDevices(QAudio::Mode mode) const {
|
||||||
|
Lock lock(_deviceMutex);
|
||||||
|
|
||||||
|
if (mode == QAudio::AudioInput) {
|
||||||
|
return _inputDevices;
|
||||||
|
} else { // if (mode == QAudio::AudioOutput)
|
||||||
|
return _outputDevices;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// background thread buffering local injectors
|
// background thread buffering local injectors
|
||||||
class LocalInjectorsThread : public BackgroundThread {
|
class LocalInjectorsThread : public BackgroundThread {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -220,8 +266,9 @@ AudioClient::AudioClient() :
|
||||||
|
|
||||||
connect(&_receivedAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioClient::handleMismatchAudioFormat);
|
connect(&_receivedAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioClient::handleMismatchAudioFormat);
|
||||||
|
|
||||||
_inputDevices = getDeviceNames(QAudio::AudioInput);
|
// initialize wasapi; if getAvailableDevices is called from the CheckDevicesThread before this, it will crash
|
||||||
_outputDevices = getDeviceNames(QAudio::AudioOutput);
|
getAvailableDevices(QAudio::AudioInput);
|
||||||
|
getAvailableDevices(QAudio::AudioOutput);
|
||||||
|
|
||||||
// start a thread to detect any device changes
|
// start a thread to detect any device changes
|
||||||
_checkDevicesThread = new CheckDevicesThread(this);
|
_checkDevicesThread = new CheckDevicesThread(this);
|
||||||
|
@ -295,13 +342,6 @@ void AudioClient::audioMixerKilled() {
|
||||||
emit disconnected();
|
emit disconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
// thread-safe
|
|
||||||
QList<QAudioDeviceInfo> getAvailableDevices(QAudio::Mode mode) {
|
|
||||||
// NOTE: availableDevices() clobbers the Qt internal device list
|
|
||||||
Lock lock(_deviceMutex);
|
|
||||||
return QAudioDeviceInfo::availableDevices(mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) {
|
QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) {
|
||||||
QAudioDeviceInfo result;
|
QAudioDeviceInfo result;
|
||||||
foreach(QAudioDeviceInfo audioDevice, getAvailableDevices(mode)) {
|
foreach(QAudioDeviceInfo audioDevice, getAvailableDevices(mode)) {
|
||||||
|
@ -315,7 +355,7 @@ QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& de
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QString friendlyNameForAudioDevice(IMMDevice* pEndpoint) {
|
QString getWinDeviceName(IMMDevice* pEndpoint) {
|
||||||
QString deviceName;
|
QString deviceName;
|
||||||
IPropertyStore* pPropertyStore;
|
IPropertyStore* pPropertyStore;
|
||||||
pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore);
|
pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore);
|
||||||
|
@ -336,7 +376,7 @@ QString friendlyNameForAudioDevice(IMMDevice* pEndpoint) {
|
||||||
return deviceName;
|
return deviceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AudioClient::friendlyNameForAudioDevice(wchar_t* guid) {
|
QString AudioClient::getWinDeviceName(wchar_t* guid) {
|
||||||
QString deviceName;
|
QString deviceName;
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
CoInitialize(nullptr);
|
CoInitialize(nullptr);
|
||||||
|
@ -348,7 +388,7 @@ QString AudioClient::friendlyNameForAudioDevice(wchar_t* guid) {
|
||||||
printf("Audio Error: device not found\n");
|
printf("Audio Error: device not found\n");
|
||||||
deviceName = QString("NONE");
|
deviceName = QString("NONE");
|
||||||
} else {
|
} else {
|
||||||
deviceName = ::friendlyNameForAudioDevice(pEndpoint);
|
deviceName = ::getWinDeviceName(pEndpoint);
|
||||||
}
|
}
|
||||||
pMMDeviceEnumerator->Release();
|
pMMDeviceEnumerator->Release();
|
||||||
pMMDeviceEnumerator = nullptr;
|
pMMDeviceEnumerator = nullptr;
|
||||||
|
@ -431,7 +471,7 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
||||||
printf("Audio Error: device not found\n");
|
printf("Audio Error: device not found\n");
|
||||||
deviceName = QString("NONE");
|
deviceName = QString("NONE");
|
||||||
} else {
|
} else {
|
||||||
deviceName = friendlyNameForAudioDevice(pEndpoint);
|
deviceName = getWinDeviceName(pEndpoint);
|
||||||
}
|
}
|
||||||
pMMDeviceEnumerator->Release();
|
pMMDeviceEnumerator->Release();
|
||||||
pMMDeviceEnumerator = NULL;
|
pMMDeviceEnumerator = NULL;
|
||||||
|
@ -791,29 +831,12 @@ void AudioClient::selectAudioFormat(const QString& selectedCodecName) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AudioClient::switchAudioDevice(QAudio::Mode mode, const QAudioDeviceInfo& deviceInfo) {
|
||||||
QString AudioClient::getDefaultDeviceName(QAudio::Mode mode) {
|
if (mode == QAudio::AudioInput) {
|
||||||
QAudioDeviceInfo deviceInfo = defaultAudioDeviceForMode(mode);
|
return switchInputToAudioDevice(deviceInfo);
|
||||||
return deviceInfo.deviceName();
|
} else { // if (mode == QAudio::AudioOutput)
|
||||||
}
|
return switchOutputToAudioDevice(deviceInfo);
|
||||||
|
|
||||||
QVector<QString> AudioClient::getDeviceNames(QAudio::Mode mode) {
|
|
||||||
QVector<QString> deviceNames;
|
|
||||||
const QList<QAudioDeviceInfo> &availableDevice = getAvailableDevices(mode);
|
|
||||||
foreach(const QAudioDeviceInfo &audioDevice, availableDevice) {
|
|
||||||
deviceNames << audioDevice.deviceName().trimmed();
|
|
||||||
}
|
}
|
||||||
return deviceNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AudioClient::switchInputToAudioDevice(const QString& inputDeviceName) {
|
|
||||||
qCDebug(audioclient) << "[" << inputDeviceName << "] [" << getNamedAudioDeviceForMode(QAudio::AudioInput, inputDeviceName).deviceName() << "]";
|
|
||||||
return switchInputToAudioDevice(getNamedAudioDeviceForMode(QAudio::AudioInput, inputDeviceName));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AudioClient::switchOutputToAudioDevice(const QString& outputDeviceName) {
|
|
||||||
qCDebug(audioclient) << "[" << outputDeviceName << "] [" << getNamedAudioDeviceForMode(QAudio::AudioOutput, outputDeviceName).deviceName() << "]";
|
|
||||||
return switchOutputToAudioDevice(getNamedAudioDeviceForMode(QAudio::AudioOutput, outputDeviceName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::configureReverb() {
|
void AudioClient::configureReverb() {
|
||||||
|
@ -1357,7 +1380,7 @@ void AudioClient::setIsStereoInput(bool isStereoInput) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// change in channel count for desired input format, restart the input device
|
// change in channel count for desired input format, restart the input device
|
||||||
switchInputToAudioDevice(_inputAudioDeviceName);
|
switchInputToAudioDevice(_inputDeviceInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1397,6 +1420,9 @@ void AudioClient::outputFormatChanged() {
|
||||||
bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) {
|
bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) {
|
||||||
bool supportedFormat = false;
|
bool supportedFormat = false;
|
||||||
|
|
||||||
|
// NOTE: device start() uses the Qt internal device list
|
||||||
|
Lock lock(_deviceMutex);
|
||||||
|
|
||||||
// cleanup any previously initialized device
|
// cleanup any previously initialized device
|
||||||
if (_audioInput) {
|
if (_audioInput) {
|
||||||
// The call to stop() causes _inputDevice to be destructed.
|
// The call to stop() causes _inputDevice to be destructed.
|
||||||
|
@ -1409,7 +1435,7 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn
|
||||||
_audioInput = NULL;
|
_audioInput = NULL;
|
||||||
_numInputCallbackBytes = 0;
|
_numInputCallbackBytes = 0;
|
||||||
|
|
||||||
_inputAudioDeviceName = "";
|
_inputDeviceInfo = QAudioDeviceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_inputToNetworkResampler) {
|
if (_inputToNetworkResampler) {
|
||||||
|
@ -1424,8 +1450,8 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn
|
||||||
|
|
||||||
if (!inputDeviceInfo.isNull()) {
|
if (!inputDeviceInfo.isNull()) {
|
||||||
qCDebug(audioclient) << "The audio input device " << inputDeviceInfo.deviceName() << "is available.";
|
qCDebug(audioclient) << "The audio input device " << inputDeviceInfo.deviceName() << "is available.";
|
||||||
_inputAudioDeviceName = inputDeviceInfo.deviceName().trimmed();
|
_inputDeviceInfo = inputDeviceInfo;
|
||||||
emit currentInputDeviceChanged(_inputAudioDeviceName);
|
emit deviceChanged(QAudio::AudioInput, inputDeviceInfo);
|
||||||
|
|
||||||
if (adjustedFormatForAudioDevice(inputDeviceInfo, _desiredInputFormat, _inputFormat)) {
|
if (adjustedFormatForAudioDevice(inputDeviceInfo, _desiredInputFormat, _inputFormat)) {
|
||||||
qCDebug(audioclient) << "The format to be used for audio input is" << _inputFormat;
|
qCDebug(audioclient) << "The format to be used for audio input is" << _inputFormat;
|
||||||
|
@ -1460,10 +1486,7 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn
|
||||||
int numFrameSamples = calculateNumberOfFrameSamples(_numInputCallbackBytes);
|
int numFrameSamples = calculateNumberOfFrameSamples(_numInputCallbackBytes);
|
||||||
_inputRingBuffer.resizeForFrameSize(numFrameSamples);
|
_inputRingBuffer.resizeForFrameSize(numFrameSamples);
|
||||||
|
|
||||||
// NOTE: device start() uses the Qt internal device list
|
|
||||||
Lock lock(_deviceMutex);
|
|
||||||
_inputDevice = _audioInput->start();
|
_inputDevice = _audioInput->start();
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
if (_inputDevice) {
|
if (_inputDevice) {
|
||||||
connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleMicAudioInput()));
|
connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleMicAudioInput()));
|
||||||
|
@ -1511,6 +1534,9 @@ void AudioClient::outputNotify() {
|
||||||
bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) {
|
bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) {
|
||||||
bool supportedFormat = false;
|
bool supportedFormat = false;
|
||||||
|
|
||||||
|
// NOTE: device start() uses the Qt internal device list
|
||||||
|
Lock lock(_deviceMutex);
|
||||||
|
|
||||||
Lock localAudioLock(_localAudioMutex);
|
Lock localAudioLock(_localAudioMutex);
|
||||||
_localSamplesAvailable.exchange(0, std::memory_order_release);
|
_localSamplesAvailable.exchange(0, std::memory_order_release);
|
||||||
|
|
||||||
|
@ -1536,6 +1562,8 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice
|
||||||
|
|
||||||
delete[] _localOutputMixBuffer;
|
delete[] _localOutputMixBuffer;
|
||||||
_localOutputMixBuffer = NULL;
|
_localOutputMixBuffer = NULL;
|
||||||
|
|
||||||
|
_outputDeviceInfo = QAudioDeviceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_networkToOutputResampler) {
|
if (_networkToOutputResampler) {
|
||||||
|
@ -1549,8 +1577,8 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice
|
||||||
|
|
||||||
if (!outputDeviceInfo.isNull()) {
|
if (!outputDeviceInfo.isNull()) {
|
||||||
qCDebug(audioclient) << "The audio output device " << outputDeviceInfo.deviceName() << "is available.";
|
qCDebug(audioclient) << "The audio output device " << outputDeviceInfo.deviceName() << "is available.";
|
||||||
_outputAudioDeviceName = outputDeviceInfo.deviceName().trimmed();
|
_outputDeviceInfo = outputDeviceInfo;
|
||||||
emit currentOutputDeviceChanged(_outputAudioDeviceName);
|
emit deviceChanged(QAudio::AudioOutput, outputDeviceInfo);
|
||||||
|
|
||||||
if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) {
|
if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) {
|
||||||
qCDebug(audioclient) << "The format to be used for audio output is" << _outputFormat;
|
qCDebug(audioclient) << "The format to be used for audio output is" << _outputFormat;
|
||||||
|
@ -1625,10 +1653,7 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice
|
||||||
|
|
||||||
_audioOutputIODevice.start();
|
_audioOutputIODevice.start();
|
||||||
|
|
||||||
// NOTE: device start() uses the Qt internal device list
|
|
||||||
Lock lock(_deviceMutex);
|
|
||||||
_audioOutput->start(&_audioOutputIODevice);
|
_audioOutput->start(&_audioOutputIODevice);
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
// setup a loopback audio output device
|
// setup a loopback audio output device
|
||||||
_loopbackAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
_loopbackAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
||||||
|
@ -1821,19 +1846,6 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now called from a background thread, to keep blocking operations off the audio thread
|
|
||||||
void AudioClient::checkDevices() {
|
|
||||||
QVector<QString> inputDevices = getDeviceNames(QAudio::AudioInput);
|
|
||||||
QVector<QString> outputDevices = getDeviceNames(QAudio::AudioOutput);
|
|
||||||
|
|
||||||
if (inputDevices != _inputDevices || outputDevices != _outputDevices) {
|
|
||||||
_inputDevices = inputDevices;
|
|
||||||
_outputDevices = outputDevices;
|
|
||||||
|
|
||||||
emit deviceChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioClient::loadSettings() {
|
void AudioClient::loadSettings() {
|
||||||
_receivedAudioStream.setDynamicJitterBufferEnabled(dynamicJitterBufferEnabled.get());
|
_receivedAudioStream.setDynamicJitterBufferEnabled(dynamicJitterBufferEnabled.get());
|
||||||
_receivedAudioStream.setStaticJitterBufferFrames(staticJitterBufferFrames.get());
|
_receivedAudioStream.setStaticJitterBufferFrames(staticJitterBufferFrames.get());
|
||||||
|
|
|
@ -146,10 +146,13 @@ public:
|
||||||
|
|
||||||
bool outputLocalInjector(AudioInjector* injector) override;
|
bool outputLocalInjector(AudioInjector* injector) override;
|
||||||
|
|
||||||
|
QAudioDeviceInfo getActiveAudioDevice(QAudio::Mode mode) const;
|
||||||
|
QList<QAudioDeviceInfo> getAudioDevices(QAudio::Mode mode) const;
|
||||||
|
|
||||||
static const float CALLBACK_ACCELERATOR_RATIO;
|
static const float CALLBACK_ACCELERATOR_RATIO;
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
static QString friendlyNameForAudioDevice(wchar_t* guid);
|
static QString getWinDeviceName(wchar_t* guid);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -185,12 +188,7 @@ public slots:
|
||||||
|
|
||||||
bool shouldLoopbackInjectors() override { return _shouldEchoToServer; }
|
bool shouldLoopbackInjectors() override { return _shouldEchoToServer; }
|
||||||
|
|
||||||
bool switchInputToAudioDevice(const QString& inputDeviceName);
|
bool switchAudioDevice(QAudio::Mode mode, const QAudioDeviceInfo& deviceInfo);
|
||||||
bool switchOutputToAudioDevice(const QString& outputDeviceName);
|
|
||||||
QString getDeviceName(QAudio::Mode mode) const { return (mode == QAudio::AudioInput) ?
|
|
||||||
_inputAudioDeviceName : _outputAudioDeviceName; }
|
|
||||||
QString getDefaultDeviceName(QAudio::Mode mode);
|
|
||||||
QVector<QString> getDeviceNames(QAudio::Mode mode);
|
|
||||||
|
|
||||||
float getInputVolume() const { return (_audioInput) ? (float)_audioInput->volume() : 0.0f; }
|
float getInputVolume() const { return (_audioInput) ? (float)_audioInput->volume() : 0.0f; }
|
||||||
void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); }
|
void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); }
|
||||||
|
@ -212,7 +210,9 @@ signals:
|
||||||
void noiseGateClosed();
|
void noiseGateClosed();
|
||||||
|
|
||||||
void changeDevice(const QAudioDeviceInfo& outputDeviceInfo);
|
void changeDevice(const QAudioDeviceInfo& outputDeviceInfo);
|
||||||
void deviceChanged();
|
|
||||||
|
void deviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& device);
|
||||||
|
void devicesChanged(QAudio::Mode mode, const QList<QAudioDeviceInfo>& devices);
|
||||||
|
|
||||||
void receivedFirstPacket();
|
void receivedFirstPacket();
|
||||||
void disconnected();
|
void disconnected();
|
||||||
|
@ -221,9 +221,6 @@ signals:
|
||||||
|
|
||||||
void muteEnvironmentRequested(glm::vec3 position, float radius);
|
void muteEnvironmentRequested(glm::vec3 position, float radius);
|
||||||
|
|
||||||
void currentOutputDeviceChanged(const QString& name);
|
|
||||||
void currentInputDeviceChanged(const QString& name);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AudioClient();
|
AudioClient();
|
||||||
~AudioClient();
|
~AudioClient();
|
||||||
|
@ -290,9 +287,6 @@ private:
|
||||||
MixedProcessedAudioStream _receivedAudioStream;
|
MixedProcessedAudioStream _receivedAudioStream;
|
||||||
bool _isStereoInput;
|
bool _isStereoInput;
|
||||||
|
|
||||||
QString _inputAudioDeviceName;
|
|
||||||
QString _outputAudioDeviceName;
|
|
||||||
|
|
||||||
quint64 _outputStarveDetectionStartTimeMsec;
|
quint64 _outputStarveDetectionStartTimeMsec;
|
||||||
int _outputStarveDetectionCount;
|
int _outputStarveDetectionCount;
|
||||||
|
|
||||||
|
@ -368,8 +362,11 @@ private:
|
||||||
glm::vec3 avatarBoundingBoxCorner;
|
glm::vec3 avatarBoundingBoxCorner;
|
||||||
glm::vec3 avatarBoundingBoxScale;
|
glm::vec3 avatarBoundingBoxScale;
|
||||||
|
|
||||||
QVector<QString> _inputDevices;
|
QAudioDeviceInfo _inputDeviceInfo;
|
||||||
QVector<QString> _outputDevices;
|
QAudioDeviceInfo _outputDeviceInfo;
|
||||||
|
|
||||||
|
QList<QAudioDeviceInfo> _inputDevices;
|
||||||
|
QList<QAudioDeviceInfo> _outputDevices;
|
||||||
|
|
||||||
bool _hasReceivedFirstPacket { false };
|
bool _hasReceivedFirstPacket { false };
|
||||||
|
|
||||||
|
|
|
@ -244,7 +244,7 @@ QString OculusDisplayPlugin::getPreferredAudioInDevice() const {
|
||||||
if (!OVR_SUCCESS(ovr_GetAudioDeviceInGuidStr(buffer))) {
|
if (!OVR_SUCCESS(ovr_GetAudioDeviceInGuidStr(buffer))) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
return AudioClient::friendlyNameForAudioDevice(buffer);
|
return AudioClient::getWinDeviceName(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString OculusDisplayPlugin::getPreferredAudioOutDevice() const {
|
QString OculusDisplayPlugin::getPreferredAudioOutDevice() const {
|
||||||
|
@ -252,7 +252,7 @@ QString OculusDisplayPlugin::getPreferredAudioOutDevice() const {
|
||||||
if (!OVR_SUCCESS(ovr_GetAudioDeviceOutGuidStr(buffer))) {
|
if (!OVR_SUCCESS(ovr_GetAudioDeviceOutGuidStr(buffer))) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
return AudioClient::friendlyNameForAudioDevice(buffer);
|
return AudioClient::getWinDeviceName(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
OculusDisplayPlugin::~OculusDisplayPlugin() {
|
OculusDisplayPlugin::~OculusDisplayPlugin() {
|
||||||
|
|
Loading…
Reference in a new issue