Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
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
5
6#include <QtCore/qdebug.h>
7#include <QtCore/private/qsystemerror_p.h>
8#include <QtMultimedia/private/qwindowsmediafoundation_p.h>
9
10
11#include <audioclient.h>
12#include <mmdeviceapi.h>
13#include <ks.h>
14#include <ksmedia.h>
15
16// MinGW misses some error codes
17#ifndef AUDCLNT_E_EFFECT_NOT_AVAILABLE
18# define AUDCLNT_E_EFFECT_NOT_AVAILABLE AUDCLNT_ERR(0x041)
19#endif
20
21#ifndef AUDCLNT_E_EFFECT_STATE_READ_ONLY
22# define AUDCLNT_E_EFFECT_STATE_READ_ONLY AUDCLNT_ERR(0x042)
23#endif
24
26
28
29using namespace std::chrono_literals;
30using namespace Qt::Literals;
31
33 { QAudioFormat::FrontLeft // SPEAKER_FRONT_LEFT (0x1)
34 , QAudioFormat::FrontRight // SPEAKER_FRONT_RIGHT (0x2)
35 , QAudioFormat::FrontCenter // SPEAKER_FRONT_CENTER (0x4)
36 , QAudioFormat::LFE // SPEAKER_LOW_FREQUENCY (0x8)
37 , QAudioFormat::BackLeft // SPEAKER_BACK_LEFT (0x10)
38 , QAudioFormat::BackRight // SPEAKER_BACK_RIGHT (0x20)
39 , QAudioFormat::FrontLeftOfCenter // SPEAKER_FRONT_LEFT_OF_CENTER (0x40)
40 , QAudioFormat::FrontRightOfCenter// SPEAKER_FRONT_RIGHT_OF_CENTER (0x80)
41 , QAudioFormat::BackCenter // SPEAKER_BACK_CENTER (0x100)
42 , QAudioFormat::SideLeft // SPEAKER_SIDE_LEFT (0x200)
43 , QAudioFormat::SideRight // SPEAKER_SIDE_RIGHT (0x400)
44 , QAudioFormat::TopCenter // SPEAKER_TOP_CENTER (0x800)
45 , QAudioFormat::TopFrontLeft // SPEAKER_TOP_FRONT_LEFT (0x1000)
46 , QAudioFormat::TopFrontCenter // SPEAKER_TOP_FRONT_CENTER (0x2000)
47 , QAudioFormat::TopFrontRight // SPEAKER_TOP_FRONT_RIGHT (0x4000)
48 , QAudioFormat::TopBackLeft // SPEAKER_TOP_BACK_LEFT (0x8000)
49 , QAudioFormat::TopBackCenter // SPEAKER_TOP_BACK_CENTER (0x10000)
50 , QAudioFormat::TopBackRight // SPEAKER_TOP_BACK_RIGHT (0x20000)
51 };
52
54{
55 quint32 config = 0;
56 int set = 0;
57 for (auto c : channelFormatMap) {
58 if (mask & 1) {
59 config |= QAudioFormat::channelConfig(c);
60 ++set;
61 }
62 if (set >= count)
63 break;
64 mask >>= 1;
65 }
66 return QAudioFormat::ChannelConfig(config);
67}
68
69static UINT32 channelConfigToMask(QAudioFormat::ChannelConfig config)
70{
71 UINT32 mask = 0;
72 quint32 i = 0;
73 for (auto c : channelFormatMap) {
74 if (config & QAudioFormat::channelConfig(c))
75 mask |= 1 << i;
76 ++i;
77 }
78 return mask;
79}
80
81bool formatToWaveFormatExtensible(const QAudioFormat &format, WAVEFORMATEXTENSIBLE &wfx)
82{
83 if (!format.isValid())
84 return false;
85
86 wfx.Format.nSamplesPerSec = format.sampleRate();
87 wfx.Format.wBitsPerSample = wfx.Samples.wValidBitsPerSample = format.bytesPerSample()*8;
88 wfx.Format.nChannels = format.channelCount();
89 wfx.Format.nBlockAlign = (wfx.Format.wBitsPerSample / 8) * wfx.Format.nChannels;
90 wfx.Format.nAvgBytesPerSec = wfx.Format.nBlockAlign * wfx.Format.nSamplesPerSec;
91 wfx.Format.cbSize = 0;
92
93 if (format.sampleFormat() == QAudioFormat::Float) {
94 wfx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
95 wfx.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
96 } else {
97 wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
98 wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
99 }
100
101 if (format.channelCount() > 2) {
102 wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
103 wfx.Format.cbSize = 22;
104 wfx.dwChannelMask = format.channelConfig() == QAudioFormat::ChannelConfigUnknown ? KSAUDIO_SPEAKER_DIRECTOUT
105 : DWORD(format.channelConfig());
106 }
107
108 return true;
109}
110
112{
113 WAVEFORMATEXTENSIBLE ret{};
114 if (formatToWaveFormatExtensible(format, ret))
115 return ret;
116
117 return std::nullopt;
118}
119
120QAudioFormat waveFormatExToFormat(const WAVEFORMATEX &in)
121{
122 QAudioFormat out;
123 out.setSampleRate(in.nSamplesPerSec);
124 out.setChannelCount(in.nChannels);
125 if (in.wFormatTag == WAVE_FORMAT_PCM) {
126 if (in.wBitsPerSample == 8)
127 out.setSampleFormat(QAudioFormat::UInt8);
128 else if (in.wBitsPerSample == 16)
129 out.setSampleFormat(QAudioFormat::Int16);
130 else if (in.wBitsPerSample == 32)
131 out.setSampleFormat(QAudioFormat::Int32);
132 } else if (in.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
133 if (in.cbSize >= 22) {
134 auto wfe = reinterpret_cast<const WAVEFORMATEXTENSIBLE &>(in);
135 if (wfe.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
136 out.setSampleFormat(QAudioFormat::Float);
137 if (qPopulationCount(wfe.dwChannelMask) >= in.nChannels)
138 out.setChannelConfig(maskToChannelConfig(wfe.dwChannelMask, in.nChannels));
139 }
140 } else if (in.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
141 out.setSampleFormat(QAudioFormat::Float);
142 }
143
144 return out;
145}
146
147QAudioFormat mediaTypeToFormat(IMFMediaType *mediaType)
148{
149 QAudioFormat format;
150 if (!mediaType)
151 return format;
152
153 UINT32 val = 0;
154 if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &val))) {
155 format.setChannelCount(int(val));
156 } else {
157 qWarning() << "Could not determine channel count from IMFMediaType";
158 return {};
159 }
160
161 if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_CHANNEL_MASK, &val))) {
162 if (int(qPopulationCount(val)) >= format.channelCount())
163 format.setChannelConfig(maskToChannelConfig(val, format.channelCount()));
164 }
165
166 if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &val))) {
167 format.setSampleRate(int(val));
168 }
169 UINT32 bitsPerSample = 0;
170 mediaType->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bitsPerSample);
171
172 GUID subType;
173 if (SUCCEEDED(mediaType->GetGUID(MF_MT_SUBTYPE, &subType))) {
174 if (subType == MFAudioFormat_Float) {
175 format.setSampleFormat(QAudioFormat::Float);
176 } else if (bitsPerSample == 8) {
177 format.setSampleFormat(QAudioFormat::UInt8);
178 } else if (bitsPerSample == 16) {
179 format.setSampleFormat(QAudioFormat::Int16);
180 } else if (bitsPerSample == 32){
181 format.setSampleFormat(QAudioFormat::Int32);
182 }
183 }
184 return format;
185}
186
187ComPtr<IMFMediaType> formatToMediaType(QWindowsMediaFoundation &wmf, const QAudioFormat &format)
188{
189 ComPtr<IMFMediaType> mediaType;
190
191 if (!format.isValid())
192 return mediaType;
193
194 wmf.mfCreateMediaType(mediaType.GetAddressOf());
195
196 mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
197 if (format.sampleFormat() == QAudioFormat::Float) {
198 mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float);
199 } else {
200 mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
201 }
202
203 mediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, UINT32(format.channelCount()));
204 if (format.channelConfig() != QAudioFormat::ChannelConfigUnknown)
205 mediaType->SetUINT32(MF_MT_AUDIO_CHANNEL_MASK, channelConfigToMask(format.channelConfig()));
206 mediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, UINT32(format.sampleRate()));
207 auto alignmentBlock = UINT32(format.bytesPerFrame());
208 mediaType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, alignmentBlock);
209 auto avgBytesPerSec = UINT32(format.sampleRate() * format.bytesPerFrame());
210 mediaType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, avgBytesPerSec);
211 mediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, UINT32(format.bytesPerSample()*8));
212 mediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
213
214 return mediaType;
215}
216
217std::optional<quint32> getBufferSizeInFrames(const ComPtr<IAudioClient3> &client)
218{
219 Q_ASSERT(client);
220
221 UINT32 bufferFrameCount = 0;
222
223 HRESULT hr = client->GetBufferSize(&bufferFrameCount);
224 if (SUCCEEDED(hr))
225 return bufferFrameCount;
226
227 qWarning() << "IAudioClient::getBufferSize failed" << audioClientErrorString(hr);
228 return std::nullopt;
229}
230
231std::optional<AudioClientDevicePeriod> getDevicePeriod(const ComPtr<IAudioClient3> &client)
232{
233 Q_ASSERT(client);
234 REFERENCE_TIME defaultPeriodDuration, minimalPeriodDuration;
235 HRESULT hr = client->GetDevicePeriod(&defaultPeriodDuration, &minimalPeriodDuration);
236
237 if (FAILED(hr)) {
238 qWarning() << "IAudioClient3::GetDevicePeriod failed" << audioClientErrorString(hr);
239 return std::nullopt;
240 }
241
242 return AudioClientDevicePeriod{
243 reference_time{ defaultPeriodDuration },
244 reference_time{ minimalPeriodDuration },
245 };
246}
247
249{
250 switch (hr) {
251 case AUDCLNT_E_NOT_INITIALIZED:
252 return u"AUDCLNT_E_NOT_INITIALIZED"_s;
253 case AUDCLNT_E_ALREADY_INITIALIZED:
254 return u"AUDCLNT_E_ALREADY_INITIALIZED"_s;
255 case AUDCLNT_E_WRONG_ENDPOINT_TYPE:
256 return u"AUDCLNT_E_WRONG_ENDPOINT_TYPE"_s;
257 case AUDCLNT_E_DEVICE_INVALIDATED:
258 return u"AUDCLNT_E_DEVICE_INVALIDATED"_s;
259 case AUDCLNT_E_NOT_STOPPED:
260 return u"AUDCLNT_E_NOT_STOPPED"_s;
261 case AUDCLNT_E_BUFFER_TOO_LARGE:
262 return u"AUDCLNT_E_BUFFER_TOO_LARGE"_s;
263 case AUDCLNT_E_OUT_OF_ORDER:
264 return u"AUDCLNT_E_OUT_OF_ORDER"_s;
265 case AUDCLNT_E_UNSUPPORTED_FORMAT:
266 return u"AUDCLNT_E_UNSUPPORTED_FORMAT"_s;
267 case AUDCLNT_E_INVALID_SIZE:
268 return u"AUDCLNT_E_INVALID_SIZE"_s;
269 case AUDCLNT_E_DEVICE_IN_USE:
270 return u"AUDCLNT_E_DEVICE_IN_USE"_s;
271 case AUDCLNT_E_BUFFER_OPERATION_PENDING:
272 return u"AUDCLNT_E_BUFFER_OPERATION_PENDING"_s;
273 case AUDCLNT_E_THREAD_NOT_REGISTERED:
274 return u"AUDCLNT_E_THREAD_NOT_REGISTERED"_s;
275 case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED:
276 return u"AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED"_s;
277 case AUDCLNT_E_ENDPOINT_CREATE_FAILED:
278 return u"AUDCLNT_E_ENDPOINT_CREATE_FAILED"_s;
279 case AUDCLNT_E_SERVICE_NOT_RUNNING:
280 return u"AUDCLNT_E_SERVICE_NOT_RUNNING"_s;
281 case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED:
282 return u"AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED"_s;
283 case AUDCLNT_E_EXCLUSIVE_MODE_ONLY:
284 return u"AUDCLNT_E_EXCLUSIVE_MODE_ONLY"_s;
285 case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL:
286 return u"AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL"_s;
287 case AUDCLNT_E_EVENTHANDLE_NOT_SET:
288 return u"AUDCLNT_E_EVENTHANDLE_NOT_SET"_s;
289 case AUDCLNT_E_INCORRECT_BUFFER_SIZE:
290 return u"AUDCLNT_E_INCORRECT_BUFFER_SIZE"_s;
291 case AUDCLNT_E_BUFFER_SIZE_ERROR:
292 return u"AUDCLNT_E_BUFFER_SIZE_ERROR"_s;
293 case AUDCLNT_E_CPUUSAGE_EXCEEDED:
294 return u"AUDCLNT_E_CPUUSAGE_EXCEEDED"_s;
295 case AUDCLNT_E_BUFFER_ERROR:
296 return u"AUDCLNT_E_BUFFER_ERROR"_s;
297 case AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED:
298 return u"AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED"_s;
299 case AUDCLNT_E_INVALID_DEVICE_PERIOD:
300 return u"AUDCLNT_E_INVALID_DEVICE_PERIOD"_s;
301 case AUDCLNT_E_INVALID_STREAM_FLAG:
302 return u"AUDCLNT_E_INVALID_STREAM_FLAG"_s;
303 case AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE:
304 return u"AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE"_s;
305 case AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES:
306 return u"AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES"_s;
307 case AUDCLNT_E_OFFLOAD_MODE_ONLY:
308 return u"AUDCLNT_E_OFFLOAD_MODE_ONLY"_s;
309 case AUDCLNT_E_NONOFFLOAD_MODE_ONLY:
310 return u"AUDCLNT_E_NONOFFLOAD_MODE_ONLY"_s;
311 case AUDCLNT_E_RESOURCES_INVALIDATED:
312 return u"AUDCLNT_E_RESOURCES_INVALIDATED"_s;
313 case AUDCLNT_E_RAW_MODE_UNSUPPORTED:
314 return u"AUDCLNT_E_RAW_MODE_UNSUPPORTED"_s;
315 case AUDCLNT_E_ENGINE_PERIODICITY_LOCKED:
316 return u"AUDCLNT_E_ENGINE_PERIODICITY_LOCKED"_s;
317 case AUDCLNT_E_ENGINE_FORMAT_LOCKED:
318 return u"AUDCLNT_E_ENGINE_FORMAT_LOCKED"_s;
319 case AUDCLNT_E_HEADTRACKING_ENABLED:
320 return u"AUDCLNT_E_HEADTRACKING_ENABLED"_s;
321 case AUDCLNT_E_HEADTRACKING_UNSUPPORTED:
322 return u"AUDCLNT_E_HEADTRACKING_UNSUPPORTED"_s;
324 return u"AUDCLNT_E_EFFECT_NOT_AVAILABLE"_s;
326 return u"AUDCLNT_E_EFFECT_STATE_READ_ONLY"_s;
327
328 default:
329 return QSystemError::windowsComString(hr);
330 }
331}
332
333bool audioClientSetRole(const ComPtr<IAudioClient3> &client, AudioEndpointRole role)
334{
335 AudioClientProperties properties{};
336 properties.cbSize = sizeof(AudioClientProperties);
337
338 switch (role) {
339 case AudioEndpointRole::MediaPlayback:
340 properties.eCategory = AudioCategory_Media;
341 break;
342 case AudioEndpointRole::SoundEffect:
343 properties.eCategory = AudioCategory_SoundEffects;
344 break;
345 case AudioEndpointRole::Accessibility:
346 properties.eCategory = AudioCategory_Speech;
347 break;
348 case AudioEndpointRole::Other:
349 properties.eCategory = AudioCategory_Other;
350 break;
351 default:
352 Q_UNREACHABLE_RETURN(false);
353 }
354
355 HRESULT hr = client->SetClientProperties(&properties);
356 if (FAILED(hr)) {
357 qWarning() << "IAudioClient2::SetClientProperties failed" << audioClientErrorString(hr);
358 abort();
359 return false;
360 }
361
362 return true;
363}
364
366createAudioClient(const ComPtr<IMMDevice> &device, const QAudioFormat &format,
367 std::optional<qsizetype> hardwareBufferFrames,
368 const QUniqueWin32NullHandle &wasapiEventHandle,
369 std::optional<AudioEndpointRole> role)
370{
371 ComPtr<IAudioClient3> audioClient;
372
373 HRESULT hr = device->Activate(__uuidof(IAudioClient3), CLSCTX_INPROC_SERVER, nullptr,
374 reinterpret_cast<void **>(audioClient.GetAddressOf()));
375 if (FAILED(hr)) {
376 qWarning() << "Failed to activate audio device" << audioClientErrorString(hr);
377 return std::nullopt;
378 }
379
380 std::optional<AudioClientDevicePeriod> devicePeriods = getDevicePeriod(audioClient);
381 if (!devicePeriods)
382 return std::nullopt;
383
384 // qCDebug(qLcAudioSource) << devicePeriods->defaultDuration << devicePeriods->minimalDuration;
385 reference_time periodSize = devicePeriods->defaultDuration;
386 if (hardwareBufferFrames) {
387 std::chrono::microseconds dur{ format.durationForFrames(*hardwareBufferFrames) };
388 if (dur < devicePeriods->minimalDuration)
389 qWarning() << "Requested hardware buffer size to small:" << dur << "minimal duration"
390 << devicePeriods->minimalDuration;
391 else
392 periodSize = dur;
393 }
394
395 auto fmt = toWaveFormatExtensible(format);
396 if (!fmt)
397 return std::nullopt;
398 auto waveFormat = *fmt;
399
400 if (role)
401 audioClientSetRole(audioClient, *role);
402
403 constexpr DWORD streamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK
404 | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
405 | AUDCLNT_STREAMFLAGS_RATEADJUST;
406
407 hr = audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, streamFlags,
408 /*hnsBufferDuration=*/reference_time(periodSize).count(),
409 /*hnsPeriodicity=*/reference_time(periodSize).count(),
410 &waveFormat.Format, nullptr);
411
412 if (FAILED(hr)) {
413 qWarning() << "IAudioClient3::Initialize failed" << audioClientErrorString(hr);
414 return std::nullopt;
415 }
416
417 std::optional<quint32> framesPerBuffer = getBufferSizeInFrames(audioClient);
418 if (!framesPerBuffer)
419 return std::nullopt;
420 qsizetype audioClientFrames = *framesPerBuffer;
421
422 hr = audioClient->SetEventHandle(wasapiEventHandle.get());
423 if (FAILED(hr)) {
424 qWarning() << "IAudioClient3::SetEventHandle failed" << audioClientErrorString(hr);
425 return std::nullopt;
426 }
427
429 /*.client =*/std::move(audioClient),
430 /*.periodSize =*/periodSize,
431 /*.audioClientFrames =*/audioClientFrames,
432 };
433}
434
435bool audioClientStart(const ComPtr<IAudioClient3> &client)
436{
437 HRESULT hr = client->Start();
438 if (FAILED(hr)) {
439 qWarning() << "IAudioClient3::Start failed" << audioClientErrorString(hr);
440 return false;
441 }
442 return true;
443}
444
445bool audioClientStop(const ComPtr<IAudioClient3> &client)
446{
447 HRESULT hr = client->Stop();
448 if (FAILED(hr)) {
449 qWarning() << "IAudioClient3::Stop failed" << audioClientErrorString(hr);
450 return false;
451 }
452 return true;
453}
454
455bool audioClientReset(const ComPtr<IAudioClient3> &client)
456{
457 HRESULT hr = client->Reset();
458 if (FAILED(hr)) {
459 qWarning() << "IAudioClient3::Reset failed" << audioClientErrorString(hr);
460 return false;
461 }
462 return true;
463}
464
465bool audioClientSetRate(const ComPtr<IAudioClient3> &client, int rate)
466{
467 ComPtr<IAudioClockAdjustment> clockAdjustment;
468
469 HRESULT hr = client->GetService(IID_PPV_ARGS(clockAdjustment.GetAddressOf()));
470 if (FAILED(hr)) {
471 qWarning() << "IAudioClient3::GetService failed to obtain IAudioClockAdjustment"
472 << audioClientErrorString(hr);
473 return false;
474 }
475
476 hr = clockAdjustment->SetSampleRate(float(rate));
477 if (FAILED(hr)) {
478 qWarning() << "IAudioClockAdjustment::SetSampleRate failed" << audioClientErrorString(hr);
479 return false;
480 }
481
482 return true;
483}
484
486{
487 // heuristics are similar to what windows does for exclusive mode:
488 // 10ms is the default, when going lower, "Pro Audio" is the way to go
489 auto threadCharacteristics = periodSize < 10ms ? "Pro Audio" : "Audio";
490 DWORD taskIndex = 0;
491 HANDLE hTask = AvSetMmThreadCharacteristicsA(threadCharacteristics, &taskIndex);
492
493 if (hTask == NULL) {
494 qWarning() << "AvSetMmThreadCharacteristics failed to set thread characteristics"
495 << QSystemError::windowsString();
496 }
497
498 AVRT_PRIORITY priority = periodSize < 10ms ? AVRT_PRIORITY_CRITICAL : AVRT_PRIORITY_HIGH;
499 bool success = AvSetMmThreadPriority(hTask, priority);
500 if (!success)
501 qWarning() << "AvSetMmThreadPriority failed to set thread priority"
502 << QSystemError::windowsString();
503}
504} // namespace QWindowsAudioUtils
505
506QT_END_NAMESPACE
static constexpr QAudioFormat::AudioChannelPosition channelFormatMap[]
QAudioFormat mediaTypeToFormat(IMFMediaType *mediaType)
std::optional< AudioClientCreationResult > createAudioClient(const ComPtr< IMMDevice > &device, const QAudioFormat &format, std::optional< qsizetype > hardwareBufferFrames, const QUniqueWin32NullHandle &wasapiEventHandle, std::optional< AudioEndpointRole > role)
bool audioClientSetRate(const ComPtr< IAudioClient3 > &client, int rate)
bool audioClientSetRole(const ComPtr< IAudioClient3 > &client, AudioEndpointRole role)
ComPtr< IMFMediaType > formatToMediaType(QWindowsMediaFoundation &wmf, const QAudioFormat &format)
bool audioClientStop(const ComPtr< IAudioClient3 > &client)
bool audioClientStart(const ComPtr< IAudioClient3 > &client)
std::optional< WAVEFORMATEXTENSIBLE > toWaveFormatExtensible(const QAudioFormat &format)
std::optional< quint32 > getBufferSizeInFrames(const ComPtr< IAudioClient3 > &client)
static UINT32 channelConfigToMask(QAudioFormat::ChannelConfig config)
bool audioClientReset(const ComPtr< IAudioClient3 > &client)
std::optional< AudioClientDevicePeriod > getDevicePeriod(const ComPtr< IAudioClient3 > &client)
std::chrono::duration< long long, std::ratio< 1, 10000000 > > reference_time
QAudioFormat waveFormatExToFormat(const WAVEFORMATEX &in)
bool formatToWaveFormatExtensible(const QAudioFormat &format, WAVEFORMATEXTENSIBLE &wfx)
QAudioFormat::ChannelConfig maskToChannelConfig(UINT32 mask, int count)
void setMCSSForPeriodSize(reference_time periodSize)
QString audioClientErrorString(HRESULT hr)
#define AUDCLNT_E_EFFECT_NOT_AVAILABLE
#define AUDCLNT_E_EFFECT_STATE_READ_ONLY
LONGLONG REFERENCE_TIME