summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@theqtcompany.com>2015-03-13 16:25:15 +0100
committerYoann Lopes <yoann.lopes@theqtcompany.com>2015-04-14 14:42:21 +0000
commit07606dde9a1f6b89f582ff8f1fbc53e2d4eb2c22 (patch)
treefe9d60b38e6f4232619ba44dd8f15dd1eada444a
parentb529cf242a596b47ebb0fc659e63439fa6e7cb79 (diff)
downloadqtmultimedia-07606dde9a1f6b89f582ff8f1fbc53e2d4eb2c22.tar.gz
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>
-rw-r--r--src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp200
-rw-r--r--src/plugins/windowsaudio/qwindowsaudiodeviceinfo.h6
-rw-r--r--src/plugins/windowsaudio/qwindowsaudioinput.cpp21
-rw-r--r--src/plugins/windowsaudio/qwindowsaudioinput.h5
-rw-r--r--src/plugins/windowsaudio/qwindowsaudiooutput.cpp119
-rw-r--r--src/plugins/windowsaudio/qwindowsaudiooutput.h5
-rw-r--r--src/plugins/windowsaudio/qwindowsaudioutils.cpp111
-rw-r--r--src/plugins/windowsaudio/qwindowsaudioutils.h67
-rw-r--r--src/plugins/windowsaudio/windowsaudio.pro6
9 files changed, 293 insertions, 247 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)
diff --git a/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.h b/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.h
index 3b274fd8d..4a2de555f 100644
--- a/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.h
+++ b/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.h
@@ -57,7 +57,6 @@
QT_BEGIN_NAMESPACE
-
const unsigned int MAX_SAMPLE_RATES = 5;
const unsigned int SAMPLE_RATES[] = { 8000, 11025, 22050, 44100, 48000 };
@@ -91,15 +90,14 @@ private:
QAudio::Mode mode;
QString device;
quint32 devId;
- QAudioFormat nearest;
QList<int> sampleRatez;
QList<int> channelz;
QList<int> sizez;
- QList<QAudioFormat::Endian> byteOrderz;
- QStringList codecz;
QList<QAudioFormat::SampleType> typez;
};
+
+
QT_END_NAMESPACE
diff --git a/src/plugins/windowsaudio/qwindowsaudioinput.cpp b/src/plugins/windowsaudio/qwindowsaudioinput.cpp
index b44f206e8..ac92cf582 100644
--- a/src/plugins/windowsaudio/qwindowsaudioinput.cpp
+++ b/src/plugins/windowsaudio/qwindowsaudioinput.cpp
@@ -296,18 +296,9 @@ bool QWindowsAudioInput::open()
period_size = 0;
- if (!settings.isValid()) {
+ if (!qt_convertFormat(settings, &wfx)) {
qWarning("QAudioInput: open error, invalid format.");
- } else if (settings.channelCount() <= 0) {
- qWarning("QAudioInput: open error, invalid number of channels (%d).",
- settings.channelCount());
- } else if (settings.sampleSize() <= 0) {
- qWarning("QAudioInput: open error, invalid sample size (%d).",
- settings.sampleSize());
- } else if (settings.sampleRate() < 8000 || settings.sampleRate() > 96000) {
- qWarning("QAudioInput: open error, sample rate out of range (%d).", settings.sampleRate());
} else if (buffer_size == 0) {
-
buffer_size
= (settings.sampleRate()
* settings.channelCount()
@@ -327,20 +318,12 @@ bool QWindowsAudioInput::open()
timeStamp.restart();
elapsedTimeOffset = 0;
- wfx.nSamplesPerSec = settings.sampleRate();
- wfx.wBitsPerSample = settings.sampleSize();
- wfx.nChannels = settings.channelCount();
- wfx.cbSize = 0;
-
- wfx.wFormatTag = WAVE_FORMAT_PCM;
- wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
- wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
QDataStream ds(&m_device, QIODevice::ReadOnly);
quint32 deviceId;
ds >> deviceId;
- if (waveInOpen(&hWaveIn, UINT_PTR(deviceId), &wfx,
+ if (waveInOpen(&hWaveIn, UINT_PTR(deviceId), &wfx.Format,
(DWORD_PTR)&waveInProc,
(DWORD_PTR) this,
CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
diff --git a/src/plugins/windowsaudio/qwindowsaudioinput.h b/src/plugins/windowsaudio/qwindowsaudioinput.h
index 27edabf0c..151996d78 100644
--- a/src/plugins/windowsaudio/qwindowsaudioinput.h
+++ b/src/plugins/windowsaudio/qwindowsaudioinput.h
@@ -45,8 +45,7 @@
#ifndef QWINDOWSAUDIOINPUT_H
#define QWINDOWSAUDIOINPUT_H
-#include <QtCore/qt_windows.h>
-#include <mmsystem.h>
+#include "qwindowsaudioutils.h"
#include <QtCore/qfile.h>
#include <QtCore/qdebug.h>
@@ -121,7 +120,7 @@ private:
qint64 totalTimeValue;
bool pullMode;
bool resuming;
- WAVEFORMATEX wfx;
+ WAVEFORMATEXTENSIBLE wfx;
HWAVEIN hWaveIn;
MMRESULT result;
WAVEHDR* waveBlocks;
diff --git a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp
index a9230139c..923488794 100644
--- a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp
+++ b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp
@@ -43,55 +43,10 @@
//
#include "qwindowsaudiooutput.h"
+#include "qwindowsaudiodeviceinfo.h"
+#include "qwindowsaudioutils.h"
#include <QtEndian>
-#ifndef SPEAKER_FRONT_LEFT
- #define SPEAKER_FRONT_LEFT 0x00000001
- #define SPEAKER_FRONT_RIGHT 0x00000002
- #define SPEAKER_FRONT_CENTER 0x00000004
- #define SPEAKER_LOW_FREQUENCY 0x00000008
- #define SPEAKER_BACK_LEFT 0x00000010
- #define SPEAKER_BACK_RIGHT 0x00000020
- #define SPEAKER_FRONT_LEFT_OF_CENTER 0x00000040
- #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080
- #define SPEAKER_BACK_CENTER 0x00000100
- #define SPEAKER_SIDE_LEFT 0x00000200
- #define SPEAKER_SIDE_RIGHT 0x00000400
- #define SPEAKER_TOP_CENTER 0x00000800
- #define SPEAKER_TOP_FRONT_LEFT 0x00001000
- #define SPEAKER_TOP_FRONT_CENTER 0x00002000
- #define SPEAKER_TOP_FRONT_RIGHT 0x00004000
- #define SPEAKER_TOP_BACK_LEFT 0x00008000
- #define SPEAKER_TOP_BACK_CENTER 0x00010000
- #define SPEAKER_TOP_BACK_RIGHT 0x00020000
- #define SPEAKER_RESERVED 0x7FFC0000
- #define SPEAKER_ALL 0x80000000
-#endif
-
-#ifndef _WAVEFORMATEXTENSIBLE_
-
- #define _WAVEFORMATEXTENSIBLE_
- typedef struct
- {
- WAVEFORMATEX Format; // Base WAVEFORMATEX data
- union
- {
- WORD wValidBitsPerSample; // Valid bits in each sample container
- WORD wSamplesPerBlock; // Samples per block of audio data; valid
- // if wBitsPerSample=0 (but rarely used).
- WORD wReserved; // Zero if neither case above applies.
- } Samples;
- DWORD dwChannelMask; // Positions of the audio channels
- GUID SubFormat; // Format identifier GUID
- } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE, *LPPWAVEFORMATEXTENSIBLE;
- typedef const WAVEFORMATEXTENSIBLE* LPCWAVEFORMATEXTENSIBLE;
-
-#endif
-
-#if !defined(WAVE_FORMAT_EXTENSIBLE)
-#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
-#endif
-
//#define DEBUG_AUDIO 1
QT_BEGIN_NAMESPACE
@@ -264,16 +219,8 @@ bool QWindowsAudioOutput::open()
period_size = 0;
- if (!settings.isValid()) {
+ if (!qt_convertFormat(settings, &wfx)) {
qWarning("QAudioOutput: open error, invalid format.");
- } else if (settings.channelCount() <= 0) {
- qWarning("QAudioOutput: open error, invalid number of channels (%d).",
- settings.channelCount());
- } else if (settings.sampleSize() <= 0) {
- qWarning("QAudioOutput: open error, invalid sample size (%d).",
- settings.sampleSize());
- } else if (settings.sampleRate() < 8000 || settings.sampleRate() > 96000) {
- qWarning("QAudioOutput: open error, sample rate out of range (%d).", settings.sampleRate());
} else if (buffer_size == 0) {
// Default buffer size, 200ms, default period size is 40ms
buffer_size
@@ -307,67 +254,19 @@ bool QWindowsAudioOutput::open()
timeStamp.restart();
elapsedTimeOffset = 0;
- wfx.nSamplesPerSec = settings.sampleRate();
- wfx.wBitsPerSample = settings.sampleSize();
- wfx.nChannels = settings.channelCount();
- wfx.cbSize = 0;
-
- bool surround = false;
-
- if (settings.channelCount() > 2)
- surround = true;
-
- wfx.wFormatTag = WAVE_FORMAT_PCM;
- wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
- wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
-
QDataStream ds(&m_device, QIODevice::ReadOnly);
quint32 deviceId;
ds >> deviceId;
- if (!surround) {
- if (waveOutOpen(&hWaveOut, UINT_PTR(deviceId), &wfx,
+ if (waveOutOpen(&hWaveOut, UINT_PTR(deviceId), &wfx.Format,
(DWORD_PTR)&waveOutProc,
(DWORD_PTR) this,
CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
- errorState = QAudio::OpenError;
- deviceState = QAudio::StoppedState;
- emit stateChanged(deviceState);
- qWarning("QAudioOutput: open error");
- return false;
- }
- } else {
- WAVEFORMATEXTENSIBLE wfex;
- wfex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
- wfex.Format.nChannels = settings.channelCount();
- wfex.Format.wBitsPerSample = settings.sampleSize();
- wfex.Format.nSamplesPerSec = settings.sampleRate();
- wfex.Format.nBlockAlign = wfex.Format.nChannels*wfex.Format.wBitsPerSample/8;
- wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec*wfex.Format.nBlockAlign;
- wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample;
- static const GUID _KSDATAFORMAT_SUBTYPE_PCM = {
- 0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
- wfex.SubFormat=_KSDATAFORMAT_SUBTYPE_PCM;
- wfex.Format.cbSize=22;
-
- wfex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
- if (settings.channelCount() >= 4)
- wfex.dwChannelMask |= SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
- if (settings.channelCount() >= 6)
- wfex.dwChannelMask |= SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY;
- if (settings.channelCount() == 8)
- wfex.dwChannelMask |= SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT;
-
- if (waveOutOpen(&hWaveOut, UINT_PTR(deviceId), &wfex.Format,
- (DWORD_PTR)&waveOutProc,
- (DWORD_PTR) this,
- CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
- errorState = QAudio::OpenError;
- deviceState = QAudio::StoppedState;
- emit stateChanged(deviceState);
- qWarning("QAudioOutput: open error");
- return false;
- }
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StoppedState;
+ emit stateChanged(deviceState);
+ qWarning("QAudioOutput: open error");
+ return false;
}
totalTimeValue = 0;
diff --git a/src/plugins/windowsaudio/qwindowsaudiooutput.h b/src/plugins/windowsaudio/qwindowsaudiooutput.h
index 479cc98c1..afc73ba5e 100644
--- a/src/plugins/windowsaudio/qwindowsaudiooutput.h
+++ b/src/plugins/windowsaudio/qwindowsaudiooutput.h
@@ -45,8 +45,7 @@
#ifndef QWINDOWSAUDIOOUTPUT_H
#define QWINDOWSAUDIOOUTPUT_H
-#include <QtCore/qt_windows.h>
-#include <mmsystem.h>
+#include "qwindowsaudioutils.h"
#include <QtCore/qdebug.h>
#include <QtCore/qtimer.h>
@@ -132,7 +131,7 @@ private:
bool open();
void close();
- WAVEFORMATEX wfx;
+ WAVEFORMATEXTENSIBLE wfx;
HWAVEOUT hWaveOut;
MMRESULT result;
WAVEHDR header;
diff --git a/src/plugins/windowsaudio/qwindowsaudioutils.cpp b/src/plugins/windowsaudio/qwindowsaudioutils.cpp
new file mode 100644
index 000000000..36a8d750f
--- /dev/null
+++ b/src/plugins/windowsaudio/qwindowsaudioutils.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwindowsaudioutils.h"
+
+#ifndef SPEAKER_FRONT_LEFT
+ #define SPEAKER_FRONT_LEFT 0x00000001
+ #define SPEAKER_FRONT_RIGHT 0x00000002
+ #define SPEAKER_FRONT_CENTER 0x00000004
+ #define SPEAKER_LOW_FREQUENCY 0x00000008
+ #define SPEAKER_BACK_LEFT 0x00000010
+ #define SPEAKER_BACK_RIGHT 0x00000020
+ #define SPEAKER_FRONT_LEFT_OF_CENTER 0x00000040
+ #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080
+ #define SPEAKER_BACK_CENTER 0x00000100
+ #define SPEAKER_SIDE_LEFT 0x00000200
+ #define SPEAKER_SIDE_RIGHT 0x00000400
+ #define SPEAKER_TOP_CENTER 0x00000800
+ #define SPEAKER_TOP_FRONT_LEFT 0x00001000
+ #define SPEAKER_TOP_FRONT_CENTER 0x00002000
+ #define SPEAKER_TOP_FRONT_RIGHT 0x00004000
+ #define SPEAKER_TOP_BACK_LEFT 0x00008000
+ #define SPEAKER_TOP_BACK_CENTER 0x00010000
+ #define SPEAKER_TOP_BACK_RIGHT 0x00020000
+ #define SPEAKER_RESERVED 0x7FFC0000
+ #define SPEAKER_ALL 0x80000000
+#endif
+
+#ifndef WAVE_FORMAT_EXTENSIBLE
+ #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
+#endif
+
+#ifndef WAVE_FORMAT_IEEE_FLOAT
+ #define WAVE_FORMAT_IEEE_FLOAT 0x0003
+#endif
+
+static const GUID _KSDATAFORMAT_SUBTYPE_PCM = {
+ 0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
+
+static const GUID _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {
+ 0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
+
+QT_BEGIN_NAMESPACE
+
+bool qt_convertFormat(const QAudioFormat &format, WAVEFORMATEXTENSIBLE *wfx)
+{
+ if (!wfx
+ || !format.isValid()
+ || format.codec() != QStringLiteral("audio/pcm")
+ || format.sampleRate() <= 0
+ || format.channelCount() <= 0
+ || format.sampleSize() <= 0
+ || format.byteOrder() != QAudioFormat::LittleEndian) {
+ return false;
+ }
+
+ wfx->Format.nSamplesPerSec = format.sampleRate();
+ wfx->Format.wBitsPerSample = wfx->Samples.wValidBitsPerSample = format.sampleSize();
+ wfx->Format.nChannels = format.channelCount();
+ wfx->Format.nBlockAlign = (wfx->Format.wBitsPerSample / 8) * wfx->Format.nChannels;
+ wfx->Format.nAvgBytesPerSec = wfx->Format.nBlockAlign * wfx->Format.nSamplesPerSec;
+ wfx->Format.cbSize = 0;
+
+ if (format.sampleType() == QAudioFormat::Float) {
+ wfx->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ wfx->SubFormat = _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+ } else {
+ wfx->Format.wFormatTag = WAVE_FORMAT_PCM;
+ wfx->SubFormat = _KSDATAFORMAT_SUBTYPE_PCM;
+ }
+
+ if (format.channelCount() > 2) {
+ wfx->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ wfx->Format.cbSize = 22;
+ wfx->dwChannelMask = 0xFFFFFFFF >> (32 - format.channelCount());
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/windowsaudio/qwindowsaudioutils.h b/src/plugins/windowsaudio/qwindowsaudioutils.h
new file mode 100644
index 000000000..1f282cea1
--- /dev/null
+++ b/src/plugins/windowsaudio/qwindowsaudioutils.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSAUDIOUTILS_H
+#define QWINDOWSAUDIOUTILS_H
+
+#include <qaudioformat.h>
+#include <QtCore/qt_windows.h>
+#include <mmsystem.h>
+
+#ifndef _WAVEFORMATEXTENSIBLE_
+
+ #define _WAVEFORMATEXTENSIBLE_
+ typedef struct
+ {
+ WAVEFORMATEX Format; // Base WAVEFORMATEX data
+ union
+ {
+ WORD wValidBitsPerSample; // Valid bits in each sample container
+ WORD wSamplesPerBlock; // Samples per block of audio data; valid
+ // if wBitsPerSample=0 (but rarely used).
+ WORD wReserved; // Zero if neither case above applies.
+ } Samples;
+ DWORD dwChannelMask; // Positions of the audio channels
+ GUID SubFormat; // Format identifier GUID
+ } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE, *LPPWAVEFORMATEXTENSIBLE;
+ typedef const WAVEFORMATEXTENSIBLE* LPCWAVEFORMATEXTENSIBLE;
+
+#endif
+
+QT_BEGIN_NAMESPACE
+
+bool qt_convertFormat(const QAudioFormat &format, WAVEFORMATEXTENSIBLE *wfx);
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSAUDIOUTILS_H
diff --git a/src/plugins/windowsaudio/windowsaudio.pro b/src/plugins/windowsaudio/windowsaudio.pro
index ead73251b..7e8e4320b 100644
--- a/src/plugins/windowsaudio/windowsaudio.pro
+++ b/src/plugins/windowsaudio/windowsaudio.pro
@@ -12,13 +12,15 @@ HEADERS += \
qwindowsaudioplugin.h \
qwindowsaudiodeviceinfo.h \
qwindowsaudioinput.h \
- qwindowsaudiooutput.h
+ qwindowsaudiooutput.h \
+ qwindowsaudioutils.h
SOURCES += \
qwindowsaudioplugin.cpp \
qwindowsaudiodeviceinfo.cpp \
qwindowsaudioinput.cpp \
- qwindowsaudiooutput.cpp
+ qwindowsaudiooutput.cpp \
+ qwindowsaudioutils.cpp
OTHER_FILES += \
windowsaudio.json