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>
This commit is contained in:
Yoann Lopes
2015-03-13 16:25:15 +01:00
parent b529cf242a
commit 07606dde9a
9 changed files with 293 additions and 247 deletions

View File

@@ -44,8 +44,8 @@
#include <QtCore/qt_windows.h> #include <QtCore/qt_windows.h>
#include <mmsystem.h>
#include "qwindowsaudiodeviceinfo.h" #include "qwindowsaudiodeviceinfo.h"
#include "qwindowsaudioutils.h"
#if defined(Q_CC_MINGW) && !defined(__MINGW64_VERSION_MAJOR) #if defined(Q_CC_MINGW) && !defined(__MINGW64_VERSION_MAJOR)
struct IBaseFilter; // Needed for strmif.h from stock MinGW. struct IBaseFilter; // Needed for strmif.h from stock MinGW.
@@ -166,8 +166,7 @@ QString QWindowsAudioDeviceInfo::deviceName() const
QStringList QWindowsAudioDeviceInfo::supportedCodecs() QStringList QWindowsAudioDeviceInfo::supportedCodecs()
{ {
updateLists(); return QStringList() << QStringLiteral("audio/pcm");
return codecz;
} }
QList<int> QWindowsAudioDeviceInfo::supportedSampleRates() QList<int> QWindowsAudioDeviceInfo::supportedSampleRates()
@@ -190,8 +189,7 @@ QList<int> QWindowsAudioDeviceInfo::supportedSampleSizes()
QList<QAudioFormat::Endian> QWindowsAudioDeviceInfo::supportedByteOrders() QList<QAudioFormat::Endian> QWindowsAudioDeviceInfo::supportedByteOrders()
{ {
updateLists(); return QList<QAudioFormat::Endian>() << QAudioFormat::LittleEndian;
return byteOrderz;
} }
QList<QAudioFormat::SampleType> QWindowsAudioDeviceInfo::supportedSampleTypes() QList<QAudioFormat::SampleType> QWindowsAudioDeviceInfo::supportedSampleTypes()
@@ -212,118 +210,50 @@ void QWindowsAudioDeviceInfo::close()
bool QWindowsAudioDeviceInfo::testSettings(const QAudioFormat& format) const bool QWindowsAudioDeviceInfo::testSettings(const QAudioFormat& format) const
{ {
// Set nearest to closest settings that do work. WAVEFORMATEXTENSIBLE wfx;
// See if what is in settings will work (return value). if (qt_convertFormat(format, &wfx)) {
// query only, do not open device
bool failed = false; if (mode == QAudio::AudioOutput) {
bool match = false; return (waveOutOpen(NULL, UINT_PTR(devId), &wfx.Format, NULL, NULL,
WAVE_FORMAT_QUERY) == MMSYSERR_NOERROR);
// check codec } else { // AudioInput
for( int i = 0; i < codecz.count(); i++) { return (waveInOpen(NULL, UINT_PTR(devId), &wfx.Format, NULL, NULL,
if (format.codec() == codecz.at(i)) WAVE_FORMAT_QUERY) == MMSYSERR_NOERROR);
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;
}
}
if (!match)
failed = true;
}
if(!failed) {
// settings work
return true;
}
return false; return false;
} }
void QWindowsAudioDeviceInfo::updateLists() void QWindowsAudioDeviceInfo::updateLists()
{ {
// redo all lists based on current settings if (!sizez.isEmpty())
bool match = false; return;
bool hasCaps = false;
DWORD fmt = 0; DWORD fmt = 0;
if(mode == QAudio::AudioOutput) { if(mode == QAudio::AudioOutput) {
WAVEOUTCAPS woc; WAVEOUTCAPS woc;
if (waveOutGetDevCaps(devId, &woc, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) { if (waveOutGetDevCaps(devId, &woc, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) {
match = true; hasCaps = true;
fmt = woc.dwFormats; fmt = woc.dwFormats;
} }
} else { } else {
WAVEINCAPS woc; WAVEINCAPS woc;
if (waveInGetDevCaps(devId, &woc, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) { if (waveInGetDevCaps(devId, &woc, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) {
match = true; hasCaps = true;
fmt = woc.dwFormats; fmt = woc.dwFormats;
} }
} }
sizez.clear(); sizez.clear();
sampleRatez.clear(); sampleRatez.clear();
channelz.clear(); channelz.clear();
byteOrderz.clear();
typez.clear(); typez.clear();
codecz.clear();
if(match) { if (hasCaps) {
// Check sample size
if ((fmt & WAVE_FORMAT_1M08) if ((fmt & WAVE_FORMAT_1M08)
|| (fmt & WAVE_FORMAT_1S08) || (fmt & WAVE_FORMAT_1S08)
|| (fmt & WAVE_FORMAT_2M08) || (fmt & WAVE_FORMAT_2M08)
@@ -333,8 +263,7 @@ void QWindowsAudioDeviceInfo::updateLists()
|| (fmt & WAVE_FORMAT_48M08) || (fmt & WAVE_FORMAT_48M08)
|| (fmt & WAVE_FORMAT_48S08) || (fmt & WAVE_FORMAT_48S08)
|| (fmt & WAVE_FORMAT_96M08) || (fmt & WAVE_FORMAT_96M08)
|| (fmt & WAVE_FORMAT_96S08) || (fmt & WAVE_FORMAT_96S08)) {
) {
sizez.append(8); sizez.append(8);
} }
if ((fmt & WAVE_FORMAT_1M16) if ((fmt & WAVE_FORMAT_1M16)
@@ -346,10 +275,11 @@ void QWindowsAudioDeviceInfo::updateLists()
|| (fmt & WAVE_FORMAT_48M16) || (fmt & WAVE_FORMAT_48M16)
|| (fmt & WAVE_FORMAT_48S16) || (fmt & WAVE_FORMAT_48S16)
|| (fmt & WAVE_FORMAT_96M16) || (fmt & WAVE_FORMAT_96M16)
|| (fmt & WAVE_FORMAT_96S16) || (fmt & WAVE_FORMAT_96S16)) {
) {
sizez.append(16); sizez.append(16);
} }
// Check sample rate
if ((fmt & WAVE_FORMAT_1M08) if ((fmt & WAVE_FORMAT_1M08)
|| (fmt & WAVE_FORMAT_1S08) || (fmt & WAVE_FORMAT_1S08)
|| (fmt & WAVE_FORMAT_1M16) || (fmt & WAVE_FORMAT_1M16)
@@ -380,23 +310,81 @@ void QWindowsAudioDeviceInfo::updateLists()
|| (fmt & WAVE_FORMAT_96S16)) { || (fmt & WAVE_FORMAT_96S16)) {
sampleRatez.append(96000); 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::SignedInt);
typez.append(QAudioFormat::UnSignedInt); 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) QList<QByteArray> QWindowsAudioDeviceInfo::availableDevices(QAudio::Mode mode)

View File

@@ -57,7 +57,6 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
const unsigned int MAX_SAMPLE_RATES = 5; const unsigned int MAX_SAMPLE_RATES = 5;
const unsigned int SAMPLE_RATES[] = { 8000, 11025, 22050, 44100, 48000 }; const unsigned int SAMPLE_RATES[] = { 8000, 11025, 22050, 44100, 48000 };
@@ -91,15 +90,14 @@ private:
QAudio::Mode mode; QAudio::Mode mode;
QString device; QString device;
quint32 devId; quint32 devId;
QAudioFormat nearest;
QList<int> sampleRatez; QList<int> sampleRatez;
QList<int> channelz; QList<int> channelz;
QList<int> sizez; QList<int> sizez;
QList<QAudioFormat::Endian> byteOrderz;
QStringList codecz;
QList<QAudioFormat::SampleType> typez; QList<QAudioFormat::SampleType> typez;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@@ -296,18 +296,9 @@ bool QWindowsAudioInput::open()
period_size = 0; period_size = 0;
if (!settings.isValid()) { if (!qt_convertFormat(settings, &wfx)) {
qWarning("QAudioInput: open error, invalid format."); 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) { } else if (buffer_size == 0) {
buffer_size buffer_size
= (settings.sampleRate() = (settings.sampleRate()
* settings.channelCount() * settings.channelCount()
@@ -327,20 +318,12 @@ bool QWindowsAudioInput::open()
timeStamp.restart(); timeStamp.restart();
elapsedTimeOffset = 0; 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); QDataStream ds(&m_device, QIODevice::ReadOnly);
quint32 deviceId; quint32 deviceId;
ds >> deviceId; ds >> deviceId;
if (waveInOpen(&hWaveIn, UINT_PTR(deviceId), &wfx, if (waveInOpen(&hWaveIn, UINT_PTR(deviceId), &wfx.Format,
(DWORD_PTR)&waveInProc, (DWORD_PTR)&waveInProc,
(DWORD_PTR) this, (DWORD_PTR) this,
CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {

View File

@@ -45,8 +45,7 @@
#ifndef QWINDOWSAUDIOINPUT_H #ifndef QWINDOWSAUDIOINPUT_H
#define QWINDOWSAUDIOINPUT_H #define QWINDOWSAUDIOINPUT_H
#include <QtCore/qt_windows.h> #include "qwindowsaudioutils.h"
#include <mmsystem.h>
#include <QtCore/qfile.h> #include <QtCore/qfile.h>
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
@@ -121,7 +120,7 @@ private:
qint64 totalTimeValue; qint64 totalTimeValue;
bool pullMode; bool pullMode;
bool resuming; bool resuming;
WAVEFORMATEX wfx; WAVEFORMATEXTENSIBLE wfx;
HWAVEIN hWaveIn; HWAVEIN hWaveIn;
MMRESULT result; MMRESULT result;
WAVEHDR* waveBlocks; WAVEHDR* waveBlocks;

View File

@@ -43,55 +43,10 @@
// //
#include "qwindowsaudiooutput.h" #include "qwindowsaudiooutput.h"
#include "qwindowsaudiodeviceinfo.h"
#include "qwindowsaudioutils.h"
#include <QtEndian> #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 //#define DEBUG_AUDIO 1
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@@ -264,16 +219,8 @@ bool QWindowsAudioOutput::open()
period_size = 0; period_size = 0;
if (!settings.isValid()) { if (!qt_convertFormat(settings, &wfx)) {
qWarning("QAudioOutput: open error, invalid format."); 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) { } else if (buffer_size == 0) {
// Default buffer size, 200ms, default period size is 40ms // Default buffer size, 200ms, default period size is 40ms
buffer_size buffer_size
@@ -307,67 +254,19 @@ bool QWindowsAudioOutput::open()
timeStamp.restart(); timeStamp.restart();
elapsedTimeOffset = 0; 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); QDataStream ds(&m_device, QIODevice::ReadOnly);
quint32 deviceId; quint32 deviceId;
ds >> deviceId; ds >> deviceId;
if (!surround) { if (waveOutOpen(&hWaveOut, UINT_PTR(deviceId), &wfx.Format,
if (waveOutOpen(&hWaveOut, UINT_PTR(deviceId), &wfx,
(DWORD_PTR)&waveOutProc, (DWORD_PTR)&waveOutProc,
(DWORD_PTR) this, (DWORD_PTR) this,
CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
errorState = QAudio::OpenError; errorState = QAudio::OpenError;
deviceState = QAudio::StoppedState; deviceState = QAudio::StoppedState;
emit stateChanged(deviceState); emit stateChanged(deviceState);
qWarning("QAudioOutput: open error"); qWarning("QAudioOutput: open error");
return false; 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;
}
} }
totalTimeValue = 0; totalTimeValue = 0;

View File

@@ -45,8 +45,7 @@
#ifndef QWINDOWSAUDIOOUTPUT_H #ifndef QWINDOWSAUDIOOUTPUT_H
#define QWINDOWSAUDIOOUTPUT_H #define QWINDOWSAUDIOOUTPUT_H
#include <QtCore/qt_windows.h> #include "qwindowsaudioutils.h"
#include <mmsystem.h>
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#include <QtCore/qtimer.h> #include <QtCore/qtimer.h>
@@ -132,7 +131,7 @@ private:
bool open(); bool open();
void close(); void close();
WAVEFORMATEX wfx; WAVEFORMATEXTENSIBLE wfx;
HWAVEOUT hWaveOut; HWAVEOUT hWaveOut;
MMRESULT result; MMRESULT result;
WAVEHDR header; WAVEHDR header;

View File

@@ -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

View File

@@ -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

View File

@@ -12,13 +12,15 @@ HEADERS += \
qwindowsaudioplugin.h \ qwindowsaudioplugin.h \
qwindowsaudiodeviceinfo.h \ qwindowsaudiodeviceinfo.h \
qwindowsaudioinput.h \ qwindowsaudioinput.h \
qwindowsaudiooutput.h qwindowsaudiooutput.h \
qwindowsaudioutils.h
SOURCES += \ SOURCES += \
qwindowsaudioplugin.cpp \ qwindowsaudioplugin.cpp \
qwindowsaudiodeviceinfo.cpp \ qwindowsaudiodeviceinfo.cpp \
qwindowsaudioinput.cpp \ qwindowsaudioinput.cpp \
qwindowsaudiooutput.cpp qwindowsaudiooutput.cpp \
qwindowsaudioutils.cpp
OTHER_FILES += \ OTHER_FILES += \
windowsaudio.json windowsaudio.json