Reputation: 568
I'm developing audio code for a program that needs to be able to record and playback on a variety of devices, some of them high end, with a variety of different wav and AIFF formats. I expected to be able to use the WASAPI library, but I'm hitting some major problems. The biggest one right now is that, as far as I can tell, devices are only allowed to play streams that are in exactly matching formats.
Here's what I'm doing- I set the device (here I'm just getting the default console device) with:
hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pPlaybackDevice);
I activate the device with:
hr = pPlaybackDevice->Activate( __uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pTakeAudioClient);
Then I check the mix format with:
hr = pTakeAudioClient->GetMixFormat(&pWaveFormatEx);
However, if I use a different format when calling Initialize:
hr = pTakeAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,hnsRequestedDuration, 0, pAnotherWaveFormatEx,NULL);
I get an error. It seems like the file absolutely has to be in the format returned by GetMixFormat. If I call IsFormatSupported to find out what formats I can submit:
hr = pTakeAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &waveFormatEx, &pAnotherWaveFormatEx);
I get E_INVALIDARG
, even if both structures are exactly the same. According to the WASAPI documents, that return comes when "Parameter ShareMode is a value other than AUDCLNT_SHAREMODE_SHARED
or AUDCLNT_SHAREMODE_EXCLUSIVE
." I am passing AUDCLNT_SHAREMODE_SHARED
. This appears to be an error in the documentation.
The mystery deepens when, for the sake of experimentation, I try:
hr = pTakeAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &waveFormatEx, NULL);
The error return is 0x8889000e
- I have not been able to find a reference to that error.
Any help you can provide will be received most gratefully, even if it is "use MMSystem". I would have started with MMSystem except that we need to be able to control the playback device when there are multiple devices.
Upvotes: 4
Views: 5323
Reputation: 404
I know this is a very old thread, but this situation has apparently been improved, although the option may have been available at the time the question was asked, I'm not sure (and the documentation, like most things Microsoft, is usually not very helpful).
Anyway, in my experience, assuming you want to use standard PCM audio, the critical factor seems to be the sampling rate you're requesting. Most sound cards seemingly won't accept anything different in this respect from what's reported in their "mix format" (this is for shared audio mode). So, either you can accept the card's sampling rate, and send everything in that sampling rate, if that's a viable option for you, or you can request the audio driver to insert a converter in your output chain as necessary.
The easiest route is to use the AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM flag when issuing your Initialize()
call, which will do just what I said and convert whatever source audio format you requested to the supported format of the device.
It seems it's even possible to change the SR on the fly by using IAudioClockAdjustment::SetSampleRate, but I've never tried this myself.. Take a look at the different flags in this page for more info.
Upvotes: 2
Reputation: 69632
0x8889000e
= AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED
(HRESULT
reading utility), which says pretty much about the reason: this format is not available for exclusive mode audio client. And you perhaps don't need it exclusive, shared mode might be good enough. Anyway, to record and playback via WASAPI you will need to negotiate a format which is supported by hardware, which is typically one of PCM audio formats.
To convert between formats you have several APIs out there (ACM, DirectShow, Media Foundation). Some APIs like DirectShow and Media Foundation will be able to both auto-convert played data to supported format, and also play it back through an audio device.
Upvotes: 2