83 if (!format.isValid())
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;
93 if (format.sampleFormat() == QAudioFormat::Float) {
94 wfx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
95 wfx.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
97 wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
98 wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
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());
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));
140 }
else if (in.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
141 out.setSampleFormat(QAudioFormat::Float);
154 if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &val))) {
155 format.setChannelCount(
int(val));
157 qWarning() <<
"Could not determine channel count from IMFMediaType";
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()));
166 if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &val))) {
167 format.setSampleRate(
int(val));
169 UINT32 bitsPerSample = 0;
170 mediaType->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bitsPerSample);
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);
189 ComPtr<IMFMediaType> mediaType;
191 if (!format.isValid())
194 wmf.mfCreateMediaType(mediaType.GetAddressOf());
196 mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
197 if (format.sampleFormat() == QAudioFormat::Float) {
198 mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float);
200 mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
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);
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;
329 return QSystemError::windowsComString(hr);
335 AudioClientProperties properties{};
336 properties.cbSize =
sizeof(AudioClientProperties);
339 case AudioEndpointRole::MediaPlayback:
340 properties.eCategory = AudioCategory_Media;
342 case AudioEndpointRole::SoundEffect:
343 properties.eCategory = AudioCategory_SoundEffects;
345 case AudioEndpointRole::Accessibility:
346 properties.eCategory = AudioCategory_Speech;
348 case AudioEndpointRole::Other:
349 properties.eCategory = AudioCategory_Other;
352 Q_UNREACHABLE_RETURN(
false);
355 HRESULT hr = client->SetClientProperties(&properties);
357 qWarning() <<
"IAudioClient2::SetClientProperties failed" << audioClientErrorString(hr);
367 std::optional<qsizetype> hardwareBufferFrames,
368 const QUniqueWin32NullHandle &wasapiEventHandle,
369 std::optional<AudioEndpointRole> role)
371 ComPtr<IAudioClient3> audioClient;
373 HRESULT hr = device->Activate(__uuidof(IAudioClient3), CLSCTX_INPROC_SERVER,
nullptr,
374 reinterpret_cast<
void **>(audioClient.GetAddressOf()));
376 qWarning() <<
"Failed to activate audio device" << audioClientErrorString(hr);
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;
395 auto fmt = toWaveFormatExtensible(format);
398 auto waveFormat = *fmt;
401 audioClientSetRole(audioClient, *role);
403 constexpr DWORD streamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK
404 | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
405 | AUDCLNT_STREAMFLAGS_RATEADJUST;
407 hr = audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, streamFlags,
408 reference_time(periodSize).count(),
409 reference_time(periodSize).count(),
410 &waveFormat.Format,
nullptr);
413 qWarning() <<
"IAudioClient3::Initialize failed" << audioClientErrorString(hr);
417 std::optional<quint32> framesPerBuffer = getBufferSizeInFrames(audioClient);
418 if (!framesPerBuffer)
420 qsizetype audioClientFrames = *framesPerBuffer;
422 hr = audioClient->SetEventHandle(wasapiEventHandle.get());
424 qWarning() <<
"IAudioClient3::SetEventHandle failed" << audioClientErrorString(hr);
429 std::move(audioClient),