84 if (!format.isValid())
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;
94 if (format.sampleFormat() == QAudioFormat::Float) {
95 wfx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
96 wfx.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
98 wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
99 wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
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());
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));
141 }
else if (in.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
142 out.setSampleFormat(QAudioFormat::Float);
155 if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &val))) {
156 format.setChannelCount(
int(val));
158 qWarning() <<
"Could not determine channel count from IMFMediaType";
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()));
167 if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &val))) {
168 format.setSampleRate(
int(val));
170 UINT32 bitsPerSample = 0;
171 mediaType->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bitsPerSample);
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);
190 ComPtr<IMFMediaType> mediaType;
192 if (!format.isValid())
195 wmf.mfCreateMediaType(mediaType.GetAddressOf());
197 mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
198 if (format.sampleFormat() == QAudioFormat::Float) {
199 mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float);
201 mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
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);
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;
330 return QSystemError::windowsComString(hr);
336 AudioClientProperties properties{};
337 properties.cbSize =
sizeof(AudioClientProperties);
340 case AudioEndpointRole::MediaPlayback:
341 properties.eCategory = AudioCategory_Media;
343 case AudioEndpointRole::SoundEffect:
344 properties.eCategory = AudioCategory_SoundEffects;
346 case AudioEndpointRole::Accessibility:
347 properties.eCategory = AudioCategory_Speech;
349 case AudioEndpointRole::Other:
350 properties.eCategory = AudioCategory_Other;
353 Q_UNREACHABLE_RETURN(
false);
356 HRESULT hr = client->SetClientProperties(&properties);
358 qWarning() <<
"IAudioClient2::SetClientProperties failed" << audioClientErrorString(hr);
368 std::optional<NativePeriodFrames> nativePeriodFrames,
369 const QUniqueWin32NullHandle &wasapiEventHandle,
370 std::optional<AudioEndpointRole> role)
372 ComPtr<IAudioClient3> audioClient;
374 HRESULT hr = device->Activate(__uuidof(IAudioClient3), CLSCTX_INPROC_SERVER,
nullptr,
375 reinterpret_cast<
void **>(audioClient.GetAddressOf()));
377 qWarning() <<
"Failed to activate audio device" << audioClientErrorString(hr);
386 QWMF::reference_time periodSize = devicePeriods->defaultDuration;
387 if (nativePeriodFrames) {
388 std::chrono::microseconds dur{
389 format.durationForFrames(qToUnderlying(*nativePeriodFrames))
391 if (dur < devicePeriods->minimalDuration)
392 qWarning() <<
"Requested hardware buffer size to small:" << dur <<
"minimal duration"
393 << devicePeriods->minimalDuration;
398 auto fmt = toWaveFormatExtensible(format);
401 auto waveFormat = *fmt;
404 audioClientSetRole(audioClient, *role);
406 constexpr DWORD streamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK
407 | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
408 | AUDCLNT_STREAMFLAGS_RATEADJUST;
410 hr = audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, streamFlags,
412 periodSize.count(), &waveFormat.Format,
416 qWarning() <<
"IAudioClient3::Initialize failed" << audioClientErrorString(hr);
420 std::optional<quint32> framesPerBuffer = getBufferSizeInFrames(audioClient);
421 if (!framesPerBuffer)
423 qsizetype audioClientFrames = *framesPerBuffer;
425 hr = audioClient->SetEventHandle(wasapiEventHandle.get());
427 qWarning() <<
"IAudioClient3::SetEventHandle failed" << audioClientErrorString(hr);
432 std::move(audioClient),