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