diff options
author | Yoann Lopes <yoann.lopes@theqtcompany.com> | 2015-03-13 16:25:15 +0100 |
---|---|---|
committer | Yoann Lopes <yoann.lopes@theqtcompany.com> | 2015-04-14 14:42:21 +0000 |
commit | 07606dde9a1f6b89f582ff8f1fbc53e2d4eb2c22 (patch) | |
tree | fe9d60b38e6f4232619ba44dd8f15dd1eada444a /src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp | |
parent | b529cf242a596b47ebb0fc659e63439fa6e7cb79 (diff) |
WindowsAudio: improve supported formats detection.
QAudioDeviceInfo::isFormatSupported() now tries to open the device with
that format to theck if it is supported. We were before simply checking
that its parameters were included in the list of supported values,
which might be incomplete.
In addition, since the Windows API to check device capabilities is quite
limited, we now test additional common formats and add them to the
supported formats if the device can open them.
Task-number: QTBUG-42648
Change-Id: Idd0affbd6d91d4fd027a6a4c86c2f3fe008a118f
Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
Diffstat (limited to 'src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp')
-rw-r--r-- | src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp | 200 |
1 files changed, 94 insertions, 106 deletions
diff --git a/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp b/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp index 625cf6824..24a577ed9 100644 --- a/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp +++ b/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp @@ -44,8 +44,8 @@ #include <QtCore/qt_windows.h> -#include <mmsystem.h> #include "qwindowsaudiodeviceinfo.h" +#include "qwindowsaudioutils.h" #if defined(Q_CC_MINGW) && !defined(__MINGW64_VERSION_MAJOR) struct IBaseFilter; // Needed for strmif.h from stock MinGW. @@ -166,8 +166,7 @@ QString QWindowsAudioDeviceInfo::deviceName() const QStringList QWindowsAudioDeviceInfo::supportedCodecs() { - updateLists(); - return codecz; + return QStringList() << QStringLiteral("audio/pcm"); } QList<int> QWindowsAudioDeviceInfo::supportedSampleRates() @@ -190,8 +189,7 @@ QList<int> QWindowsAudioDeviceInfo::supportedSampleSizes() QList<QAudioFormat::Endian> QWindowsAudioDeviceInfo::supportedByteOrders() { - updateLists(); - return byteOrderz; + return QList<QAudioFormat::Endian>() << QAudioFormat::LittleEndian; } QList<QAudioFormat::SampleType> QWindowsAudioDeviceInfo::supportedSampleTypes() @@ -212,118 +210,50 @@ void QWindowsAudioDeviceInfo::close() bool QWindowsAudioDeviceInfo::testSettings(const QAudioFormat& format) const { - // Set nearest to closest settings that do work. - // See if what is in settings will work (return value). - - bool failed = false; - bool match = false; - - // check codec - for( int i = 0; i < codecz.count(); i++) { - if (format.codec() == codecz.at(i)) - match = true; - } - if (!match) failed = true; - - // check channel - match = false; - if (!failed) { - for (int i = 0; i < channelz.count(); i++) { - if (format.channelCount() == channelz.at(i)) { - match = true; - break; - } - } - if (!match) - failed = true; - } - - // check sampleRate - match = false; - if (!failed) { - for (int i = 0; i < sampleRatez.count(); i++) { - if (format.sampleRate() == sampleRatez.at(i)) { - match = true; - break; - } - } - if (!match) - failed = true; - } - - // check sample size - match = false; - if (!failed) { - for( int i = 0; i < sizez.count(); i++) { - if (format.sampleSize() == sizez.at(i)) { - match = true; - break; - } - } - if (!match) - failed = true; - } - - // check byte order - match = false; - if (!failed) { - for( int i = 0; i < byteOrderz.count(); i++) { - if (format.byteOrder() == byteOrderz.at(i)) { - match = true; - break; - } - } - if (!match) - failed = true; - } - - // check sample type - match = false; - if (!failed) { - for( int i = 0; i < typez.count(); i++) { - if (format.sampleType() == typez.at(i)) { - match = true; - break; - } + WAVEFORMATEXTENSIBLE wfx; + if (qt_convertFormat(format, &wfx)) { + // query only, do not open device + if (mode == QAudio::AudioOutput) { + return (waveOutOpen(NULL, UINT_PTR(devId), &wfx.Format, NULL, NULL, + WAVE_FORMAT_QUERY) == MMSYSERR_NOERROR); + } else { // AudioInput + return (waveInOpen(NULL, UINT_PTR(devId), &wfx.Format, NULL, NULL, + WAVE_FORMAT_QUERY) == MMSYSERR_NOERROR); } - if (!match) - failed = true; } - if(!failed) { - // settings work - return true; - } return false; } void QWindowsAudioDeviceInfo::updateLists() { - // redo all lists based on current settings - bool match = false; + if (!sizez.isEmpty()) + return; + + bool hasCaps = false; DWORD fmt = 0; if(mode == QAudio::AudioOutput) { WAVEOUTCAPS woc; if (waveOutGetDevCaps(devId, &woc, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) { - match = true; + hasCaps = true; fmt = woc.dwFormats; } } else { WAVEINCAPS woc; if (waveInGetDevCaps(devId, &woc, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) { - match = true; + hasCaps = true; fmt = woc.dwFormats; } } + sizez.clear(); sampleRatez.clear(); channelz.clear(); - byteOrderz.clear(); typez.clear(); - codecz.clear(); - if(match) { + if (hasCaps) { + // Check sample size if ((fmt & WAVE_FORMAT_1M08) || (fmt & WAVE_FORMAT_1S08) || (fmt & WAVE_FORMAT_2M08) @@ -333,8 +263,7 @@ void QWindowsAudioDeviceInfo::updateLists() || (fmt & WAVE_FORMAT_48M08) || (fmt & WAVE_FORMAT_48S08) || (fmt & WAVE_FORMAT_96M08) - || (fmt & WAVE_FORMAT_96S08) - ) { + || (fmt & WAVE_FORMAT_96S08)) { sizez.append(8); } if ((fmt & WAVE_FORMAT_1M16) @@ -346,10 +275,11 @@ void QWindowsAudioDeviceInfo::updateLists() || (fmt & WAVE_FORMAT_48M16) || (fmt & WAVE_FORMAT_48S16) || (fmt & WAVE_FORMAT_96M16) - || (fmt & WAVE_FORMAT_96S16) - ) { + || (fmt & WAVE_FORMAT_96S16)) { sizez.append(16); } + + // Check sample rate if ((fmt & WAVE_FORMAT_1M08) || (fmt & WAVE_FORMAT_1S08) || (fmt & WAVE_FORMAT_1M16) @@ -380,23 +310,81 @@ void QWindowsAudioDeviceInfo::updateLists() || (fmt & WAVE_FORMAT_96S16)) { sampleRatez.append(96000); } - channelz.append(1); - channelz.append(2); - if (mode == QAudio::AudioOutput) { - channelz.append(4); - channelz.append(6); - channelz.append(8); - } - byteOrderz.append(QAudioFormat::LittleEndian); + // Check channel count + if (fmt & WAVE_FORMAT_1M08 + || fmt & WAVE_FORMAT_1M16 + || fmt & WAVE_FORMAT_2M08 + || fmt & WAVE_FORMAT_2M16 + || fmt & WAVE_FORMAT_4M08 + || fmt & WAVE_FORMAT_4M16 + || fmt & WAVE_FORMAT_48M08 + || fmt & WAVE_FORMAT_48M16 + || fmt & WAVE_FORMAT_96M08 + || fmt & WAVE_FORMAT_96M16) { + channelz.append(1); + } + if (fmt & WAVE_FORMAT_1S08 + || fmt & WAVE_FORMAT_1S16 + || fmt & WAVE_FORMAT_2S08 + || fmt & WAVE_FORMAT_2S16 + || fmt & WAVE_FORMAT_4S08 + || fmt & WAVE_FORMAT_4S16 + || fmt & WAVE_FORMAT_48S08 + || fmt & WAVE_FORMAT_48S16 + || fmt & WAVE_FORMAT_96S08 + || fmt & WAVE_FORMAT_96S16) { + channelz.append(2); + } typez.append(QAudioFormat::SignedInt); typez.append(QAudioFormat::UnSignedInt); - codecz.append(QLatin1String("audio/pcm")); + // WAVEOUTCAPS and WAVEINCAPS contains information only for the previously tested parameters. + // WaveOut and WaveInt might actually support more formats, the only way to know is to try + // opening the device with it. + QAudioFormat testFormat; + testFormat.setCodec(QStringLiteral("audio/pcm")); + testFormat.setByteOrder(QAudioFormat::LittleEndian); + testFormat.setSampleType(QAudioFormat::SignedInt); + testFormat.setChannelCount(channelz.first()); + testFormat.setSampleRate(sampleRatez.at(sampleRatez.size() / 2)); + testFormat.setSampleSize(sizez.last()); + const QAudioFormat defaultTestFormat(testFormat); + + // Check if float samples are supported + testFormat.setSampleType(QAudioFormat::Float); + testFormat.setSampleSize(32); + if (testSettings(testFormat)) + typez.append(QAudioFormat::Float); + + // Check channel counts > 2 + testFormat = defaultTestFormat; + for (int i = 3; i < 19; ++i) { // <mmreg.h> defines 18 different channels + testFormat.setChannelCount(i); + if (testSettings(testFormat)) + channelz.append(i); + } + + // Check more sample sizes + testFormat = defaultTestFormat; + QList<int> testSampleSizes = QList<int>() << 24 << 32 << 48 << 64; + Q_FOREACH (int s, testSampleSizes) { + testFormat.setSampleSize(s); + if (testSettings(testFormat)) + sizez.append(s); + } + + // Check more sample rates + testFormat = defaultTestFormat; + QList<int> testSampleRates = QList<int>() << 8000 << 16000 << 32000 << 88200 << 192000; + Q_FOREACH (int r, testSampleRates) { + testFormat.setSampleRate(r); + if (testSettings(testFormat)) + sampleRatez.append(r); + } + std::sort(sampleRatez.begin(), sampleRatez.end()); } - if (sampleRatez.count() > 0) - sampleRatez.prepend(8000); } QList<QByteArray> QWindowsAudioDeviceInfo::availableDevices(QAudio::Mode mode) |