mirror of
https://github.com/overte-org/overte.git
synced 2025-07-16 08:36:41 +02:00
created new AudioWrapper
This commit is contained in:
parent
a3fa82d72e
commit
cc11bd9552
7 changed files with 324 additions and 358 deletions
|
@ -440,13 +440,13 @@ void Audio::handlePushedToTalk(bool enabled) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::setInputDevice(const QAudioDeviceInfo& device, bool isHMD) {
|
void Audio::setInputDevice(const HifiAudioDeviceInfo& device, bool isHMD) {
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
_devices.chooseInputDevice(device, isHMD);
|
_devices.chooseInputDevice(device, isHMD);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::setOutputDevice(const QAudioDeviceInfo& device, bool isHMD) {
|
void Audio::setOutputDevice(const HifiAudioDeviceInfo& device, bool isHMD) {
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
_devices.chooseOutputDevice(device, isHMD);
|
_devices.chooseOutputDevice(device, isHMD);
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "SettingHandle.h"
|
#include "SettingHandle.h"
|
||||||
#include "AudioFileWav.h"
|
#include "AudioFileWav.h"
|
||||||
#include <shared/ReadWriteLockable.h>
|
#include <shared/ReadWriteLockable.h>
|
||||||
|
#include "HifiAudioDeviceInfo.h"
|
||||||
|
|
||||||
using MutedGetter = std::function<bool()>;
|
using MutedGetter = std::function<bool()>;
|
||||||
using MutedSetter = std::function<void(bool)>;
|
using MutedSetter = std::function<void(bool)>;
|
||||||
|
@ -158,7 +159,7 @@ public:
|
||||||
* @param {boolean} isHMD - Is HMD.
|
* @param {boolean} isHMD - Is HMD.
|
||||||
* @deprecated This function is deprecated and will be removed.
|
* @deprecated This function is deprecated and will be removed.
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE void setInputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
Q_INVOKABLE void setInputDevice(const HifiAudioDeviceInfo& device, bool isHMD);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function Audio.setOutputDevice
|
* @function Audio.setOutputDevice
|
||||||
|
@ -166,7 +167,7 @@ public:
|
||||||
* @param {boolean} isHMD - Is HMD.
|
* @param {boolean} isHMD - Is HMD.
|
||||||
* @deprecated This function is deprecated and will be removed.
|
* @deprecated This function is deprecated and will be removed.
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE void setOutputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
Q_INVOKABLE void setOutputDevice(const HifiAudioDeviceInfo& device, bool isHMD);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Enables or disables reverberation. Reverberation is done by the client on the post-mix audio. The reverberation options
|
* Enables or disables reverberation. Reverberation is done by the client on the post-mix audio. The reverberation options
|
||||||
|
|
|
@ -29,6 +29,8 @@ static Setting::Handle<QString> desktopOutputDeviceSetting { QStringList { Audio
|
||||||
static Setting::Handle<QString> hmdInputDeviceSetting { QStringList { Audio::AUDIO, Audio::HMD, "INPUT" }};
|
static Setting::Handle<QString> hmdInputDeviceSetting { QStringList { Audio::AUDIO, Audio::HMD, "INPUT" }};
|
||||||
static Setting::Handle<QString> hmdOutputDeviceSetting { QStringList { Audio::AUDIO, Audio::HMD, "OUTPUT" }};
|
static Setting::Handle<QString> hmdOutputDeviceSetting { QStringList { Audio::AUDIO, Audio::HMD, "OUTPUT" }};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(HifiAudioDeviceInfo);
|
||||||
|
|
||||||
Setting::Handle<QString>& getSetting(bool contextIsHMD, QAudio::Mode mode) {
|
Setting::Handle<QString>& getSetting(bool contextIsHMD, QAudio::Mode mode) {
|
||||||
if (mode == QAudio::AudioInput) {
|
if (mode == QAudio::AudioInput) {
|
||||||
return contextIsHMD ? hmdInputDeviceSetting : desktopInputDeviceSetting;
|
return contextIsHMD ? hmdInputDeviceSetting : desktopInputDeviceSetting;
|
||||||
|
@ -139,7 +141,7 @@ QVariant AudioDeviceList::data(const QModelIndex& index, int role) const {
|
||||||
} else if (role == SelectedHMDRole) {
|
} else if (role == SelectedHMDRole) {
|
||||||
return _devices.at(index.row())->selectedHMD;
|
return _devices.at(index.row())->selectedHMD;
|
||||||
} else if (role == InfoRole) {
|
} else if (role == InfoRole) {
|
||||||
return QVariant::fromValue<QAudioDeviceInfo>(_devices.at(index.row())->info);
|
return QVariant::fromValue<HifiAudioDeviceInfo>(_devices.at(index.row())->info);
|
||||||
} else {
|
} else {
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
@ -191,8 +193,8 @@ void AudioDeviceList::resetDevice(bool contextIsHMD) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD) {
|
void AudioDeviceList::onDeviceChanged(const HifiAudioDeviceInfo& device, bool isHMD) {
|
||||||
QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice;
|
HifiAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice;
|
||||||
selectedDevice = device;
|
selectedDevice = device;
|
||||||
|
|
||||||
for (auto i = 0; i < _devices.size(); ++i) {
|
for (auto i = 0; i < _devices.size(); ++i) {
|
||||||
|
@ -259,25 +261,25 @@ std::shared_ptr<scripting::AudioDevice> getSimilarDevice(const QString& deviceNa
|
||||||
return devices[minDistanceIndex];
|
return devices[minDistanceIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDeviceList::onDevicesChanged(const QList<QAudioDeviceInfo>& devices) {
|
void AudioDeviceList::onDevicesChanged(const QList<HifiAudioDeviceInfo>& devices) {
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|
||||||
QList<std::shared_ptr<AudioDevice>> newDevices;
|
QList<std::shared_ptr<AudioDevice>> newDevices;
|
||||||
bool hmdIsSelected = false;
|
bool hmdIsSelected = false;
|
||||||
bool desktopIsSelected = false;
|
bool desktopIsSelected = false;
|
||||||
|
|
||||||
foreach(const QAudioDeviceInfo& deviceInfo, devices) {
|
foreach(const HifiAudioDeviceInfo& deviceInfo, devices) {
|
||||||
for (bool isHMD : {false, true}) {
|
for (bool isHMD : {false, true}) {
|
||||||
auto& backupSelectedDeviceName = isHMD ? _backupSelectedHMDDeviceName : _backupSelectedDesktopDeviceName;
|
auto& backupSelectedDeviceName = isHMD ? _backupSelectedHMDDeviceName : _backupSelectedDesktopDeviceName;
|
||||||
if (deviceInfo.deviceName() == backupSelectedDeviceName) {
|
if (deviceInfo.deviceName() == backupSelectedDeviceName) {
|
||||||
QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice;
|
HifiAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice;
|
||||||
selectedDevice = deviceInfo;
|
selectedDevice = deviceInfo;
|
||||||
backupSelectedDeviceName.clear();
|
backupSelectedDeviceName.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(const QAudioDeviceInfo& deviceInfo, devices) {
|
foreach(const HifiAudioDeviceInfo& deviceInfo, devices) {
|
||||||
AudioDevice device;
|
AudioDevice device;
|
||||||
device.info = deviceInfo;
|
device.info = deviceInfo;
|
||||||
device.display = device.info.deviceName()
|
device.display = device.info.deviceName()
|
||||||
|
@ -286,10 +288,10 @@ void AudioDeviceList::onDevicesChanged(const QList<QAudioDeviceInfo>& devices) {
|
||||||
.replace(" )", ")");
|
.replace(" )", ")");
|
||||||
|
|
||||||
for (bool isHMD : {false, true}) {
|
for (bool isHMD : {false, true}) {
|
||||||
QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice;
|
HifiAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice;
|
||||||
bool& isSelected = isHMD ? device.selectedHMD : device.selectedDesktop;
|
bool& isSelected = isHMD ? device.selectedHMD : device.selectedDesktop;
|
||||||
|
|
||||||
if (!selectedDevice.isNull()) {
|
if (!selectedDevice.getDevice().isNull()) {
|
||||||
isSelected = (device.info == selectedDevice);
|
isSelected = (device.info == selectedDevice);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -325,13 +327,13 @@ void AudioDeviceList::onDevicesChanged(const QList<QAudioDeviceInfo>& devices) {
|
||||||
|
|
||||||
if (!newDevices.isEmpty()) {
|
if (!newDevices.isEmpty()) {
|
||||||
if (!hmdIsSelected) {
|
if (!hmdIsSelected) {
|
||||||
_backupSelectedHMDDeviceName = !_selectedHMDDevice.isNull() ? _selectedHMDDevice.deviceName() : _hmdSavedDeviceName;
|
_backupSelectedHMDDeviceName = !_selectedHMDDevice.getDevice().isNull() ? _selectedHMDDevice.deviceName() : _hmdSavedDeviceName;
|
||||||
auto device = getSimilarDevice(_backupSelectedHMDDeviceName, newDevices);
|
auto device = getSimilarDevice(_backupSelectedHMDDeviceName, newDevices);
|
||||||
device->selectedHMD = true;
|
device->selectedHMD = true;
|
||||||
emit selectedDevicePlugged(device->info, true);
|
emit selectedDevicePlugged(device->info, true);
|
||||||
}
|
}
|
||||||
if (!desktopIsSelected) {
|
if (!desktopIsSelected) {
|
||||||
_backupSelectedDesktopDeviceName = !_selectedDesktopDevice.isNull() ? _selectedDesktopDevice.deviceName() : _desktopSavedDeviceName;
|
_backupSelectedDesktopDeviceName = !_selectedDesktopDevice.getDevice().isNull() ? _selectedDesktopDevice.deviceName() : _desktopSavedDeviceName;
|
||||||
auto device = getSimilarDevice(_backupSelectedDesktopDeviceName, newDevices);
|
auto device = getSimilarDevice(_backupSelectedDesktopDeviceName, newDevices);
|
||||||
device->selectedDesktop = true;
|
device->selectedDesktop = true;
|
||||||
emit selectedDevicePlugged(device->info, false);
|
emit selectedDevicePlugged(device->info, false);
|
||||||
|
@ -382,8 +384,8 @@ AudioDevices::AudioDevices(bool& contextIsHMD) : _contextIsHMD(contextIsHMD) {
|
||||||
_outputs.onDeviceChanged(client->getActiveAudioDevice(QAudio::AudioOutput), contextIsHMD);
|
_outputs.onDeviceChanged(client->getActiveAudioDevice(QAudio::AudioOutput), 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<HifiAudioDeviceInfo>& devicesInput = client->getAudioDevices(QAudio::AudioInput);
|
||||||
const QList<QAudioDeviceInfo>& devicesOutput = client->getAudioDevices(QAudio::AudioOutput);
|
const QList<HifiAudioDeviceInfo>& devicesOutput = client->getAudioDevices(QAudio::AudioOutput);
|
||||||
|
|
||||||
//setup devices
|
//setup devices
|
||||||
_inputs.onDevicesChanged(devicesInput);
|
_inputs.onDevicesChanged(devicesInput);
|
||||||
|
@ -397,9 +399,9 @@ void AudioDevices::onContextChanged(const QString& context) {
|
||||||
_outputs.resetDevice(_contextIsHMD);
|
_outputs.resetDevice(_contextIsHMD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDevices::onDeviceSelected(QAudio::Mode mode, const QAudioDeviceInfo& device,
|
void AudioDevices::onDeviceSelected(QAudio::Mode mode, const HifiAudioDeviceInfo& device,
|
||||||
const QAudioDeviceInfo& previousDevice, bool isHMD) {
|
const HifiAudioDeviceInfo& previousDevice, bool isHMD) {
|
||||||
QString deviceName = device.isNull() ? QString() : device.deviceName();
|
QString deviceName = device.getDevice().isNull() ? QString() : device.deviceName();
|
||||||
|
|
||||||
auto& setting = getSetting(isHMD, mode);
|
auto& setting = getSetting(isHMD, mode);
|
||||||
|
|
||||||
|
@ -410,7 +412,7 @@ void AudioDevices::onDeviceSelected(QAudio::Mode mode, const QAudioDeviceInfo& d
|
||||||
setting.set(deviceName);
|
setting.set(deviceName);
|
||||||
|
|
||||||
// log the selected device
|
// log the selected device
|
||||||
if (!device.isNull()) {
|
if (!device.getDevice().isNull()) {
|
||||||
QJsonObject data;
|
QJsonObject data;
|
||||||
|
|
||||||
const QString MODE = "audio_mode";
|
const QString MODE = "audio_mode";
|
||||||
|
@ -434,13 +436,13 @@ void AudioDevices::onDeviceSelected(QAudio::Mode mode, const QAudioDeviceInfo& d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDevices::onDeviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& device) {
|
void AudioDevices::onDeviceChanged(QAudio::Mode mode, const HifiAudioDeviceInfo& device) {
|
||||||
if (mode == QAudio::AudioInput) {
|
if (mode == QAudio::AudioInput) {
|
||||||
if (_requestedInputDevice == device) {
|
if (_requestedInputDevice == device) {
|
||||||
onDeviceSelected(QAudio::AudioInput, device,
|
onDeviceSelected(QAudio::AudioInput, device,
|
||||||
_contextIsHMD ? _inputs._selectedHMDDevice : _inputs._selectedDesktopDevice,
|
_contextIsHMD ? _inputs._selectedHMDDevice : _inputs._selectedDesktopDevice,
|
||||||
_contextIsHMD);
|
_contextIsHMD);
|
||||||
_requestedInputDevice = QAudioDeviceInfo();
|
_requestedInputDevice = HifiAudioDeviceInfo();
|
||||||
}
|
}
|
||||||
_inputs.onDeviceChanged(device, _contextIsHMD);
|
_inputs.onDeviceChanged(device, _contextIsHMD);
|
||||||
} else { // if (mode == QAudio::AudioOutput)
|
} else { // if (mode == QAudio::AudioOutput)
|
||||||
|
@ -448,13 +450,13 @@ void AudioDevices::onDeviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& de
|
||||||
onDeviceSelected(QAudio::AudioOutput, device,
|
onDeviceSelected(QAudio::AudioOutput, device,
|
||||||
_contextIsHMD ? _outputs._selectedHMDDevice : _outputs._selectedDesktopDevice,
|
_contextIsHMD ? _outputs._selectedHMDDevice : _outputs._selectedDesktopDevice,
|
||||||
_contextIsHMD);
|
_contextIsHMD);
|
||||||
_requestedOutputDevice = QAudioDeviceInfo();
|
_requestedOutputDevice = HifiAudioDeviceInfo();
|
||||||
}
|
}
|
||||||
_outputs.onDeviceChanged(device, _contextIsHMD);
|
_outputs.onDeviceChanged(device, _contextIsHMD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList<QAudioDeviceInfo>& devices) {
|
void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList<HifiAudioDeviceInfo>& devices) {
|
||||||
static std::once_flag once;
|
static std::once_flag once;
|
||||||
std::call_once(once, [&] {
|
std::call_once(once, [&] {
|
||||||
//readout settings
|
//readout settings
|
||||||
|
@ -503,14 +505,14 @@ void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList<QAudioDeviceI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioDevices::chooseInputDevice(const QAudioDeviceInfo& device, bool isHMD) {
|
void AudioDevices::chooseInputDevice(const HifiAudioDeviceInfo& device, bool isHMD) {
|
||||||
//check if current context equals device to change
|
//check if current context equals device to change
|
||||||
if (_contextIsHMD == isHMD) {
|
if (_contextIsHMD == isHMD) {
|
||||||
auto client = DependencyManager::get<AudioClient>().data();
|
auto client = DependencyManager::get<AudioClient>().data();
|
||||||
_requestedInputDevice = device;
|
_requestedInputDevice = device;
|
||||||
QMetaObject::invokeMethod(client, "switchAudioDevice",
|
QMetaObject::invokeMethod(client, "switchAudioDevice",
|
||||||
Q_ARG(QAudio::Mode, QAudio::AudioInput),
|
Q_ARG(QAudio::Mode, QAudio::AudioInput),
|
||||||
Q_ARG(const QAudioDeviceInfo&, device));
|
Q_ARG(const QAudioDeviceInfo&, device.getDevice()));
|
||||||
} else {
|
} else {
|
||||||
//context is different. just save device in settings
|
//context is different. just save device in settings
|
||||||
onDeviceSelected(QAudio::AudioInput, device,
|
onDeviceSelected(QAudio::AudioInput, device,
|
||||||
|
@ -520,14 +522,14 @@ void AudioDevices::chooseInputDevice(const QAudioDeviceInfo& device, bool isHMD)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDevices::chooseOutputDevice(const QAudioDeviceInfo& device, bool isHMD) {
|
void AudioDevices::chooseOutputDevice(const HifiAudioDeviceInfo& device, bool isHMD) {
|
||||||
//check if current context equals device to change
|
//check if current context equals device to change
|
||||||
if (_contextIsHMD == isHMD) {
|
if (_contextIsHMD == isHMD) {
|
||||||
auto client = DependencyManager::get<AudioClient>().data();
|
auto client = DependencyManager::get<AudioClient>().data();
|
||||||
_requestedOutputDevice = device;
|
_requestedOutputDevice = device;
|
||||||
QMetaObject::invokeMethod(client, "switchAudioDevice",
|
QMetaObject::invokeMethod(client, "switchAudioDevice",
|
||||||
Q_ARG(QAudio::Mode, QAudio::AudioOutput),
|
Q_ARG(QAudio::Mode, QAudio::AudioOutput),
|
||||||
Q_ARG(const QAudioDeviceInfo&, device));
|
Q_ARG(const QAudioDeviceInfo&, device.getDevice()));
|
||||||
} else {
|
} else {
|
||||||
//context is different. just save device in settings
|
//context is different. just save device in settings
|
||||||
onDeviceSelected(QAudio::AudioOutput, device,
|
onDeviceSelected(QAudio::AudioOutput, device,
|
||||||
|
|
|
@ -19,11 +19,13 @@
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QAudioDeviceInfo>
|
#include <QAudioDeviceInfo>
|
||||||
|
|
||||||
|
#include "HifiAudioDeviceInfo.h"
|
||||||
|
|
||||||
namespace scripting {
|
namespace scripting {
|
||||||
|
|
||||||
class AudioDevice {
|
class AudioDevice {
|
||||||
public:
|
public:
|
||||||
QAudioDeviceInfo info;
|
HifiAudioDeviceInfo info;
|
||||||
QString display;
|
QString display;
|
||||||
bool selectedDesktop { false };
|
bool selectedDesktop { false };
|
||||||
bool selectedHMD { false };
|
bool selectedHMD { false };
|
||||||
|
@ -50,12 +52,12 @@ public:
|
||||||
void resetDevice(bool contextIsHMD);
|
void resetDevice(bool contextIsHMD);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void deviceChanged(const QAudioDeviceInfo& device);
|
void deviceChanged(const HifiAudioDeviceInfo& device);
|
||||||
void selectedDevicePlugged(const QAudioDeviceInfo& device, bool isHMD);
|
void selectedDevicePlugged(const HifiAudioDeviceInfo& device, bool isHMD);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD);
|
void onDeviceChanged(const HifiAudioDeviceInfo& device, bool isHMD);
|
||||||
void onDevicesChanged(const QList<QAudioDeviceInfo>& devices);
|
void onDevicesChanged(const QList<HifiAudioDeviceInfo>& devices);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class AudioDevices;
|
friend class AudioDevices;
|
||||||
|
@ -63,8 +65,8 @@ protected:
|
||||||
static QHash<int, QByteArray> _roles;
|
static QHash<int, QByteArray> _roles;
|
||||||
static Qt::ItemFlags _flags;
|
static Qt::ItemFlags _flags;
|
||||||
const QAudio::Mode _mode;
|
const QAudio::Mode _mode;
|
||||||
QAudioDeviceInfo _selectedDesktopDevice;
|
HifiAudioDeviceInfo _selectedDesktopDevice;
|
||||||
QAudioDeviceInfo _selectedHMDDevice;
|
HifiAudioDeviceInfo _selectedHMDDevice;
|
||||||
QString _backupSelectedDesktopDeviceName;
|
QString _backupSelectedDesktopDeviceName;
|
||||||
QString _backupSelectedHMDDeviceName;
|
QString _backupSelectedHMDDeviceName;
|
||||||
QList<std::shared_ptr<AudioDevice>> _devices;
|
QList<std::shared_ptr<AudioDevice>> _devices;
|
||||||
|
@ -124,14 +126,14 @@ signals:
|
||||||
void nop();
|
void nop();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void chooseInputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
void chooseInputDevice(const HifiAudioDeviceInfo& device, bool isHMD);
|
||||||
void chooseOutputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
void chooseOutputDevice(const HifiAudioDeviceInfo& 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 HifiAudioDeviceInfo& device,
|
||||||
const QAudioDeviceInfo& previousDevice, bool isHMD);
|
const HifiAudioDeviceInfo& previousDevice, bool isHMD);
|
||||||
void onDeviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& device);
|
void onDeviceChanged(QAudio::Mode mode, const HifiAudioDeviceInfo& device);
|
||||||
void onDevicesChanged(QAudio::Mode mode, const QList<QAudioDeviceInfo>& devices);
|
void onDevicesChanged(QAudio::Mode mode, const QList<HifiAudioDeviceInfo>& devices);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Audio;
|
friend class Audio;
|
||||||
|
@ -141,8 +143,8 @@ private:
|
||||||
|
|
||||||
AudioInputDeviceList _inputs;
|
AudioInputDeviceList _inputs;
|
||||||
AudioDeviceList _outputs { QAudio::AudioOutput };
|
AudioDeviceList _outputs { QAudio::AudioOutput };
|
||||||
QAudioDeviceInfo _requestedOutputDevice;
|
HifiAudioDeviceInfo _requestedOutputDevice;
|
||||||
QAudioDeviceInfo _requestedInputDevice;
|
HifiAudioDeviceInfo _requestedInputDevice;
|
||||||
|
|
||||||
const bool& _contextIsHMD;
|
const bool& _contextIsHMD;
|
||||||
};
|
};
|
||||||
|
|
|
@ -82,8 +82,7 @@ static const int STARVE_DETECTION_PERIOD = 10 * 1000; // 10 Seconds
|
||||||
|
|
||||||
Setting::Handle<bool> dynamicJitterBufferEnabled("dynamicJitterBuffersEnabled",
|
Setting::Handle<bool> dynamicJitterBufferEnabled("dynamicJitterBuffersEnabled",
|
||||||
InboundAudioStream::DEFAULT_DYNAMIC_JITTER_BUFFER_ENABLED);
|
InboundAudioStream::DEFAULT_DYNAMIC_JITTER_BUFFER_ENABLED);
|
||||||
Setting::Handle<int> staticJitterBufferFrames("staticJitterBufferFrames",
|
Setting::Handle<int> staticJitterBufferFrames("staticJitterBufferFrames", InboundAudioStream::DEFAULT_STATIC_JITTER_FRAMES);
|
||||||
InboundAudioStream::DEFAULT_STATIC_JITTER_FRAMES);
|
|
||||||
|
|
||||||
// protect the Qt internal device list
|
// protect the Qt internal device list
|
||||||
using Mutex = std::mutex;
|
using Mutex = std::mutex;
|
||||||
|
@ -92,10 +91,25 @@ Mutex _deviceMutex;
|
||||||
Mutex _recordMutex;
|
Mutex _recordMutex;
|
||||||
|
|
||||||
// thread-safe
|
// thread-safe
|
||||||
QList<QAudioDeviceInfo> getAvailableDevices(QAudio::Mode mode) {
|
QList<HifiAudioDeviceInfo> getAvailableDevices(QAudio::Mode mode) {
|
||||||
// NOTE: availableDevices() clobbers the Qt internal device list
|
// NOTE: availableDevices() clobbers the Qt internal device list
|
||||||
Lock lock(_deviceMutex);
|
Lock lock(_deviceMutex);
|
||||||
return QAudioDeviceInfo::availableDevices(mode);
|
auto devices = QAudioDeviceInfo::availableDevices(mode);
|
||||||
|
|
||||||
|
QList<HifiAudioDeviceInfo> newDevices;
|
||||||
|
QAudioDeviceInfo::defaultOutputDevice();
|
||||||
|
|
||||||
|
for (auto& device : devices) {
|
||||||
|
bool isDefault = false;
|
||||||
|
if (mode == QAudio::Mode::AudioInput) {
|
||||||
|
isDefault = device == QAudioDeviceInfo::defaultInputDevice();
|
||||||
|
} else {
|
||||||
|
isDefault = device == QAudioDeviceInfo::defaultOutputDevice();
|
||||||
|
}
|
||||||
|
newDevices.push_back(HifiAudioDeviceInfo(device, isDefault, mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
return newDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now called from a background thread, to keep blocking operations off the audio thread
|
// now called from a background thread, to keep blocking operations off the audio thread
|
||||||
|
@ -122,17 +136,17 @@ void AudioClient::checkDevices() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QAudioDeviceInfo AudioClient::getActiveAudioDevice(QAudio::Mode mode) const {
|
HifiAudioDeviceInfo AudioClient::getActiveAudioDevice(QAudio::Mode mode) const {
|
||||||
Lock lock(_deviceMutex);
|
Lock lock(_deviceMutex);
|
||||||
|
|
||||||
if (mode == QAudio::AudioInput) {
|
if (mode == QAudio::AudioInput) {
|
||||||
return _inputDeviceInfo;
|
return _inputDeviceInfo;
|
||||||
} else { // if (mode == QAudio::AudioOutput)
|
} else {
|
||||||
return _outputDeviceInfo;
|
return _outputDeviceInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAudioDeviceInfo> AudioClient::getAudioDevices(QAudio::Mode mode) const {
|
QList<HifiAudioDeviceInfo> AudioClient::getAudioDevices(QAudio::Mode mode) const {
|
||||||
Lock lock(_deviceMutex);
|
Lock lock(_deviceMutex);
|
||||||
|
|
||||||
if (mode == QAudio::AudioInput) {
|
if (mode == QAudio::AudioInput) {
|
||||||
|
@ -144,7 +158,6 @@ QList<QAudioDeviceInfo> AudioClient::getAudioDevices(QAudio::Mode mode) const {
|
||||||
|
|
||||||
static void channelUpmix(int16_t* source, int16_t* dest, int numSamples, int numExtraChannels) {
|
static void channelUpmix(int16_t* source, int16_t* dest, int numSamples, int numExtraChannels) {
|
||||||
for (int i = 0; i < numSamples / 2; i++) {
|
for (int i = 0; i < numSamples / 2; i++) {
|
||||||
|
|
||||||
// read 2 samples
|
// read 2 samples
|
||||||
int16_t left = *source++;
|
int16_t left = *source++;
|
||||||
int16_t right = *source++;
|
int16_t right = *source++;
|
||||||
|
@ -160,7 +173,6 @@ static void channelUpmix(int16_t* source, int16_t* dest, int numSamples, int num
|
||||||
|
|
||||||
static void channelDownmix(int16_t* source, int16_t* dest, int numSamples) {
|
static void channelDownmix(int16_t* source, int16_t* dest, int numSamples) {
|
||||||
for (int i = 0; i < numSamples / 2; i++) {
|
for (int i = 0; i < numSamples / 2; i++) {
|
||||||
|
|
||||||
// read 2 samples
|
// read 2 samples
|
||||||
int16_t left = *source++;
|
int16_t left = *source++;
|
||||||
int16_t right = *source++;
|
int16_t right = *source++;
|
||||||
|
@ -171,7 +183,6 @@ static void channelDownmix(int16_t* source, int16_t* dest, int numSamples) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool detectClipping(int16_t* samples, int numSamples, int numChannels) {
|
static bool detectClipping(int16_t* samples, int numSamples, int numChannels) {
|
||||||
|
|
||||||
const int32_t CLIPPING_THRESHOLD = 32392; // -0.1 dBFS
|
const int32_t CLIPPING_THRESHOLD = 32392; // -0.1 dBFS
|
||||||
const int CLIPPING_DETECTION = 3; // consecutive samples over threshold
|
const int CLIPPING_DETECTION = 3; // consecutive samples over threshold
|
||||||
|
|
||||||
|
@ -214,7 +225,6 @@ static bool detectClipping(int16_t* samples, int numSamples, int numChannels) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static float computeLoudness(int16_t* samples, int numSamples) {
|
static float computeLoudness(int16_t* samples, int numSamples) {
|
||||||
|
|
||||||
float scale = numSamples ? 1.0f / numSamples : 0.0f;
|
float scale = numSamples ? 1.0f / numSamples : 0.0f;
|
||||||
|
|
||||||
int32_t loudness = 0;
|
int32_t loudness = 0;
|
||||||
|
@ -226,7 +236,6 @@ static float computeLoudness(int16_t* samples, int numSamples) {
|
||||||
|
|
||||||
template <int NUM_CHANNELS>
|
template <int NUM_CHANNELS>
|
||||||
static void applyGainSmoothing(float* buffer, int numFrames, float gain0, float gain1) {
|
static void applyGainSmoothing(float* buffer, int numFrames, float gain0, float gain1) {
|
||||||
|
|
||||||
// fast path for unity gain
|
// fast path for unity gain
|
||||||
if (gain0 == 1.0f && gain1 == 1.0f) {
|
if (gain0 == 1.0f && gain1 == 1.0f) {
|
||||||
return;
|
return;
|
||||||
|
@ -241,7 +250,6 @@ static void applyGainSmoothing(float* buffer, int numFrames, float gain0, float
|
||||||
float tStep = 1.0f / numFrames;
|
float tStep = 1.0f / numFrames;
|
||||||
|
|
||||||
for (int i = 0; i < numFrames; i++) {
|
for (int i = 0; i < numFrames; i++) {
|
||||||
|
|
||||||
// evaluate poly over t=[0,1)
|
// evaluate poly over t=[0,1)
|
||||||
float gain = (c3 * t + c2) * t * t + c0;
|
float gain = (c3 * t + c2) * t * t + c0;
|
||||||
t += tStep;
|
t += tStep;
|
||||||
|
@ -258,52 +266,22 @@ static inline float convertToFloat(int16_t sample) {
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioClient::AudioClient() :
|
AudioClient::AudioClient() :
|
||||||
AbstractAudioInterface(),
|
AbstractAudioInterface(), _gate(this), _audioInput(NULL), _dummyAudioInput(NULL), _desiredInputFormat(), _inputFormat(),
|
||||||
_gate(this),
|
_numInputCallbackBytes(0), _audioOutput(NULL), _desiredOutputFormat(), _outputFormat(), _outputFrameSize(0),
|
||||||
_audioInput(NULL),
|
_numOutputCallbackBytes(0), _loopbackAudioOutput(NULL), _loopbackOutputDevice(NULL), _inputRingBuffer(0),
|
||||||
_dummyAudioInput(NULL),
|
_localInjectorsStream(0, 1), _receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES), _isStereoInput(false),
|
||||||
_desiredInputFormat(),
|
_outputStarveDetectionStartTimeMsec(0), _outputStarveDetectionCount(0),
|
||||||
_inputFormat(),
|
|
||||||
_numInputCallbackBytes(0),
|
|
||||||
_audioOutput(NULL),
|
|
||||||
_desiredOutputFormat(),
|
|
||||||
_outputFormat(),
|
|
||||||
_outputFrameSize(0),
|
|
||||||
_numOutputCallbackBytes(0),
|
|
||||||
_loopbackAudioOutput(NULL),
|
|
||||||
_loopbackOutputDevice(NULL),
|
|
||||||
_inputRingBuffer(0),
|
|
||||||
_localInjectorsStream(0, 1),
|
|
||||||
_receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES),
|
|
||||||
_isStereoInput(false),
|
|
||||||
_outputStarveDetectionStartTimeMsec(0),
|
|
||||||
_outputStarveDetectionCount(0),
|
|
||||||
_outputBufferSizeFrames("audioOutputBufferFrames", DEFAULT_BUFFER_FRAMES),
|
_outputBufferSizeFrames("audioOutputBufferFrames", DEFAULT_BUFFER_FRAMES),
|
||||||
_sessionOutputBufferSizeFrames(_outputBufferSizeFrames.get()),
|
_sessionOutputBufferSizeFrames(_outputBufferSizeFrames.get()),
|
||||||
_outputStarveDetectionEnabled("audioOutputStarveDetectionEnabled", DEFAULT_STARVE_DETECTION_ENABLED),
|
_outputStarveDetectionEnabled("audioOutputStarveDetectionEnabled", DEFAULT_STARVE_DETECTION_ENABLED),
|
||||||
_lastRawInputLoudness(0.0f),
|
_lastRawInputLoudness(0.0f), _lastSmoothedRawInputLoudness(0.0f), _lastInputLoudness(0.0f), _timeSinceLastClip(-1.0f),
|
||||||
_lastSmoothedRawInputLoudness(0.0f),
|
_muted(false), _shouldEchoLocally(false), _shouldEchoToServer(false), _isNoiseGateEnabled(true), _isAECEnabled(true),
|
||||||
_lastInputLoudness(0.0f),
|
_reverb(false), _reverbOptions(&_scriptReverbOptions), _inputToNetworkResampler(NULL), _networkToOutputResampler(NULL),
|
||||||
_timeSinceLastClip(-1.0f),
|
_localToOutputResampler(NULL), _loopbackResampler(NULL), _audioLimiter(AudioConstants::SAMPLE_RATE, OUTPUT_CHANNEL_COUNT),
|
||||||
_muted(false),
|
_outgoingAvatarAudioSequenceNumber(0), _audioOutputIODevice(_localInjectorsStream, _receivedAudioStream, this),
|
||||||
_shouldEchoLocally(false),
|
_stats(&_receivedAudioStream), _positionGetter(DEFAULT_POSITION_GETTER),
|
||||||
_shouldEchoToServer(false),
|
|
||||||
_isNoiseGateEnabled(true),
|
|
||||||
_isAECEnabled(true),
|
|
||||||
_reverb(false),
|
|
||||||
_reverbOptions(&_scriptReverbOptions),
|
|
||||||
_inputToNetworkResampler(NULL),
|
|
||||||
_networkToOutputResampler(NULL),
|
|
||||||
_localToOutputResampler(NULL),
|
|
||||||
_loopbackResampler(NULL),
|
|
||||||
_audioLimiter(AudioConstants::SAMPLE_RATE, OUTPUT_CHANNEL_COUNT),
|
|
||||||
_outgoingAvatarAudioSequenceNumber(0),
|
|
||||||
_audioOutputIODevice(_localInjectorsStream, _receivedAudioStream, this),
|
|
||||||
_stats(&_receivedAudioStream),
|
|
||||||
_positionGetter(DEFAULT_POSITION_GETTER),
|
|
||||||
#if defined(Q_OS_ANDROID)
|
#if defined(Q_OS_ANDROID)
|
||||||
_checkInputTimer(this),
|
_checkInputTimer(this), _isHeadsetPluggedIn(false),
|
||||||
_isHeadsetPluggedIn(false),
|
|
||||||
#endif
|
#endif
|
||||||
_orientationGetter(DEFAULT_ORIENTATION_GETTER) {
|
_orientationGetter(DEFAULT_ORIENTATION_GETTER) {
|
||||||
|
|
||||||
|
@ -314,17 +292,21 @@ AudioClient::AudioClient() :
|
||||||
{
|
{
|
||||||
Setting::Handle<int>::Deprecated("maxFramesOverDesired", InboundAudioStream::MAX_FRAMES_OVER_DESIRED);
|
Setting::Handle<int>::Deprecated("maxFramesOverDesired", InboundAudioStream::MAX_FRAMES_OVER_DESIRED);
|
||||||
Setting::Handle<int>::Deprecated("windowStarveThreshold", InboundAudioStream::WINDOW_STARVE_THRESHOLD);
|
Setting::Handle<int>::Deprecated("windowStarveThreshold", InboundAudioStream::WINDOW_STARVE_THRESHOLD);
|
||||||
Setting::Handle<int>::Deprecated("windowSecondsForDesiredCalcOnTooManyStarves", InboundAudioStream::WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES);
|
Setting::Handle<int>::Deprecated("windowSecondsForDesiredCalcOnTooManyStarves",
|
||||||
Setting::Handle<int>::Deprecated("windowSecondsForDesiredReduction", InboundAudioStream::WINDOW_SECONDS_FOR_DESIRED_REDUCTION);
|
InboundAudioStream::WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES);
|
||||||
|
Setting::Handle<int>::Deprecated("windowSecondsForDesiredReduction",
|
||||||
|
InboundAudioStream::WINDOW_SECONDS_FOR_DESIRED_REDUCTION);
|
||||||
Setting::Handle<bool>::Deprecated("useStDevForJitterCalc", InboundAudioStream::USE_STDEV_FOR_JITTER);
|
Setting::Handle<bool>::Deprecated("useStDevForJitterCalc", InboundAudioStream::USE_STDEV_FOR_JITTER);
|
||||||
Setting::Handle<bool>::Deprecated("repetitionWithFade", InboundAudioStream::REPETITION_WITH_FADE);
|
Setting::Handle<bool>::Deprecated("repetitionWithFade", InboundAudioStream::REPETITION_WITH_FADE);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(&_receivedAudioStream, &MixedProcessedAudioStream::processSamples,
|
connect(&_receivedAudioStream, &MixedProcessedAudioStream::processSamples, this, &AudioClient::processReceivedSamples,
|
||||||
this, &AudioClient::processReceivedSamples, Qt::DirectConnection);
|
Qt::DirectConnection);
|
||||||
connect(this, &AudioClient::changeDevice, this, [=](const QAudioDeviceInfo& outputDeviceInfo) {
|
connect(this, &AudioClient::changeDevice, this, [=](const HifiAudioDeviceInfo& outputDeviceInfo) {
|
||||||
qCDebug(audioclient) << "got AudioClient::changeDevice signal, about to call switchOutputToAudioDevice() outputDeviceInfo: [" << outputDeviceInfo.deviceName() << "]";
|
qCDebug(audioclient)
|
||||||
switchOutputToAudioDevice(outputDeviceInfo);
|
<< "got AudioClient::changeDevice signal, about to call switchOutputToAudioDevice() outputDeviceInfo: ["
|
||||||
|
<< outputDeviceInfo.deviceName() << "]";
|
||||||
|
switchOutputToAudioDevice(outputDeviceInfo.getDevice());
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(&_receivedAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioClient::handleMismatchAudioFormat);
|
connect(&_receivedAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioClient::handleMismatchAudioFormat);
|
||||||
|
@ -350,9 +332,8 @@ AudioClient::AudioClient() :
|
||||||
|
|
||||||
// start a thread to detect peak value changes
|
// start a thread to detect peak value changes
|
||||||
_checkPeakValuesTimer = new QTimer(this);
|
_checkPeakValuesTimer = new QTimer(this);
|
||||||
connect(_checkPeakValuesTimer, &QTimer::timeout, this, [this] {
|
connect(_checkPeakValuesTimer, &QTimer::timeout, this,
|
||||||
QtConcurrent::run(QThreadPool::globalInstance(), [this] { checkPeakValues(); });
|
[this] { QtConcurrent::run(QThreadPool::globalInstance(), [this] { checkPeakValues(); }); });
|
||||||
});
|
|
||||||
const unsigned long PEAK_VALUES_CHECK_INTERVAL_MSECS = 50;
|
const unsigned long PEAK_VALUES_CHECK_INTERVAL_MSECS = 50;
|
||||||
_checkPeakValuesTimer->start(PEAK_VALUES_CHECK_INTERVAL_MSECS);
|
_checkPeakValuesTimer->start(PEAK_VALUES_CHECK_INTERVAL_MSECS);
|
||||||
|
|
||||||
|
@ -373,9 +354,7 @@ AudioClient::AudioClient() :
|
||||||
packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat");
|
packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat");
|
||||||
|
|
||||||
auto& domainHandler = nodeList->getDomainHandler();
|
auto& domainHandler = nodeList->getDomainHandler();
|
||||||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this] {
|
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this] { _solo.reset(); });
|
||||||
_solo.reset();
|
|
||||||
});
|
|
||||||
connect(nodeList.data(), &NodeList::nodeActivated, this, [this](SharedNodePointer node) {
|
connect(nodeList.data(), &NodeList::nodeActivated, this, [this](SharedNodePointer node) {
|
||||||
if (node->getType() == NodeType::AudioMixer) {
|
if (node->getType() == NodeType::AudioMixer) {
|
||||||
_solo.resend();
|
_solo.resend();
|
||||||
|
@ -384,7 +363,6 @@ AudioClient::AudioClient() :
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioClient::~AudioClient() {
|
AudioClient::~AudioClient() {
|
||||||
|
|
||||||
stop();
|
stop();
|
||||||
|
|
||||||
if (_codec && _encoder) {
|
if (_codec && _encoder) {
|
||||||
|
@ -401,11 +379,11 @@ void AudioClient::customDeleter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) {
|
void AudioClient::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) {
|
||||||
qCDebug(audioclient) << __FUNCTION__ << "sendingNode:" << *node << "currentCodec:" << currentCodec << "recievedCodec:" << recievedCodec;
|
qCDebug(audioclient) << __FUNCTION__ << "sendingNode:" << *node << "currentCodec:" << currentCodec
|
||||||
|
<< "recievedCodec:" << recievedCodec;
|
||||||
selectAudioFormat(recievedCodec);
|
selectAudioFormat(recievedCodec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioClient::reset() {
|
void AudioClient::reset() {
|
||||||
_receivedAudioStream.reset();
|
_receivedAudioStream.reset();
|
||||||
_stats.reset();
|
_stats.reset();
|
||||||
|
@ -433,9 +411,9 @@ void AudioClient::setAudioPaused(bool pause) {
|
||||||
|
|
||||||
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 (HifiAudioDeviceInfo audioDevice, getAvailableDevices(mode)) {
|
||||||
if (audioDevice.deviceName().trimmed() == deviceName.trimmed()) {
|
if (audioDevice.deviceName().trimmed() == deviceName.trimmed()) {
|
||||||
result = audioDevice;
|
result = audioDevice.getDevice();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -468,7 +446,8 @@ QString AudioClient::getWinDeviceName(wchar_t* guid) {
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
CoInitialize(nullptr);
|
CoInitialize(nullptr);
|
||||||
IMMDeviceEnumerator* pMMDeviceEnumerator = nullptr;
|
IMMDeviceEnumerator* pMMDeviceEnumerator = nullptr;
|
||||||
CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator);
|
CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
|
||||||
|
(void**)&pMMDeviceEnumerator);
|
||||||
IMMDevice* pEndpoint;
|
IMMDevice* pEndpoint;
|
||||||
hr = pMMDeviceEnumerator->GetDevice(guid, &pEndpoint);
|
hr = pMMDeviceEnumerator->GetDevice(guid, &pEndpoint);
|
||||||
if (hr == E_NOTFOUND) {
|
if (hr == E_NOTFOUND) {
|
||||||
|
@ -492,30 +471,22 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
||||||
if (getAvailableDevices(mode).size() > 1) {
|
if (getAvailableDevices(mode).size() > 1) {
|
||||||
AudioDeviceID defaultDeviceID = 0;
|
AudioDeviceID defaultDeviceID = 0;
|
||||||
uint32_t propertySize = sizeof(AudioDeviceID);
|
uint32_t propertySize = sizeof(AudioDeviceID);
|
||||||
AudioObjectPropertyAddress propertyAddress = {
|
AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyDefaultInputDevice,
|
||||||
kAudioHardwarePropertyDefaultInputDevice,
|
kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
|
||||||
kAudioObjectPropertyScopeGlobal,
|
|
||||||
kAudioObjectPropertyElementMaster
|
|
||||||
};
|
|
||||||
|
|
||||||
if (mode == QAudio::AudioOutput) {
|
if (mode == QAudio::AudioOutput) {
|
||||||
propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
|
propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OSStatus getPropertyError =
|
||||||
OSStatus getPropertyError = AudioObjectGetPropertyData(kAudioObjectSystemObject,
|
AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &defaultDeviceID);
|
||||||
&propertyAddress,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
&propertySize,
|
|
||||||
&defaultDeviceID);
|
|
||||||
|
|
||||||
if (!getPropertyError && propertySize) {
|
if (!getPropertyError && propertySize) {
|
||||||
CFStringRef deviceName = NULL;
|
CFStringRef deviceName = NULL;
|
||||||
propertySize = sizeof(deviceName);
|
propertySize = sizeof(deviceName);
|
||||||
propertyAddress.mSelector = kAudioDevicePropertyDeviceNameCFString;
|
propertyAddress.mSelector = kAudioDevicePropertyDeviceNameCFString;
|
||||||
getPropertyError = AudioObjectGetPropertyData(defaultDeviceID, &propertyAddress, 0,
|
getPropertyError =
|
||||||
NULL, &propertySize, &deviceName);
|
AudioObjectGetPropertyData(defaultDeviceID, &propertyAddress, 0, NULL, &propertySize, &deviceName);
|
||||||
|
|
||||||
if (!getPropertyError && propertySize) {
|
if (!getPropertyError && propertySize) {
|
||||||
// find a device in the list that matches the name we have and return it
|
// find a device in the list that matches the name we have and return it
|
||||||
|
@ -553,9 +524,11 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
CoInitialize(NULL);
|
CoInitialize(NULL);
|
||||||
IMMDeviceEnumerator* pMMDeviceEnumerator = NULL;
|
IMMDeviceEnumerator* pMMDeviceEnumerator = NULL;
|
||||||
CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator);
|
CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
|
||||||
|
(void**)&pMMDeviceEnumerator);
|
||||||
IMMDevice* pEndpoint;
|
IMMDevice* pEndpoint;
|
||||||
hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint(mode == QAudio::AudioOutput ? eRender : eCapture, eMultimedia, &pEndpoint);
|
hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint(mode == QAudio::AudioOutput ? eRender : eCapture, eMultimedia,
|
||||||
|
&pEndpoint);
|
||||||
if (hr == E_NOTFOUND) {
|
if (hr == E_NOTFOUND) {
|
||||||
printf("Audio Error: device not found\n");
|
printf("Audio Error: device not found\n");
|
||||||
deviceName = QString("NONE");
|
deviceName = QString("NONE");
|
||||||
|
@ -569,8 +542,8 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(audioclient) << "defaultAudioDeviceForMode mode: " << (mode == QAudio::AudioOutput ? "Output" : "Input")
|
qCDebug(audioclient) << "defaultAudioDeviceForMode mode: " << (mode == QAudio::AudioOutput ? "Output" : "Input") << " ["
|
||||||
<< " [" << deviceName << "] [" << getNamedAudioDeviceForMode(mode, deviceName).deviceName() << "]";
|
<< deviceName << "] [" << getNamedAudioDeviceForMode(mode, deviceName).deviceName() << "]";
|
||||||
|
|
||||||
return getNamedAudioDeviceForMode(mode, deviceName);
|
return getNamedAudioDeviceForMode(mode, deviceName);
|
||||||
#endif
|
#endif
|
||||||
|
@ -598,10 +571,8 @@ bool AudioClient::getNamedAudioDeviceForModeExists(QAudio::Mode mode, const QStr
|
||||||
return (getNamedAudioDeviceForMode(mode, deviceName).deviceName() == deviceName);
|
return (getNamedAudioDeviceForMode(mode, deviceName).deviceName() == deviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// attempt to use the native sample rate and channel count
|
// attempt to use the native sample rate and channel count
|
||||||
bool nativeFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, QAudioFormat& audioFormat) {
|
bool nativeFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, QAudioFormat& audioFormat) {
|
||||||
|
|
||||||
audioFormat = audioDevice.preferredFormat();
|
audioFormat = audioDevice.preferredFormat();
|
||||||
|
|
||||||
// converting to/from this rate must produce an integral number of samples
|
// converting to/from this rate must produce an integral number of samples
|
||||||
|
@ -622,7 +593,6 @@ bool nativeFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, QAudioForma
|
||||||
// attempt the native sample rate, with channels forced to 2
|
// attempt the native sample rate, with channels forced to 2
|
||||||
audioFormat.setChannelCount(2);
|
audioFormat.setChannelCount(2);
|
||||||
if (!audioDevice.isFormatSupported(audioFormat)) {
|
if (!audioDevice.isFormatSupported(audioFormat)) {
|
||||||
|
|
||||||
// attempt the native sample rate, with channels forced to 1
|
// attempt the native sample rate, with channels forced to 1
|
||||||
audioFormat.setChannelCount(1);
|
audioFormat.setChannelCount(1);
|
||||||
if (!audioDevice.isFormatSupported(audioFormat)) {
|
if (!audioDevice.isFormatSupported(audioFormat)) {
|
||||||
|
@ -636,7 +606,6 @@ bool nativeFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, QAudioForma
|
||||||
bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
|
bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
|
||||||
const QAudioFormat& desiredAudioFormat,
|
const QAudioFormat& desiredAudioFormat,
|
||||||
QAudioFormat& adjustedAudioFormat) {
|
QAudioFormat& adjustedAudioFormat) {
|
||||||
|
|
||||||
qCDebug(audioclient) << "The desired format for audio I/O is" << desiredAudioFormat;
|
qCDebug(audioclient) << "The desired format for audio I/O is" << desiredAudioFormat;
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
|
@ -669,7 +638,6 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
|
||||||
|
|
||||||
for (int channelCount : (desiredAudioFormat.channelCount() == 1 ? inputChannels : outputChannels)) {
|
for (int channelCount : (desiredAudioFormat.channelCount() == 1 ? inputChannels : outputChannels)) {
|
||||||
for (int sampleRate : sampleRates) {
|
for (int sampleRate : sampleRates) {
|
||||||
|
|
||||||
adjustedAudioFormat.setChannelCount(channelCount);
|
adjustedAudioFormat.setChannelCount(channelCount);
|
||||||
adjustedAudioFormat.setSampleRate(sampleRate);
|
adjustedAudioFormat.setSampleRate(sampleRate);
|
||||||
|
|
||||||
|
@ -682,8 +650,11 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
|
||||||
return false; // a supported format could not be found
|
return false; // a supported format could not be found
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sampleChannelConversion(const int16_t* sourceSamples, int16_t* destinationSamples, int numSourceSamples,
|
bool sampleChannelConversion(const int16_t* sourceSamples,
|
||||||
const int sourceChannelCount, const int destinationChannelCount) {
|
int16_t* destinationSamples,
|
||||||
|
int numSourceSamples,
|
||||||
|
const int sourceChannelCount,
|
||||||
|
const int destinationChannelCount) {
|
||||||
if (sourceChannelCount == 2 && destinationChannelCount == 1) {
|
if (sourceChannelCount == 2 && destinationChannelCount == 1) {
|
||||||
// loop through the stereo input audio samples and average every two samples
|
// loop through the stereo input audio samples and average every two samples
|
||||||
for (int i = 0; i < numSourceSamples; i += 2) {
|
for (int i = 0; i < numSourceSamples; i += 2) {
|
||||||
|
@ -692,7 +663,6 @@ bool sampleChannelConversion(const int16_t* sourceSamples, int16_t* destinationS
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (sourceChannelCount == 1 && destinationChannelCount == 2) {
|
} else if (sourceChannelCount == 1 && destinationChannelCount == 2) {
|
||||||
|
|
||||||
// loop through the mono input audio and repeat each sample twice
|
// loop through the mono input audio and repeat each sample twice
|
||||||
for (int i = 0; i < numSourceSamples; ++i) {
|
for (int i = 0; i < numSourceSamples; ++i) {
|
||||||
destinationSamples[i * 2] = destinationSamples[(i * 2) + 1] = sourceSamples[i];
|
destinationSamples[i * 2] = destinationSamples[(i * 2) + 1] = sourceSamples[i];
|
||||||
|
@ -705,28 +675,29 @@ bool sampleChannelConversion(const int16_t* sourceSamples, int16_t* destinationS
|
||||||
}
|
}
|
||||||
|
|
||||||
int possibleResampling(AudioSRC* resampler,
|
int possibleResampling(AudioSRC* resampler,
|
||||||
const int16_t* sourceSamples, int16_t* destinationSamples,
|
const int16_t* sourceSamples,
|
||||||
int numSourceSamples, int maxDestinationSamples,
|
int16_t* destinationSamples,
|
||||||
const int sourceChannelCount, const int destinationChannelCount) {
|
int numSourceSamples,
|
||||||
|
int maxDestinationSamples,
|
||||||
|
const int sourceChannelCount,
|
||||||
|
const int destinationChannelCount) {
|
||||||
int numSourceFrames = numSourceSamples / sourceChannelCount;
|
int numSourceFrames = numSourceSamples / sourceChannelCount;
|
||||||
int numDestinationFrames = 0;
|
int numDestinationFrames = 0;
|
||||||
|
|
||||||
if (numSourceSamples > 0) {
|
if (numSourceSamples > 0) {
|
||||||
if (!resampler) {
|
if (!resampler) {
|
||||||
if (!sampleChannelConversion(sourceSamples, destinationSamples, numSourceSamples,
|
if (!sampleChannelConversion(sourceSamples, destinationSamples, numSourceSamples, sourceChannelCount,
|
||||||
sourceChannelCount, destinationChannelCount)) {
|
destinationChannelCount)) {
|
||||||
// no conversion, we can copy the samples directly across
|
// no conversion, we can copy the samples directly across
|
||||||
memcpy(destinationSamples, sourceSamples, numSourceSamples * AudioConstants::SAMPLE_SIZE);
|
memcpy(destinationSamples, sourceSamples, numSourceSamples * AudioConstants::SAMPLE_SIZE);
|
||||||
}
|
}
|
||||||
numDestinationFrames = numSourceFrames;
|
numDestinationFrames = numSourceFrames;
|
||||||
} else {
|
} else {
|
||||||
if (sourceChannelCount != destinationChannelCount) {
|
if (sourceChannelCount != destinationChannelCount) {
|
||||||
|
|
||||||
int16_t* channelConversionSamples = new int16_t[numSourceFrames * destinationChannelCount];
|
int16_t* channelConversionSamples = new int16_t[numSourceFrames * destinationChannelCount];
|
||||||
|
|
||||||
sampleChannelConversion(sourceSamples, channelConversionSamples, numSourceSamples,
|
sampleChannelConversion(sourceSamples, channelConversionSamples, numSourceSamples, sourceChannelCount,
|
||||||
sourceChannelCount, destinationChannelCount);
|
destinationChannelCount);
|
||||||
|
|
||||||
numDestinationFrames = resampler->render(channelConversionSamples, destinationSamples, numSourceFrames);
|
numDestinationFrames = resampler->render(channelConversionSamples, destinationSamples, numSourceFrames);
|
||||||
|
|
||||||
|
@ -746,7 +717,6 @@ int possibleResampling(AudioSRC* resampler,
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::start() {
|
void AudioClient::start() {
|
||||||
|
|
||||||
// set up the desired audio format
|
// set up the desired audio format
|
||||||
_desiredInputFormat.setSampleRate(AudioConstants::SAMPLE_RATE);
|
_desiredInputFormat.setSampleRate(AudioConstants::SAMPLE_RATE);
|
||||||
_desiredInputFormat.setSampleSize(16);
|
_desiredInputFormat.setSampleSize(16);
|
||||||
|
@ -835,7 +805,6 @@ void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message)
|
||||||
nodeList->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveFirstAudioPacket);
|
nodeList->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveFirstAudioPacket);
|
||||||
|
|
||||||
if (_audioOutput) {
|
if (_audioOutput) {
|
||||||
|
|
||||||
if (!_hasReceivedFirstPacket) {
|
if (!_hasReceivedFirstPacket) {
|
||||||
_hasReceivedFirstPacket = true;
|
_hasReceivedFirstPacket = true;
|
||||||
|
|
||||||
|
@ -852,8 +821,8 @@ void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioClient::Gate::Gate(AudioClient* audioClient) :
|
AudioClient::Gate::Gate(AudioClient* audioClient) : _audioClient(audioClient) {
|
||||||
_audioClient(audioClient) {}
|
}
|
||||||
|
|
||||||
void AudioClient::Gate::setIsSimulatingJitter(bool enable) {
|
void AudioClient::Gate::setIsSimulatingJitter(bool enable) {
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
@ -906,7 +875,6 @@ void AudioClient::Gate::flush() {
|
||||||
_index = 0;
|
_index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioClient::handleNoisyMutePacket(QSharedPointer<ReceivedMessage> message) {
|
void AudioClient::handleNoisyMutePacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
if (!_muted) {
|
if (!_muted) {
|
||||||
setMuted(true);
|
setMuted(true);
|
||||||
|
@ -952,7 +920,6 @@ void AudioClient::handleSelectedAudioFormat(QSharedPointer<ReceivedMessage> mess
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::selectAudioFormat(const QString& selectedCodecName) {
|
void AudioClient::selectAudioFormat(const QString& selectedCodecName) {
|
||||||
|
|
||||||
_selectedCodecName = selectedCodecName;
|
_selectedCodecName = selectedCodecName;
|
||||||
|
|
||||||
qCDebug(audioclient) << "Selected Codec:" << _selectedCodecName << "isStereoInput:" << _isStereoInput;
|
qCDebug(audioclient) << "Selected Codec:" << _selectedCodecName << "isStereoInput:" << _isStereoInput;
|
||||||
|
@ -970,12 +937,12 @@ void AudioClient::selectAudioFormat(const QString& selectedCodecName) {
|
||||||
if (_selectedCodecName == plugin->getName()) {
|
if (_selectedCodecName == plugin->getName()) {
|
||||||
_codec = plugin;
|
_codec = plugin;
|
||||||
_receivedAudioStream.setupCodec(plugin, _selectedCodecName, AudioConstants::STEREO);
|
_receivedAudioStream.setupCodec(plugin, _selectedCodecName, AudioConstants::STEREO);
|
||||||
_encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE, _isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
_encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE,
|
||||||
|
_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||||
qCDebug(audioclient) << "Selected Codec Plugin:" << _codec.get();
|
qCDebug(audioclient) << "Selected Codec Plugin:" << _codec.get();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioClient::switchAudioDevice(QAudio::Mode mode, const QAudioDeviceInfo& deviceInfo) {
|
bool AudioClient::switchAudioDevice(QAudio::Mode mode, const QAudioDeviceInfo& deviceInfo) {
|
||||||
|
@ -1040,7 +1007,6 @@ void AudioClient::configureReverb() {
|
||||||
void AudioClient::updateReverbOptions() {
|
void AudioClient::updateReverbOptions() {
|
||||||
bool reverbChanged = false;
|
bool reverbChanged = false;
|
||||||
if (_receivedAudioStream.hasReverb()) {
|
if (_receivedAudioStream.hasReverb()) {
|
||||||
|
|
||||||
if (_zoneReverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) {
|
if (_zoneReverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) {
|
||||||
_zoneReverbOptions.setReverbTime(_receivedAudioStream.getRevebTime());
|
_zoneReverbOptions.setReverbTime(_receivedAudioStream.getRevebTime());
|
||||||
reverbChanged = true;
|
reverbChanged = true;
|
||||||
|
@ -1153,7 +1119,6 @@ void AudioClient::configureWebrtc() {
|
||||||
|
|
||||||
// rebuffer into 10ms chunks
|
// rebuffer into 10ms chunks
|
||||||
void AudioClient::processWebrtcFarEnd(const int16_t* samples, int numFrames, int numChannels, int sampleRate) {
|
void AudioClient::processWebrtcFarEnd(const int16_t* samples, int numFrames, int numChannels, int sampleRate) {
|
||||||
|
|
||||||
const webrtc::StreamConfig streamConfig = webrtc::StreamConfig(sampleRate, numChannels);
|
const webrtc::StreamConfig streamConfig = webrtc::StreamConfig(sampleRate, numChannels);
|
||||||
const int numChunk = (int)streamConfig.num_frames();
|
const int numChunk = (int)streamConfig.num_frames();
|
||||||
|
|
||||||
|
@ -1167,7 +1132,6 @@ void AudioClient::processWebrtcFarEnd(const int16_t* samples, int numFrames, int
|
||||||
}
|
}
|
||||||
|
|
||||||
while (numFrames > 0) {
|
while (numFrames > 0) {
|
||||||
|
|
||||||
// number of frames to fill
|
// number of frames to fill
|
||||||
int numFill = std::min(numFrames, numChunk - _numFifoFarEnd);
|
int numFill = std::min(numFrames, numChunk - _numFifoFarEnd);
|
||||||
|
|
||||||
|
@ -1178,7 +1142,6 @@ void AudioClient::processWebrtcFarEnd(const int16_t* samples, int numFrames, int
|
||||||
_numFifoFarEnd += numFill;
|
_numFifoFarEnd += numFill;
|
||||||
|
|
||||||
if (_numFifoFarEnd == numChunk) {
|
if (_numFifoFarEnd == numChunk) {
|
||||||
|
|
||||||
// convert audio format
|
// convert audio format
|
||||||
float buffer[WEBRTC_CHANNELS_MAX][WEBRTC_FRAMES_MAX];
|
float buffer[WEBRTC_CHANNELS_MAX][WEBRTC_FRAMES_MAX];
|
||||||
float* const buffers[WEBRTC_CHANNELS_MAX] = { buffer[0], buffer[1] };
|
float* const buffers[WEBRTC_CHANNELS_MAX] = { buffer[0], buffer[1] };
|
||||||
|
@ -1195,7 +1158,6 @@ void AudioClient::processWebrtcFarEnd(const int16_t* samples, int numFrames, int
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::processWebrtcNearEnd(int16_t* samples, int numFrames, int numChannels, int sampleRate) {
|
void AudioClient::processWebrtcNearEnd(int16_t* samples, int numFrames, int numChannels, int sampleRate) {
|
||||||
|
|
||||||
const webrtc::StreamConfig streamConfig = webrtc::StreamConfig(sampleRate, numChannels);
|
const webrtc::StreamConfig streamConfig = webrtc::StreamConfig(sampleRate, numChannels);
|
||||||
const int numChunk = (int)streamConfig.num_frames();
|
const int numChunk = (int)streamConfig.num_frames();
|
||||||
|
|
||||||
|
@ -1254,7 +1216,8 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
||||||
|
|
||||||
// if required, create loopback resampler
|
// if required, create loopback resampler
|
||||||
if (_inputFormat.sampleRate() != _outputFormat.sampleRate() && !_loopbackResampler) {
|
if (_inputFormat.sampleRate() != _outputFormat.sampleRate() && !_loopbackResampler) {
|
||||||
qCDebug(audioclient) << "Resampling from" << _inputFormat.sampleRate() << "to" << _outputFormat.sampleRate() << "for audio loopback.";
|
qCDebug(audioclient) << "Resampling from" << _inputFormat.sampleRate() << "to" << _outputFormat.sampleRate()
|
||||||
|
<< "for audio loopback.";
|
||||||
_loopbackResampler = new AudioSRC(_inputFormat.sampleRate(), _outputFormat.sampleRate(), OUTPUT_CHANNEL_COUNT);
|
_loopbackResampler = new AudioSRC(_inputFormat.sampleRate(), _outputFormat.sampleRate(), OUTPUT_CHANNEL_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1270,10 +1233,8 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
||||||
int16_t* inputSamples = reinterpret_cast<int16_t*>(inputByteArray.data());
|
int16_t* inputSamples = reinterpret_cast<int16_t*>(inputByteArray.data());
|
||||||
int16_t* loopbackSamples = reinterpret_cast<int16_t*>(loopBackByteArray.data());
|
int16_t* loopbackSamples = reinterpret_cast<int16_t*>(loopBackByteArray.data());
|
||||||
|
|
||||||
int numLoopbackSamples = possibleResampling(_loopbackResampler,
|
int numLoopbackSamples = possibleResampling(_loopbackResampler, inputSamples, loopbackSamples, numInputSamples,
|
||||||
inputSamples, loopbackSamples,
|
maxLoopbackSamples, _inputFormat.channelCount(), OUTPUT_CHANNEL_COUNT);
|
||||||
numInputSamples, maxLoopbackSamples,
|
|
||||||
_inputFormat.channelCount(), OUTPUT_CHANNEL_COUNT);
|
|
||||||
|
|
||||||
loopBackByteArray.resize(numLoopbackSamples * AudioConstants::SAMPLE_SIZE);
|
loopBackByteArray.resize(numLoopbackSamples * AudioConstants::SAMPLE_SIZE);
|
||||||
|
|
||||||
|
@ -1286,11 +1247,9 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
||||||
// if required, upmix or downmix to deviceChannelCount
|
// if required, upmix or downmix to deviceChannelCount
|
||||||
int deviceChannelCount = _outputFormat.channelCount();
|
int deviceChannelCount = _outputFormat.channelCount();
|
||||||
if (deviceChannelCount == OUTPUT_CHANNEL_COUNT) {
|
if (deviceChannelCount == OUTPUT_CHANNEL_COUNT) {
|
||||||
|
|
||||||
_loopbackOutputDevice->write(loopBackByteArray);
|
_loopbackOutputDevice->write(loopBackByteArray);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
static QByteArray deviceByteArray;
|
static QByteArray deviceByteArray;
|
||||||
|
|
||||||
int numDeviceSamples = (numLoopbackSamples * deviceChannelCount) / OUTPUT_CHANNEL_COUNT;
|
int numDeviceSamples = (numLoopbackSamples * deviceChannelCount) / OUTPUT_CHANNEL_COUNT;
|
||||||
|
@ -1310,7 +1269,6 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
||||||
|
|
||||||
void AudioClient::handleAudioInput(QByteArray& audioBuffer) {
|
void AudioClient::handleAudioInput(QByteArray& audioBuffer) {
|
||||||
if (!_audioPaused) {
|
if (!_audioPaused) {
|
||||||
|
|
||||||
bool audioGateOpen = false;
|
bool audioGateOpen = false;
|
||||||
|
|
||||||
if (!_muted) {
|
if (!_muted) {
|
||||||
|
@ -1364,8 +1322,7 @@ void AudioClient::handleAudioInput(QByteArray& audioBuffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, _isStereoInput,
|
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, _isStereoInput,
|
||||||
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale,
|
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale, packetType, _selectedCodecName);
|
||||||
packetType, _selectedCodecName);
|
|
||||||
_stats.sentPacket();
|
_stats.sentPacket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1380,9 +1337,10 @@ void AudioClient::handleMicAudioInput() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// input samples required to produce exactly NETWORK_FRAME_SAMPLES of output
|
// input samples required to produce exactly NETWORK_FRAME_SAMPLES of output
|
||||||
const int inputSamplesRequired = (_inputToNetworkResampler ?
|
const int inputSamplesRequired =
|
||||||
_inputToNetworkResampler->getMinInput(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL) :
|
(_inputToNetworkResampler ? _inputToNetworkResampler->getMinInput(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL)
|
||||||
AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL) * _inputFormat.channelCount();
|
: AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL) *
|
||||||
|
_inputFormat.channelCount();
|
||||||
|
|
||||||
const auto inputAudioSamples = std::unique_ptr<int16_t[]>(new int16_t[inputSamplesRequired]);
|
const auto inputAudioSamples = std::unique_ptr<int16_t[]>(new int16_t[inputSamplesRequired]);
|
||||||
QByteArray inputByteArray = _inputDevice->readAll();
|
QByteArray inputByteArray = _inputDevice->readAll();
|
||||||
|
@ -1394,17 +1352,14 @@ void AudioClient::handleMicAudioInput() {
|
||||||
float audioInputMsecsRead = inputByteArray.size() / (float)(_inputFormat.bytesForDuration(USECS_PER_MSEC));
|
float audioInputMsecsRead = inputByteArray.size() / (float)(_inputFormat.bytesForDuration(USECS_PER_MSEC));
|
||||||
_stats.updateInputMsRead(audioInputMsecsRead);
|
_stats.updateInputMsRead(audioInputMsecsRead);
|
||||||
|
|
||||||
const int numNetworkBytes = _isStereoInput
|
const int numNetworkBytes =
|
||||||
? AudioConstants::NETWORK_FRAME_BYTES_STEREO
|
_isStereoInput ? AudioConstants::NETWORK_FRAME_BYTES_STEREO : AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL;
|
||||||
: AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL;
|
const int numNetworkSamples =
|
||||||
const int numNetworkSamples = _isStereoInput
|
_isStereoInput ? AudioConstants::NETWORK_FRAME_SAMPLES_STEREO : AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL;
|
||||||
? AudioConstants::NETWORK_FRAME_SAMPLES_STEREO
|
|
||||||
: AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL;
|
|
||||||
|
|
||||||
static int16_t networkAudioSamples[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO];
|
static int16_t networkAudioSamples[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO];
|
||||||
|
|
||||||
while (_inputRingBuffer.samplesAvailable() >= inputSamplesRequired) {
|
while (_inputRingBuffer.samplesAvailable() >= inputSamplesRequired) {
|
||||||
|
|
||||||
_inputRingBuffer.readSamples(inputAudioSamples.get(), inputSamplesRequired);
|
_inputRingBuffer.readSamples(inputAudioSamples.get(), inputSamplesRequired);
|
||||||
|
|
||||||
// detect clipping on the raw input
|
// detect clipping on the raw input
|
||||||
|
@ -1434,10 +1389,8 @@ void AudioClient::handleMicAudioInput() {
|
||||||
emit inputLoudnessChanged(_lastSmoothedRawInputLoudness, isClipping);
|
emit inputLoudnessChanged(_lastSmoothedRawInputLoudness, isClipping);
|
||||||
|
|
||||||
if (!_muted) {
|
if (!_muted) {
|
||||||
possibleResampling(_inputToNetworkResampler,
|
possibleResampling(_inputToNetworkResampler, inputAudioSamples.get(), networkAudioSamples, inputSamplesRequired,
|
||||||
inputAudioSamples.get(), networkAudioSamples,
|
numNetworkSamples, _inputFormat.channelCount(), _desiredInputFormat.channelCount());
|
||||||
inputSamplesRequired, numNetworkSamples,
|
|
||||||
_inputFormat.channelCount(), _desiredInputFormat.channelCount());
|
|
||||||
}
|
}
|
||||||
int bytesInInputRingBuffer = _inputRingBuffer.samplesAvailable() * AudioConstants::SAMPLE_SIZE;
|
int bytesInInputRingBuffer = _inputRingBuffer.samplesAvailable() * AudioConstants::SAMPLE_SIZE;
|
||||||
float msecsInInputRingBuffer = bytesInInputRingBuffer / (float)(_inputFormat.bytesForDuration(USECS_PER_MSEC));
|
float msecsInInputRingBuffer = bytesInInputRingBuffer / (float)(_inputFormat.bytesForDuration(USECS_PER_MSEC));
|
||||||
|
@ -1449,9 +1402,8 @@ void AudioClient::handleMicAudioInput() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleDummyAudioInput() {
|
void AudioClient::handleDummyAudioInput() {
|
||||||
const int numNetworkBytes = _isStereoInput
|
const int numNetworkBytes =
|
||||||
? AudioConstants::NETWORK_FRAME_BYTES_STEREO
|
_isStereoInput ? AudioConstants::NETWORK_FRAME_BYTES_STEREO : AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL;
|
||||||
: AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL;
|
|
||||||
|
|
||||||
QByteArray audioBuffer(numNetworkBytes, 0); // silent
|
QByteArray audioBuffer(numNetworkBytes, 0); // silent
|
||||||
handleAudioInput(audioBuffer);
|
handleAudioInput(audioBuffer);
|
||||||
|
@ -1484,8 +1436,7 @@ void AudioClient::prepareLocalAudioInjectors(std::unique_ptr<Lock> localAudioLoc
|
||||||
int bufferCapacity = _localInjectorsStream.getSampleCapacity();
|
int bufferCapacity = _localInjectorsStream.getSampleCapacity();
|
||||||
int maxOutputSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * AudioConstants::STEREO;
|
int maxOutputSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * AudioConstants::STEREO;
|
||||||
if (_localToOutputResampler) {
|
if (_localToOutputResampler) {
|
||||||
maxOutputSamples =
|
maxOutputSamples = _localToOutputResampler->getMaxOutput(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL) *
|
||||||
_localToOutputResampler->getMaxOutput(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL) *
|
|
||||||
AudioConstants::STEREO;
|
AudioConstants::STEREO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1518,8 +1469,7 @@ void AudioClient::prepareLocalAudioInjectors(std::unique_ptr<Lock> localAudioLoc
|
||||||
} else {
|
} else {
|
||||||
// write to local injectors' ring buffer
|
// write to local injectors' ring buffer
|
||||||
samples = AudioConstants::NETWORK_FRAME_SAMPLES_STEREO;
|
samples = AudioConstants::NETWORK_FRAME_SAMPLES_STEREO;
|
||||||
_localInjectorsStream.writeSamples(_localMixBuffer,
|
_localInjectorsStream.writeSamples(_localMixBuffer, AudioConstants::NETWORK_FRAME_SAMPLES_STEREO);
|
||||||
AudioConstants::NETWORK_FRAME_SAMPLES_STEREO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_localSamplesAvailable.fetch_add(samples, std::memory_order_release);
|
_localSamplesAvailable.fetch_add(samples, std::memory_order_release);
|
||||||
|
@ -1544,26 +1494,23 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) {
|
||||||
// the lock guarantees that injectorBuffer, if found, is invariant
|
// the lock guarantees that injectorBuffer, if found, is invariant
|
||||||
auto injectorBuffer = injector->getLocalBuffer();
|
auto injectorBuffer = injector->getLocalBuffer();
|
||||||
if (injectorBuffer) {
|
if (injectorBuffer) {
|
||||||
|
|
||||||
auto options = injector->getOptions();
|
auto options = injector->getOptions();
|
||||||
|
|
||||||
static const int HRTF_DATASET_INDEX = 1;
|
static const int HRTF_DATASET_INDEX = 1;
|
||||||
|
|
||||||
int numChannels = options.ambisonic ? AudioConstants::AMBISONIC : (options.stereo ? AudioConstants::STEREO : AudioConstants::MONO);
|
int numChannels = options.ambisonic ? AudioConstants::AMBISONIC
|
||||||
|
: (options.stereo ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||||
size_t bytesToRead = numChannels * AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL;
|
size_t bytesToRead = numChannels * AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL;
|
||||||
|
|
||||||
// get one frame from the injector
|
// get one frame from the injector
|
||||||
memset(_localScratchBuffer, 0, bytesToRead);
|
memset(_localScratchBuffer, 0, bytesToRead);
|
||||||
if (0 < injectorBuffer->readData((char*)_localScratchBuffer, bytesToRead)) {
|
if (0 < injectorBuffer->readData((char*)_localScratchBuffer, bytesToRead)) {
|
||||||
|
|
||||||
bool isSystemSound = !options.positionSet && !options.ambisonic;
|
bool isSystemSound = !options.positionSet && !options.ambisonic;
|
||||||
|
|
||||||
float gain = options.volume * (isSystemSound ? _systemInjectorGain : _localInjectorGain);
|
float gain = options.volume * (isSystemSound ? _systemInjectorGain : _localInjectorGain);
|
||||||
|
|
||||||
if (options.ambisonic) {
|
if (options.ambisonic) {
|
||||||
|
|
||||||
if (options.positionSet) {
|
if (options.positionSet) {
|
||||||
|
|
||||||
// distance attenuation
|
// distance attenuation
|
||||||
glm::vec3 relativePosition = options.position - _positionGetter();
|
glm::vec3 relativePosition = options.position - _positionGetter();
|
||||||
float distance = glm::max(glm::length(relativePosition), EPSILON);
|
float distance = glm::max(glm::length(relativePosition), EPSILON);
|
||||||
|
@ -1583,12 +1530,10 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) {
|
||||||
float qz = relativeOrientation.y;
|
float qz = relativeOrientation.y;
|
||||||
|
|
||||||
// spatialize into mixBuffer
|
// spatialize into mixBuffer
|
||||||
injector->getLocalFOA().render(_localScratchBuffer, mixBuffer, HRTF_DATASET_INDEX,
|
injector->getLocalFOA().render(_localScratchBuffer, mixBuffer, HRTF_DATASET_INDEX, qw, qx, qy, qz, gain,
|
||||||
qw, qx, qy, qz, gain, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
|
AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
|
||||||
} else if (options.stereo) {
|
} else if (options.stereo) {
|
||||||
|
|
||||||
if (options.positionSet) {
|
if (options.positionSet) {
|
||||||
|
|
||||||
// distance attenuation
|
// distance attenuation
|
||||||
glm::vec3 relativePosition = options.position - _positionGetter();
|
glm::vec3 relativePosition = options.position - _positionGetter();
|
||||||
float distance = glm::max(glm::length(relativePosition), EPSILON);
|
float distance = glm::max(glm::length(relativePosition), EPSILON);
|
||||||
|
@ -1601,7 +1546,6 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) {
|
||||||
} else { // injector is mono
|
} else { // injector is mono
|
||||||
|
|
||||||
if (options.positionSet) {
|
if (options.positionSet) {
|
||||||
|
|
||||||
// distance attenuation
|
// distance attenuation
|
||||||
glm::vec3 relativePosition = options.position - _positionGetter();
|
glm::vec3 relativePosition = options.position - _positionGetter();
|
||||||
float distance = glm::max(glm::length(relativePosition), EPSILON);
|
float distance = glm::max(glm::length(relativePosition), EPSILON);
|
||||||
|
@ -1610,10 +1554,9 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) {
|
||||||
float azimuth = azimuthForSource(relativePosition);
|
float azimuth = azimuthForSource(relativePosition);
|
||||||
|
|
||||||
// spatialize into mixBuffer
|
// spatialize into mixBuffer
|
||||||
injector->getLocalHRTF().render(_localScratchBuffer, mixBuffer, HRTF_DATASET_INDEX,
|
injector->getLocalHRTF().render(_localScratchBuffer, mixBuffer, HRTF_DATASET_INDEX, azimuth, distance,
|
||||||
azimuth, distance, gain, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
|
gain, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// direct mix into mixBuffer
|
// direct mix into mixBuffer
|
||||||
injector->getLocalHRTF().mixMono(_localScratchBuffer, mixBuffer, gain,
|
injector->getLocalHRTF().mixMono(_localScratchBuffer, mixBuffer, gain,
|
||||||
AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
|
AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
|
||||||
|
@ -1621,14 +1564,12 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//qCDebug(audioclient) << "injector has no more data, marking finished for removal";
|
//qCDebug(audioclient) << "injector has no more data, marking finished for removal";
|
||||||
injector->finishLocalInjection();
|
injector->finishLocalInjection();
|
||||||
injectorsToRemove.append(injector);
|
injectorsToRemove.append(injector);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//qCDebug(audioclient) << "injector has no local buffer, marking as finished for removal";
|
//qCDebug(audioclient) << "injector has no local buffer, marking as finished for removal";
|
||||||
injector->finishLocalInjection();
|
injector->finishLocalInjection();
|
||||||
injectorsToRemove.append(injector);
|
injectorsToRemove.append(injector);
|
||||||
|
@ -1647,7 +1588,6 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::processReceivedSamples(const QByteArray& decodedBuffer, QByteArray& outputBuffer) {
|
void AudioClient::processReceivedSamples(const QByteArray& decodedBuffer, QByteArray& outputBuffer) {
|
||||||
|
|
||||||
const int16_t* decodedSamples = reinterpret_cast<const int16_t*>(decodedBuffer.data());
|
const int16_t* decodedSamples = reinterpret_cast<const int16_t*>(decodedBuffer.data());
|
||||||
assert(decodedBuffer.size() == AudioConstants::NETWORK_FRAME_BYTES_STEREO);
|
assert(decodedBuffer.size() == AudioConstants::NETWORK_FRAME_BYTES_STEREO);
|
||||||
|
|
||||||
|
@ -1736,7 +1676,7 @@ void AudioClient::setAcousticEchoCancellation(bool enable, bool emitSignal) {
|
||||||
|
|
||||||
bool AudioClient::setIsStereoInput(bool isStereoInput) {
|
bool AudioClient::setIsStereoInput(bool isStereoInput) {
|
||||||
bool stereoInputChanged = false;
|
bool stereoInputChanged = false;
|
||||||
if (isStereoInput != _isStereoInput && _inputDeviceInfo.supportedChannelCounts().contains(2)) {
|
if (isStereoInput != _isStereoInput && _inputDeviceInfo.getDevice().supportedChannelCounts().contains(2)) {
|
||||||
_isStereoInput = isStereoInput;
|
_isStereoInput = isStereoInput;
|
||||||
stereoInputChanged = true;
|
stereoInputChanged = true;
|
||||||
|
|
||||||
|
@ -1751,12 +1691,13 @@ bool AudioClient::setIsStereoInput(bool isStereoInput) {
|
||||||
if (_encoder) {
|
if (_encoder) {
|
||||||
_codec->releaseEncoder(_encoder);
|
_codec->releaseEncoder(_encoder);
|
||||||
}
|
}
|
||||||
_encoder = _codec->createEncoder(AudioConstants::SAMPLE_RATE, _isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
_encoder = _codec->createEncoder(AudioConstants::SAMPLE_RATE,
|
||||||
|
_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||||
}
|
}
|
||||||
qCDebug(audioclient) << "Reset Codec:" << _selectedCodecName << "isStereoInput:" << _isStereoInput;
|
qCDebug(audioclient) << "Reset Codec:" << _selectedCodecName << "isStereoInput:" << _isStereoInput;
|
||||||
|
|
||||||
// restart the input device
|
// restart the input device
|
||||||
switchInputToAudioDevice(_inputDeviceInfo);
|
switchInputToAudioDevice(_inputDeviceInfo.getDevice());
|
||||||
|
|
||||||
emit isStereoInputChanged(_isStereoInput);
|
emit isStereoInputChanged(_isStereoInput);
|
||||||
}
|
}
|
||||||
|
@ -1791,7 +1732,6 @@ int AudioClient::getNumLocalInjectors() {
|
||||||
Lock lock(_injectorsMutex);
|
Lock lock(_injectorsMutex);
|
||||||
return _activeLocalAudioInjectors.size();
|
return _activeLocalAudioInjectors.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::outputFormatChanged() {
|
void AudioClient::outputFormatChanged() {
|
||||||
_outputFrameSize = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * OUTPUT_CHANNEL_COUNT * _outputFormat.sampleRate()) /
|
_outputFrameSize = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * OUTPUT_CHANNEL_COUNT * _outputFormat.sampleRate()) /
|
||||||
_desiredOutputFormat.sampleRate();
|
_desiredOutputFormat.sampleRate();
|
||||||
|
@ -1823,7 +1763,7 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInf
|
||||||
_audioInput = NULL;
|
_audioInput = NULL;
|
||||||
_numInputCallbackBytes = 0;
|
_numInputCallbackBytes = 0;
|
||||||
|
|
||||||
_inputDeviceInfo = QAudioDeviceInfo();
|
_inputDeviceInfo = HifiAudioDeviceInfo(); //QAudioDeviceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dummyAudioInput) {
|
if (_dummyAudioInput) {
|
||||||
|
@ -1856,23 +1796,24 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInf
|
||||||
|
|
||||||
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.";
|
||||||
_inputDeviceInfo = inputDeviceInfo;
|
_inputDeviceInfo = HifiAudioDeviceInfo();
|
||||||
emit deviceChanged(QAudio::AudioInput, inputDeviceInfo);
|
_inputDeviceInfo.setDevice(inputDeviceInfo);
|
||||||
|
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;
|
||||||
|
|
||||||
// we've got the best we can get for input
|
// we've got the best we can get for input
|
||||||
// if required, setup a resampler for this input to our desired network format
|
// if required, setup a resampler for this input to our desired network format
|
||||||
if (_inputFormat != _desiredInputFormat
|
if (_inputFormat != _desiredInputFormat && _inputFormat.sampleRate() != _desiredInputFormat.sampleRate()) {
|
||||||
&& _inputFormat.sampleRate() != _desiredInputFormat.sampleRate()) {
|
|
||||||
qCDebug(audioclient) << "Attemping to create a resampler for input format to network format.";
|
qCDebug(audioclient) << "Attemping to create a resampler for input format to network format.";
|
||||||
|
|
||||||
assert(_inputFormat.sampleSize() == 16);
|
assert(_inputFormat.sampleSize() == 16);
|
||||||
assert(_desiredInputFormat.sampleSize() == 16);
|
assert(_desiredInputFormat.sampleSize() == 16);
|
||||||
int channelCount = (_inputFormat.channelCount() == 2 && _desiredInputFormat.channelCount() == 2) ? 2 : 1;
|
int channelCount = (_inputFormat.channelCount() == 2 && _desiredInputFormat.channelCount() == 2) ? 2 : 1;
|
||||||
|
|
||||||
_inputToNetworkResampler = new AudioSRC(_inputFormat.sampleRate(), _desiredInputFormat.sampleRate(), channelCount);
|
_inputToNetworkResampler =
|
||||||
|
new AudioSRC(_inputFormat.sampleRate(), _desiredInputFormat.sampleRate(), channelCount);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qCDebug(audioclient) << "No resampling required for audio input to match desired network format.";
|
qCDebug(audioclient) << "No resampling required for audio input to match desired network format.";
|
||||||
|
@ -1919,7 +1860,7 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo inputDeviceInf
|
||||||
// This enables clients without a mic to still receive an audio stream from the mixer.
|
// This enables clients without a mic to still receive an audio stream from the mixer.
|
||||||
if (!_audioInput) {
|
if (!_audioInput) {
|
||||||
qCDebug(audioclient) << "Audio input device is not available, using dummy input.";
|
qCDebug(audioclient) << "Audio input device is not available, using dummy input.";
|
||||||
_inputDeviceInfo = QAudioDeviceInfo();
|
_inputDeviceInfo.setDevice(QAudioDeviceInfo());
|
||||||
emit deviceChanged(QAudio::AudioInput, _inputDeviceInfo);
|
emit deviceChanged(QAudio::AudioInput, _inputDeviceInfo);
|
||||||
|
|
||||||
_inputFormat = _desiredInputFormat;
|
_inputFormat = _desiredInputFormat;
|
||||||
|
@ -2014,8 +1955,8 @@ void AudioClient::outputNotify() {
|
||||||
int newOutputBufferSizeFrames = setOutputBufferSize(oldOutputBufferSizeFrames + 1, false);
|
int newOutputBufferSizeFrames = setOutputBufferSize(oldOutputBufferSizeFrames + 1, false);
|
||||||
|
|
||||||
if (newOutputBufferSizeFrames > oldOutputBufferSizeFrames) {
|
if (newOutputBufferSizeFrames > oldOutputBufferSizeFrames) {
|
||||||
qCDebug(audioclient,
|
qCDebug(audioclient, "Starve threshold surpassed (%d starves in %d ms)", _outputStarveDetectionCount,
|
||||||
"Starve threshold surpassed (%d starves in %d ms)", _outputStarveDetectionCount, dt);
|
dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
_outputStarveDetectionStartTimeMsec = now;
|
_outputStarveDetectionStartTimeMsec = now;
|
||||||
|
@ -2029,7 +1970,8 @@ void AudioClient::outputNotify() {
|
||||||
bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceInfo, bool isShutdownRequest) {
|
bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceInfo, bool isShutdownRequest) {
|
||||||
Q_ASSERT_X(QThread::currentThread() == thread(), Q_FUNC_INFO, "Function invoked on wrong thread");
|
Q_ASSERT_X(QThread::currentThread() == thread(), Q_FUNC_INFO, "Function invoked on wrong thread");
|
||||||
|
|
||||||
qCDebug(audioclient) << "AudioClient::switchOutputToAudioDevice() outputDeviceInfo: [" << outputDeviceInfo.deviceName() << "]";
|
qCDebug(audioclient) << "AudioClient::switchOutputToAudioDevice() outputDeviceInfo: [" << outputDeviceInfo.deviceName()
|
||||||
|
<< "]";
|
||||||
bool supportedFormat = false;
|
bool supportedFormat = false;
|
||||||
|
|
||||||
// NOTE: device start() uses the Qt internal device list
|
// NOTE: device start() uses the Qt internal device list
|
||||||
|
@ -2062,7 +2004,9 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceI
|
||||||
delete[] _localOutputMixBuffer;
|
delete[] _localOutputMixBuffer;
|
||||||
_localOutputMixBuffer = NULL;
|
_localOutputMixBuffer = NULL;
|
||||||
|
|
||||||
_outputDeviceInfo = QAudioDeviceInfo();
|
//ctor call needed?
|
||||||
|
_outputDeviceInfo = HifiAudioDeviceInfo();
|
||||||
|
_outputDeviceInfo.setDevice(QAudioDeviceInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanup any resamplers
|
// cleanup any resamplers
|
||||||
|
@ -2088,23 +2032,24 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceI
|
||||||
|
|
||||||
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.";
|
||||||
_outputDeviceInfo = outputDeviceInfo;
|
_outputDeviceInfo.setDevice(outputDeviceInfo);
|
||||||
emit deviceChanged(QAudio::AudioOutput, outputDeviceInfo);
|
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;
|
||||||
|
|
||||||
// we've got the best we can get for input
|
// we've got the best we can get for input
|
||||||
// if required, setup a resampler for this input to our desired network format
|
// if required, setup a resampler for this input to our desired network format
|
||||||
if (_desiredOutputFormat != _outputFormat
|
if (_desiredOutputFormat != _outputFormat && _desiredOutputFormat.sampleRate() != _outputFormat.sampleRate()) {
|
||||||
&& _desiredOutputFormat.sampleRate() != _outputFormat.sampleRate()) {
|
|
||||||
qCDebug(audioclient) << "Attemping to create a resampler for network format to output format.";
|
qCDebug(audioclient) << "Attemping to create a resampler for network format to output format.";
|
||||||
|
|
||||||
assert(_desiredOutputFormat.sampleSize() == 16);
|
assert(_desiredOutputFormat.sampleSize() == 16);
|
||||||
assert(_outputFormat.sampleSize() == 16);
|
assert(_outputFormat.sampleSize() == 16);
|
||||||
|
|
||||||
_networkToOutputResampler = new AudioSRC(_desiredOutputFormat.sampleRate(), _outputFormat.sampleRate(), OUTPUT_CHANNEL_COUNT);
|
_networkToOutputResampler =
|
||||||
_localToOutputResampler = new AudioSRC(_desiredOutputFormat.sampleRate(), _outputFormat.sampleRate(), OUTPUT_CHANNEL_COUNT);
|
new AudioSRC(_desiredOutputFormat.sampleRate(), _outputFormat.sampleRate(), OUTPUT_CHANNEL_COUNT);
|
||||||
|
_localToOutputResampler =
|
||||||
|
new AudioSRC(_desiredOutputFormat.sampleRate(), _outputFormat.sampleRate(), OUTPUT_CHANNEL_COUNT);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qCDebug(audioclient) << "No resampling required for network output to match actual output format.";
|
qCDebug(audioclient) << "No resampling required for network output to match actual output format.";
|
||||||
|
@ -2116,7 +2061,9 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceI
|
||||||
_audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
_audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this);
|
||||||
|
|
||||||
int deviceChannelCount = _outputFormat.channelCount();
|
int deviceChannelCount = _outputFormat.channelCount();
|
||||||
int frameSize = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * deviceChannelCount * _outputFormat.sampleRate()) / _desiredOutputFormat.sampleRate();
|
int frameSize =
|
||||||
|
(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * deviceChannelCount * _outputFormat.sampleRate()) /
|
||||||
|
_desiredOutputFormat.sampleRate();
|
||||||
int requestedSize = _sessionOutputBufferSizeFrames * frameSize * AudioConstants::SAMPLE_SIZE;
|
int requestedSize = _sessionOutputBufferSizeFrames * frameSize * AudioConstants::SAMPLE_SIZE;
|
||||||
_audioOutput->setBufferSize(requestedSize);
|
_audioOutput->setBufferSize(requestedSize);
|
||||||
|
|
||||||
|
@ -2137,7 +2084,9 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo outputDeviceI
|
||||||
_outputScratchBuffer = new int16_t[_outputPeriod];
|
_outputScratchBuffer = new int16_t[_outputPeriod];
|
||||||
|
|
||||||
// size local output mix buffer based on resampled network frame size
|
// size local output mix buffer based on resampled network frame size
|
||||||
int networkPeriod = _localToOutputResampler ? _localToOutputResampler->getMaxOutput(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO) : AudioConstants::NETWORK_FRAME_SAMPLES_STEREO;
|
int networkPeriod = _localToOutputResampler
|
||||||
|
? _localToOutputResampler->getMaxOutput(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO)
|
||||||
|
: AudioConstants::NETWORK_FRAME_SAMPLES_STEREO;
|
||||||
_localOutputMixBuffer = new float[networkPeriod];
|
_localOutputMixBuffer = new float[networkPeriod];
|
||||||
|
|
||||||
// local period should be at least twice the output period,
|
// local period should be at least twice the output period,
|
||||||
|
@ -2180,7 +2129,8 @@ int AudioClient::setOutputBufferSize(int numFrames, bool persist) {
|
||||||
qCDebug(audioclient) << __FUNCTION__ << "numFrames:" << numFrames << "persist:" << persist;
|
qCDebug(audioclient) << __FUNCTION__ << "numFrames:" << numFrames << "persist:" << persist;
|
||||||
|
|
||||||
numFrames = std::min(std::max(numFrames, MIN_BUFFER_FRAMES), MAX_BUFFER_FRAMES);
|
numFrames = std::min(std::max(numFrames, MIN_BUFFER_FRAMES), MAX_BUFFER_FRAMES);
|
||||||
qCDebug(audioclient) << __FUNCTION__ << "clamped numFrames:" << numFrames << "_sessionOutputBufferSizeFrames:" << _sessionOutputBufferSizeFrames;
|
qCDebug(audioclient) << __FUNCTION__ << "clamped numFrames:" << numFrames
|
||||||
|
<< "_sessionOutputBufferSizeFrames:" << _sessionOutputBufferSizeFrames;
|
||||||
|
|
||||||
if (numFrames != _sessionOutputBufferSizeFrames) {
|
if (numFrames != _sessionOutputBufferSizeFrames) {
|
||||||
qCInfo(audioclient, "Audio output buffer set to %d frames", numFrames);
|
qCInfo(audioclient, "Audio output buffer set to %d frames", numFrames);
|
||||||
|
@ -2211,10 +2161,10 @@ const float AudioClient::CALLBACK_ACCELERATOR_RATIO = 2.0f;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int AudioClient::calculateNumberOfInputCallbackBytes(const QAudioFormat& format) const {
|
int AudioClient::calculateNumberOfInputCallbackBytes(const QAudioFormat& format) const {
|
||||||
int numInputCallbackBytes = (int)(((AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL
|
int numInputCallbackBytes = (int)(((AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL * format.channelCount() *
|
||||||
* format.channelCount()
|
((float)format.sampleRate() / AudioConstants::SAMPLE_RATE)) /
|
||||||
* ((float) format.sampleRate() / AudioConstants::SAMPLE_RATE))
|
CALLBACK_ACCELERATOR_RATIO) +
|
||||||
/ CALLBACK_ACCELERATOR_RATIO) + 0.5f);
|
0.5f);
|
||||||
|
|
||||||
return numInputCallbackBytes;
|
return numInputCallbackBytes;
|
||||||
}
|
}
|
||||||
|
@ -2236,7 +2186,6 @@ float AudioClient::azimuthForSource(const glm::vec3& relativePosition) {
|
||||||
|
|
||||||
float rotatedSourcePositionLength2 = glm::length2(rotatedSourcePosition);
|
float rotatedSourcePositionLength2 = glm::length2(rotatedSourcePosition);
|
||||||
if (rotatedSourcePositionLength2 > SOURCE_DISTANCE_THRESHOLD) {
|
if (rotatedSourcePositionLength2 > SOURCE_DISTANCE_THRESHOLD) {
|
||||||
|
|
||||||
// produce an oriented angle about the y-axis
|
// produce an oriented angle about the y-axis
|
||||||
glm::vec3 direction = rotatedSourcePosition * (1.0f / fastSqrtf(rotatedSourcePositionLength2));
|
glm::vec3 direction = rotatedSourcePosition * (1.0f / fastSqrtf(rotatedSourcePositionLength2));
|
||||||
float angle = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward"
|
float angle = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward"
|
||||||
|
@ -2249,7 +2198,6 @@ float AudioClient::azimuthForSource(const glm::vec3& relativePosition) {
|
||||||
}
|
}
|
||||||
|
|
||||||
float AudioClient::gainForSource(float distance, float volume) {
|
float AudioClient::gainForSource(float distance, float volume) {
|
||||||
|
|
||||||
// attenuation = -6dB * log2(distance)
|
// attenuation = -6dB * log2(distance)
|
||||||
// reference attenuation of 0dB at distance = ATTN_DISTANCE_REF
|
// reference attenuation of 0dB at distance = ATTN_DISTANCE_REF
|
||||||
float d = (1.0f / ATTN_DISTANCE_REF) * std::max(distance, HRTF_NEARFIELD_MIN);
|
float d = (1.0f / ATTN_DISTANCE_REF) * std::max(distance, HRTF_NEARFIELD_MIN);
|
||||||
|
@ -2260,7 +2208,6 @@ float AudioClient::gainForSource(float distance, float volume) {
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 AudioClient::AudioOutputIODevice::readData(char* data, qint64 maxSize) {
|
qint64 AudioClient::AudioOutputIODevice::readData(char* data, qint64 maxSize) {
|
||||||
|
|
||||||
// lock-free wait for initialization to avoid races
|
// lock-free wait for initialization to avoid races
|
||||||
if (!_audio->_audioOutputInitialized.load(std::memory_order_acquire)) {
|
if (!_audio->_audioOutputInitialized.load(std::memory_order_acquire)) {
|
||||||
memset(data, 0, maxSize);
|
memset(data, 0, maxSize);
|
||||||
|
@ -2279,7 +2226,8 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
|
||||||
int samplesRequested = maxSamplesRequested;
|
int samplesRequested = maxSamplesRequested;
|
||||||
int networkSamplesPopped;
|
int networkSamplesPopped;
|
||||||
if ((networkSamplesPopped = _receivedAudioStream.popSamples(samplesRequested, false)) > 0) {
|
if ((networkSamplesPopped = _receivedAudioStream.popSamples(samplesRequested, false)) > 0) {
|
||||||
qCDebug(audiostream, "Read %d samples from buffer (%d available, %d requested)", networkSamplesPopped, _receivedAudioStream.getSamplesAvailable(), samplesRequested);
|
qCDebug(audiostream, "Read %d samples from buffer (%d available, %d requested)", networkSamplesPopped,
|
||||||
|
_receivedAudioStream.getSamplesAvailable(), samplesRequested);
|
||||||
AudioRingBuffer::ConstIterator lastPopOutput = _receivedAudioStream.getLastPopOutput();
|
AudioRingBuffer::ConstIterator lastPopOutput = _receivedAudioStream.getLastPopOutput();
|
||||||
lastPopOutput.readSamples(scratchBuffer, networkSamplesPopped);
|
lastPopOutput.readSamples(scratchBuffer, networkSamplesPopped);
|
||||||
for (int i = 0; i < networkSamplesPopped; i++) {
|
for (int i = 0; i < networkSamplesPopped; i++) {
|
||||||
|
@ -2311,14 +2259,13 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
|
||||||
samplesRequested = std::min(samplesRequested, samplesAvailable);
|
samplesRequested = std::min(samplesRequested, samplesAvailable);
|
||||||
if ((injectorSamplesPopped = _localInjectorsStream.appendSamples(mixBuffer, samplesRequested, append)) > 0) {
|
if ((injectorSamplesPopped = _localInjectorsStream.appendSamples(mixBuffer, samplesRequested, append)) > 0) {
|
||||||
_audio->_localSamplesAvailable.fetch_sub(injectorSamplesPopped, std::memory_order_release);
|
_audio->_localSamplesAvailable.fetch_sub(injectorSamplesPopped, std::memory_order_release);
|
||||||
qCDebug(audiostream, "Read %d samples from injectors (%d available, %d requested)", injectorSamplesPopped, _localInjectorsStream.samplesAvailable(), samplesRequested);
|
qCDebug(audiostream, "Read %d samples from injectors (%d available, %d requested)", injectorSamplesPopped,
|
||||||
|
_localInjectorsStream.samplesAvailable(), samplesRequested);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare injectors for the next callback
|
// prepare injectors for the next callback
|
||||||
QtConcurrent::run(QThreadPool::globalInstance(), [this] {
|
QtConcurrent::run(QThreadPool::globalInstance(), [this] { _audio->prepareLocalAudioInjectors(); });
|
||||||
_audio->prepareLocalAudioInjectors();
|
|
||||||
});
|
|
||||||
|
|
||||||
int samplesPopped = std::max(networkSamplesPopped, injectorSamplesPopped);
|
int samplesPopped = std::max(networkSamplesPopped, injectorSamplesPopped);
|
||||||
if (samplesPopped == 0) {
|
if (samplesPopped == 0) {
|
||||||
|
@ -2398,7 +2345,6 @@ void AudioClient::loadSettings() {
|
||||||
for (auto& plugin : codecPlugins) {
|
for (auto& plugin : codecPlugins) {
|
||||||
qCDebug(audioclient) << "Codec available:" << plugin->getName();
|
qCDebug(audioclient) << "Codec available:" << plugin->getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::saveSettings() {
|
void AudioClient::saveSettings() {
|
||||||
|
@ -2411,9 +2357,9 @@ void AudioClient::setAvatarBoundingBoxParameters(glm::vec3 corner, glm::vec3 sca
|
||||||
avatarBoundingBoxScale = scale;
|
avatarBoundingBoxScale = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioClient::startThread() {
|
void AudioClient::startThread() {
|
||||||
moveToNewNamedThread(this, "Audio Thread", [this] { start(); }, QThread::TimeCriticalPriority);
|
moveToNewNamedThread(
|
||||||
|
this, "Audio Thread", [this] { start(); }, QThread::TimeCriticalPriority);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::setInputVolume(float volume, bool emitSignal) {
|
void AudioClient::setInputVolume(float volume, bool emitSignal) {
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
|
|
||||||
#include "AudioIOStats.h"
|
#include "AudioIOStats.h"
|
||||||
#include "AudioFileWav.h"
|
#include "AudioFileWav.h"
|
||||||
|
#include "HifiAudioDeviceInfo.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
|
@ -79,11 +80,14 @@ class QIODevice;
|
||||||
class Transform;
|
class Transform;
|
||||||
class NLPacket;
|
class NLPacket;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AudioClient : public AbstractAudioInterface, public Dependency {
|
class AudioClient : public AbstractAudioInterface, public Dependency {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
SINGLETON_DEPENDENCY
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
using LocalInjectorsStream = AudioMixRingBuffer;
|
using LocalInjectorsStream = AudioMixRingBuffer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const int MIN_BUFFER_FRAMES;
|
static const int MIN_BUFFER_FRAMES;
|
||||||
static const int MAX_BUFFER_FRAMES;
|
static const int MAX_BUFFER_FRAMES;
|
||||||
|
@ -96,15 +100,21 @@ public:
|
||||||
|
|
||||||
class AudioOutputIODevice : public QIODevice {
|
class AudioOutputIODevice : public QIODevice {
|
||||||
public:
|
public:
|
||||||
AudioOutputIODevice(LocalInjectorsStream& localInjectorsStream, MixedProcessedAudioStream& receivedAudioStream,
|
AudioOutputIODevice(LocalInjectorsStream& localInjectorsStream,
|
||||||
|
MixedProcessedAudioStream& receivedAudioStream,
|
||||||
AudioClient* audio) :
|
AudioClient* audio) :
|
||||||
_localInjectorsStream(localInjectorsStream), _receivedAudioStream(receivedAudioStream),
|
_localInjectorsStream(localInjectorsStream),
|
||||||
_audio(audio), _unfulfilledReads(0) {}
|
_receivedAudioStream(receivedAudioStream), _audio(audio), _unfulfilledReads(0) {}
|
||||||
|
|
||||||
void start() { open(QIODevice::ReadOnly | QIODevice::Unbuffered); }
|
void start() { open(QIODevice::ReadOnly | QIODevice::Unbuffered); }
|
||||||
qint64 readData(char* data, qint64 maxSize) override;
|
qint64 readData(char* data, qint64 maxSize) override;
|
||||||
qint64 writeData(const char* data, qint64 maxSize) override { return 0; }
|
qint64 writeData(const char* data, qint64 maxSize) override { return 0; }
|
||||||
int getRecentUnfulfilledReads() { int unfulfilledReads = _unfulfilledReads; _unfulfilledReads = 0; return unfulfilledReads; }
|
int getRecentUnfulfilledReads() {
|
||||||
|
int unfulfilledReads = _unfulfilledReads;
|
||||||
|
_unfulfilledReads = 0;
|
||||||
|
return unfulfilledReads;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LocalInjectorsStream& _localInjectorsStream;
|
LocalInjectorsStream& _localInjectorsStream;
|
||||||
MixedProcessedAudioStream& _receivedAudioStream;
|
MixedProcessedAudioStream& _receivedAudioStream;
|
||||||
|
@ -155,8 +165,8 @@ public:
|
||||||
|
|
||||||
bool outputLocalInjector(const AudioInjectorPointer& injector) override;
|
bool outputLocalInjector(const AudioInjectorPointer& injector) override;
|
||||||
|
|
||||||
QAudioDeviceInfo getActiveAudioDevice(QAudio::Mode mode) const;
|
HifiAudioDeviceInfo getActiveAudioDevice(QAudio::Mode mode) const;
|
||||||
QList<QAudioDeviceInfo> getAudioDevices(QAudio::Mode mode) const;
|
QList<HifiAudioDeviceInfo> getAudioDevices(QAudio::Mode mode) const;
|
||||||
|
|
||||||
void enablePeakValues(bool enable) { _enablePeakValues = enable; }
|
void enablePeakValues(bool enable) { _enablePeakValues = enable; }
|
||||||
bool peakValuesAvailable() const;
|
bool peakValuesAvailable() const;
|
||||||
|
@ -269,10 +279,10 @@ signals:
|
||||||
void noiseGateOpened();
|
void noiseGateOpened();
|
||||||
void noiseGateClosed();
|
void noiseGateClosed();
|
||||||
|
|
||||||
void changeDevice(const QAudioDeviceInfo& outputDeviceInfo);
|
void changeDevice(const HifiAudioDeviceInfo& outputDeviceInfo);
|
||||||
|
|
||||||
void deviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& device);
|
void deviceChanged(QAudio::Mode mode, const HifiAudioDeviceInfo& device);
|
||||||
void devicesChanged(QAudio::Mode mode, const QList<QAudioDeviceInfo>& devices);
|
void devicesChanged(QAudio::Mode mode, const QList<HifiAudioDeviceInfo>& devices);
|
||||||
void peakValueListChanged(const QList<float> peakValueList);
|
void peakValueListChanged(const QList<float> peakValueList);
|
||||||
|
|
||||||
void receivedFirstPacket();
|
void receivedFirstPacket();
|
||||||
|
@ -459,11 +469,17 @@ private:
|
||||||
glm::vec3 avatarBoundingBoxCorner;
|
glm::vec3 avatarBoundingBoxCorner;
|
||||||
glm::vec3 avatarBoundingBoxScale;
|
glm::vec3 avatarBoundingBoxScale;
|
||||||
|
|
||||||
QAudioDeviceInfo _inputDeviceInfo;
|
HifiAudioDeviceInfo _inputDeviceInfo;
|
||||||
QAudioDeviceInfo _outputDeviceInfo;
|
HifiAudioDeviceInfo _outputDeviceInfo;
|
||||||
|
|
||||||
QList<QAudioDeviceInfo> _inputDevices;
|
QList<HifiAudioDeviceInfo> _inputDevices;
|
||||||
QList<QAudioDeviceInfo> _outputDevices;
|
QList<HifiAudioDeviceInfo> _outputDevices;
|
||||||
|
|
||||||
|
//QAudioDeviceInfo _inputDeviceInfo;
|
||||||
|
// QAudioDeviceInfo _outputDeviceInfo;
|
||||||
|
|
||||||
|
// QList<QAudioDeviceInfo> _inputDevices;
|
||||||
|
/// QList<QAudioDeviceInfo> _outputDevices;
|
||||||
|
|
||||||
AudioFileWav _audioFileWav;
|
AudioFileWav _audioFileWav;
|
||||||
|
|
||||||
|
@ -497,5 +513,4 @@ private:
|
||||||
bool _isRecording{ false };
|
bool _isRecording{ false };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // hifi_AudioClient_h
|
#endif // hifi_AudioClient_h
|
||||||
|
|
|
@ -356,7 +356,7 @@ void OffscreenQmlSurface::onRootCreated() {
|
||||||
getSurfaceContext()->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow()));
|
getSurfaceContext()->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow()));
|
||||||
|
|
||||||
// Connect with the audio client and listen for audio device changes
|
// Connect with the audio client and listen for audio device changes
|
||||||
connect(DependencyManager::get<AudioClient>().data(), &AudioClient::deviceChanged, this, [this](QAudio::Mode mode, const QAudioDeviceInfo& device) {
|
connect(DependencyManager::get<AudioClient>().data(), &AudioClient::deviceChanged, this, [this](QAudio::Mode mode, const HifiAudioDeviceInfo& device) {
|
||||||
if (mode == QAudio::Mode::AudioOutput) {
|
if (mode == QAudio::Mode::AudioOutput) {
|
||||||
QMetaObject::invokeMethod(this, "changeAudioOutputDevice", Qt::QueuedConnection, Q_ARG(QString, device.deviceName()));
|
QMetaObject::invokeMethod(this, "changeAudioOutputDevice", Qt::QueuedConnection, Q_ARG(QString, device.deviceName()));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue