mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-31 12:55:33 +08:00
[AFV] Select audio device based on situational need
For AFV itself, a low latency device is required (which on Windows most likely will pick WASAPI). For notifications and effects, the most compatible device is required (which on Windows will most likely fall back to QWindowsAudio).
This commit is contained in:
committed by
Mat Sutcliffe
parent
18ec101391
commit
90e87835fc
@@ -7,6 +7,10 @@
|
||||
*/
|
||||
|
||||
#include "audioutilities.h"
|
||||
#include <QAudioInput>
|
||||
#include <QAudioOutput>
|
||||
|
||||
using namespace BlackMisc::Audio;
|
||||
|
||||
namespace BlackSound
|
||||
{
|
||||
@@ -76,4 +80,98 @@ namespace BlackSound
|
||||
return output;
|
||||
}
|
||||
|
||||
QAudioDeviceInfo getLowestLatencyDevice(const CAudioDeviceInfo &device, QAudioFormat &format)
|
||||
{
|
||||
if (device.isDefault())
|
||||
{
|
||||
if (device.getType() == CAudioDeviceInfo::InputDevice) { return QAudioDeviceInfo::defaultInputDevice(); }
|
||||
else { return QAudioDeviceInfo::defaultOutputDevice(); }
|
||||
}
|
||||
|
||||
QAudio::Mode mode = device.getType() == CAudioDeviceInfo::InputDevice ? QAudio::AudioInput : QAudio::AudioOutput;
|
||||
const QList<QAudioDeviceInfo> allQtDevices = QAudioDeviceInfo::availableDevices(mode);
|
||||
|
||||
// Find the one with lowest latency.
|
||||
QList<QAudioDeviceInfo> supportedDevices;
|
||||
for (const QAudioDeviceInfo &d : allQtDevices)
|
||||
{
|
||||
if (d.deviceName() == device.getName())
|
||||
{
|
||||
if (! d.isFormatSupported(format))
|
||||
{
|
||||
// Check whether the nearest format is acceptable for our needs
|
||||
QAudioFormat nearestFormat = d.nearestFormat(format);
|
||||
if (nearestFormat.sampleRate() != format.sampleRate() ||
|
||||
nearestFormat.sampleSize() != format.sampleSize() ||
|
||||
nearestFormat.sampleType() != format.sampleType() ||
|
||||
nearestFormat.byteOrder() != format.byteOrder() ||
|
||||
nearestFormat.codec() != format.codec())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
supportedDevices.push_back(d);
|
||||
}
|
||||
}
|
||||
|
||||
if (supportedDevices.empty()) { return {}; }
|
||||
|
||||
QAudioDeviceInfo deviceWithLowestLatency = supportedDevices.at(0);
|
||||
|
||||
if (supportedDevices.size() > 1)
|
||||
{
|
||||
QAudioFormat nearestFormat = format;
|
||||
int lowestBufferSize = std::numeric_limits<int>::max();
|
||||
for (const QAudioDeviceInfo &d : supportedDevices)
|
||||
{
|
||||
int bufferSize = 0;
|
||||
if (device.getType() == CAudioDeviceInfo::InputDevice)
|
||||
{
|
||||
QAudioInput input(d, d.nearestFormat(format));
|
||||
input.start();
|
||||
input.stop();
|
||||
bufferSize = input.bufferSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
QAudioOutput output(d, d.nearestFormat(format));
|
||||
output.start();
|
||||
output.stop();
|
||||
bufferSize = output.bufferSize();
|
||||
}
|
||||
|
||||
if (bufferSize < lowestBufferSize)
|
||||
{
|
||||
deviceWithLowestLatency = d;
|
||||
nearestFormat = d.nearestFormat(format);
|
||||
lowestBufferSize = bufferSize;
|
||||
}
|
||||
}
|
||||
format = nearestFormat;
|
||||
}
|
||||
return deviceWithLowestLatency;
|
||||
}
|
||||
|
||||
QAudioDeviceInfo getHighestCompatibleOutputDevice(const CAudioDeviceInfo &device, QAudioFormat &format)
|
||||
{
|
||||
if (device.isDefault()) { return QAudioDeviceInfo::defaultOutputDevice(); }
|
||||
|
||||
const QList<QAudioDeviceInfo> allQtDevices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
|
||||
|
||||
QList<QAudioDeviceInfo> supportedDevices;
|
||||
for (const QAudioDeviceInfo &d : allQtDevices)
|
||||
{
|
||||
if (d.deviceName() == device.getName())
|
||||
{
|
||||
if (d.isFormatSupported(format))
|
||||
{
|
||||
supportedDevices.push_back(d);
|
||||
}
|
||||
}
|
||||
|
||||
if (supportedDevices.size() > 0) { return supportedDevices.at(0); }
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // ns
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
#define BLACKSOUND_AUDIOUTILITIES_H
|
||||
|
||||
#include "blacksound/blacksoundexport.h"
|
||||
#include "blackmisc/audio/audiodeviceinfo.h"
|
||||
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QByteArray>
|
||||
#include <QVector>
|
||||
|
||||
@@ -24,6 +27,10 @@ namespace BlackSound
|
||||
BLACKSOUND_EXPORT QVector<float> convertFromMonoToStereo(const QVector<float> &mono);
|
||||
BLACKSOUND_EXPORT QVector<qint16> convertFromStereoToMono(const QVector<qint16> &stereo);
|
||||
BLACKSOUND_EXPORT QVector<float> convertFromShortToFloat(const QVector<qint16> &input);
|
||||
|
||||
BLACKSOUND_EXPORT QAudioDeviceInfo getLowestLatencyDevice(const BlackMisc::Audio::CAudioDeviceInfo &device, QAudioFormat &format);
|
||||
BLACKSOUND_EXPORT QAudioDeviceInfo getHighestCompatibleOutputDevice(const BlackMisc::Audio::CAudioDeviceInfo &device, QAudioFormat &format);
|
||||
|
||||
//! @}
|
||||
} // ns
|
||||
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
|
||||
#include "threadedtonepairplayer.h"
|
||||
#include "blackmisc/logmessage.h"
|
||||
#include "blacksound/audioutilities.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
using namespace BlackMisc;
|
||||
using namespace BlackMisc::Audio;
|
||||
using namespace BlackSound;
|
||||
|
||||
namespace BlackSound
|
||||
{
|
||||
@@ -38,36 +40,14 @@ namespace BlackSound
|
||||
{
|
||||
CLogMessage(this).info(u"CThreadedTonePairPlayer for device '%1'") << m_deviceInfo.getName();
|
||||
|
||||
QAudioDeviceInfo selectedDevice;
|
||||
if (m_deviceInfo.isDefault())
|
||||
{
|
||||
selectedDevice = QAudioDeviceInfo::defaultOutputDevice();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Add smart algorithm to find the device with exactly supports the audio format below
|
||||
const QList<QAudioDeviceInfo> outputDevices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
|
||||
for (const QAudioDeviceInfo &d : outputDevices)
|
||||
{
|
||||
if (d.deviceName() == m_deviceInfo.getName())
|
||||
{
|
||||
selectedDevice = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_audioFormat.setSampleRate(44100);
|
||||
m_audioFormat.setChannelCount(1);
|
||||
m_audioFormat.setSampleSize(16); // 8 or 16 works
|
||||
m_audioFormat.setCodec("audio/pcm");
|
||||
m_audioFormat.setByteOrder(QAudioFormat::LittleEndian);
|
||||
m_audioFormat.setSampleType(QAudioFormat::SignedInt);
|
||||
|
||||
QAudioFormat format;
|
||||
format.setSampleRate(44100);
|
||||
format.setChannelCount(1);
|
||||
format.setSampleSize(16); // 8 or 16 works
|
||||
format.setCodec("audio/pcm");
|
||||
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||
format.setSampleType(QAudioFormat::SignedInt);
|
||||
if (!selectedDevice.isFormatSupported(format))
|
||||
{
|
||||
format = selectedDevice.nearestFormat(format);
|
||||
}
|
||||
m_audioFormat = format;
|
||||
QAudioDeviceInfo selectedDevice = getHighestCompatibleOutputDevice(m_deviceInfo, m_audioFormat);
|
||||
m_audioOutput = new QAudioOutput(selectedDevice, m_audioFormat, this);
|
||||
connect(m_audioOutput, &QAudioOutput::stateChanged, this, &CThreadedTonePairPlayer::handleStateChanged);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user