Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qwindowsaudioutils.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6#include "qdebug.h"
7#include "ks.h"
8#include "ksmedia.h"
9
10#include <audioclient.h>
11
13
15 { QAudioFormat::FrontLeft // SPEAKER_FRONT_LEFT (0x1)
16 , QAudioFormat::FrontRight // SPEAKER_FRONT_RIGHT (0x2)
17 , QAudioFormat::FrontCenter // SPEAKER_FRONT_CENTER (0x4)
18 , QAudioFormat::LFE // SPEAKER_LOW_FREQUENCY (0x8)
19 , QAudioFormat::BackLeft // SPEAKER_BACK_LEFT (0x10)
20 , QAudioFormat::BackRight // SPEAKER_BACK_RIGHT (0x20)
21 , QAudioFormat::FrontLeftOfCenter // SPEAKER_FRONT_LEFT_OF_CENTER (0x40)
22 , QAudioFormat::FrontRightOfCenter// SPEAKER_FRONT_RIGHT_OF_CENTER (0x80)
23 , QAudioFormat::BackCenter // SPEAKER_BACK_CENTER (0x100)
24 , QAudioFormat::SideLeft // SPEAKER_SIDE_LEFT (0x200)
25 , QAudioFormat::SideRight // SPEAKER_SIDE_RIGHT (0x400)
26 , QAudioFormat::TopCenter // SPEAKER_TOP_CENTER (0x800)
27 , QAudioFormat::TopFrontLeft // SPEAKER_TOP_FRONT_LEFT (0x1000)
28 , QAudioFormat::TopFrontCenter // SPEAKER_TOP_FRONT_CENTER (0x2000)
29 , QAudioFormat::TopFrontRight // SPEAKER_TOP_FRONT_RIGHT (0x4000)
30 , QAudioFormat::TopBackLeft // SPEAKER_TOP_BACK_LEFT (0x8000)
31 , QAudioFormat::TopBackCenter // SPEAKER_TOP_BACK_CENTER (0x10000)
32 , QAudioFormat::TopBackRight // SPEAKER_TOP_BACK_RIGHT (0x20000)
33 };
34
36{
37 quint32 config = 0;
38 int set = 0;
39 for (auto c : channelFormatMap) {
40 if (mask & 1) {
42 ++set;
43 }
44 if (set >= count)
45 break;
46 mask >>= 1;
47 }
49}
50
52{
53 UINT32 mask = 0;
54 quint32 i = 0;
55 for (auto c : channelFormatMap) {
57 mask |= 1 << i;
58 ++i;
59 }
60 return mask;
61}
62
64{
65 if (!format.isValid())
66 return false;
67
68 wfx.Format.nSamplesPerSec = format.sampleRate();
69 wfx.Format.wBitsPerSample = wfx.Samples.wValidBitsPerSample = format.bytesPerSample()*8;
70 wfx.Format.nChannels = format.channelCount();
71 wfx.Format.nBlockAlign = (wfx.Format.wBitsPerSample / 8) * wfx.Format.nChannels;
72 wfx.Format.nAvgBytesPerSec = wfx.Format.nBlockAlign * wfx.Format.nSamplesPerSec;
73 wfx.Format.cbSize = 0;
74
75 if (format.sampleFormat() == QAudioFormat::Float) {
76 wfx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
77 wfx.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
78 } else {
79 wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
80 wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
81 }
82
83 if (format.channelCount() > 2) {
84 wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
85 wfx.Format.cbSize = 22;
86 wfx.dwChannelMask = format.channelConfig() == QAudioFormat::ChannelConfigUnknown ? KSAUDIO_SPEAKER_DIRECTOUT
87 : DWORD(format.channelConfig());
88 }
89
90 return true;
91}
92
94{
96 out.setSampleRate(in.nSamplesPerSec);
97 out.setChannelCount(in.nChannels);
98 if (in.wFormatTag == WAVE_FORMAT_PCM) {
99 if (in.wBitsPerSample == 8)
100 out.setSampleFormat(QAudioFormat::UInt8);
101 else if (in.wBitsPerSample == 16)
102 out.setSampleFormat(QAudioFormat::Int16);
103 else if (in.wBitsPerSample == 32)
104 out.setSampleFormat(QAudioFormat::Int32);
105 } else if (in.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
106 if (in.cbSize >= 22) {
107 auto wfe = reinterpret_cast<const WAVEFORMATEXTENSIBLE &>(in);
108 if (wfe.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
109 out.setSampleFormat(QAudioFormat::Float);
110 if (qPopulationCount(wfe.dwChannelMask) >= in.nChannels)
111 out.setChannelConfig(maskToChannelConfig(wfe.dwChannelMask, in.nChannels));
112 }
113 } else if (in.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
114 out.setSampleFormat(QAudioFormat::Float);
115 }
116
117 return out;
118}
119
121{
123 if (!mediaType)
124 return format;
125
126 UINT32 val = 0;
127 if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &val))) {
128 format.setChannelCount(int(val));
129 } else {
130 qWarning() << "Could not determine channel count from IMFMediaType";
131 return {};
132 }
133
134 if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_CHANNEL_MASK, &val))) {
135 if (int(qPopulationCount(val)) >= format.channelCount())
136 format.setChannelConfig(maskToChannelConfig(val, format.channelCount()));
137 }
138
139 if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &val))) {
140 format.setSampleRate(int(val));
141 }
142 UINT32 bitsPerSample = 0;
143 mediaType->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bitsPerSample);
144
145 GUID subType;
146 if (SUCCEEDED(mediaType->GetGUID(MF_MT_SUBTYPE, &subType))) {
147 if (subType == MFAudioFormat_Float) {
148 format.setSampleFormat(QAudioFormat::Float);
149 } else if (bitsPerSample == 8) {
150 format.setSampleFormat(QAudioFormat::UInt8);
151 } else if (bitsPerSample == 16) {
152 format.setSampleFormat(QAudioFormat::Int16);
153 } else if (bitsPerSample == 32){
154 format.setSampleFormat(QAudioFormat::Int32);
155 }
156 }
157 return format;
158}
159
161{
162 ComPtr<IMFMediaType> mediaType;
163
164 if (!format.isValid())
165 return mediaType;
166
167 wmf.mfCreateMediaType(mediaType.GetAddressOf());
168
169 mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
170 if (format.sampleFormat() == QAudioFormat::Float) {
171 mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float);
172 } else {
173 mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
174 }
175
176 mediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, UINT32(format.channelCount()));
177 if (format.channelConfig() != QAudioFormat::ChannelConfigUnknown)
178 mediaType->SetUINT32(MF_MT_AUDIO_CHANNEL_MASK, channelConfigToMask(format.channelConfig()));
179 mediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, UINT32(format.sampleRate()));
180 auto alignmentBlock = UINT32(format.bytesPerFrame());
181 mediaType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, alignmentBlock);
182 auto avgBytesPerSec = UINT32(format.sampleRate() * format.bytesPerFrame());
183 mediaType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, avgBytesPerSec);
184 mediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, UINT32(format.bytesPerSample()*8));
185 mediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
186
187 return mediaType;
188}
189
190std::optional<quint32> QWindowsAudioUtils::audioClientFramesInUse(IAudioClient *client)
191{
192 Q_ASSERT(client);
193 UINT32 framesPadding = 0;
194 if (SUCCEEDED(client->GetCurrentPadding(&framesPadding)))
195 return framesPadding;
196 return {};
197}
198
199std::optional<quint32> QWindowsAudioUtils::audioClientFramesAllocated(IAudioClient *client)
200{
201 Q_ASSERT(client);
202 UINT32 bufferFrameCount = 0;
203 if (SUCCEEDED(client->GetBufferSize(&bufferFrameCount)))
204 return bufferFrameCount;
205 return {};
206}
207
The QAudioFormat class stores audio stream parameter information.
AudioChannelPosition
Describes the possible audio channel positions.
constexpr ChannelConfig channelConfig() const noexcept
Returns the current channel configuration.
ChannelConfig
\variable QAudioFormat::NChannelPositions
decltype(&::MFCreateMediaType) mfCreateMediaType
Combined button and popup list for selecting options.
std::optional< quint32 > audioClientFramesInUse(IAudioClient *client)
Q_MULTIMEDIA_EXPORT QAudioFormat mediaTypeToFormat(IMFMediaType *mediaType)
std::optional< quint32 > audioClientFramesAllocated(IAudioClient *client)
ComPtr< IMFMediaType > formatToMediaType(QWindowsMediaFoundation &, const QAudioFormat &format)
QAudioFormat waveFormatExToFormat(const WAVEFORMATEX &in)
bool formatToWaveFormatExtensible(const QAudioFormat &format, WAVEFORMATEXTENSIBLE &wfx)
QAudioFormat::ChannelConfig maskToChannelConfig(UINT32 mask, int count)
Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR uint qPopulationCount(quint32 v) noexcept
EGLConfig config
#define qWarning
Definition qlogging.h:162
GLenum GLenum GLsizei count
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLint GLsizei GLsizei GLenum format
const GLubyte * c
GLuint GLfloat * val
GLuint in
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
unsigned int quint32
Definition qtypes.h:45
static UINT32 channelConfigToMask(QAudioFormat::ChannelConfig config)
static QT_BEGIN_NAMESPACE QAudioFormat::AudioChannelPosition channelFormatMap[]
QFuture< QSet< QChar > > set
[10]
QTextStream out(stdout)
[7]