[wdmaudiodev] Re: Vista Core API: Changing audio device sample rate via PKEY_AudioEngine_DeviceFormat does not work

  • From: Mitchell Rundle <mitchr@xxxxxxxxxxxxx>
  • To: "wdmaudiodev@xxxxxxxxxxxxx" <wdmaudiodev@xxxxxxxxxxxxx>
  • Date: Tue, 9 Jan 2007 10:01:41 -0800

You cannot set the device format via the propertyStore alone as this will cause 
the internal state of various audio core components to be out of sync.

You can set the device format at install time via the device inf.  If this is a 
viable solution let me know and I will provide more details.

Regards,
Mitch Rundle
Microsoft

This posting is provided "AS IS" with no warranties, and confers no rights.

-----Original Message-----
From: wdmaudiodev-bounce@xxxxxxxxxxxxx 
[mailto:wdmaudiodev-bounce@xxxxxxxxxxxxx] On Behalf Of 
=?iso-8859-1?Q?Br??ler@xxxxxxxxxxxxx
Sent: Tuesday, January 09, 2007 12:52 AM
To: wdmaudiodev@xxxxxxxxxxxxx
Subject: [wdmaudiodev] Vista Core API: Changing audio device sample rate via 
PKEY_AudioEngine_DeviceFormat does not work

Hi,

for a certain audio device that we are distributing, the default sampling rate 
is not working correctly and needs to be changed. This can be done by the end 
user via control panel:

Vista allows to configure the sampling rate of a sound device:

- Context menu of speaker icon in system tray, menu entry "Recording Devices"
- Choose handset or headset and click on "Properties"
- Go to tab "Advanced"
- By default the sampling rate for a capture device is "1 channel, 16 bit, 
44100 Hz (CD Quality)"

We cannot live with the situation that all users have to do this configuration 
so I was looking for a way to do this programatically.

Vista provides some new API documented in "Core Audio APIs in Windows Vista". A 
property store (IPropertyStore) can now be used to read and (write) audio 
device properties. The documentation reads: "Header file Mmdeviceapi.h defines 
a number of properties of audio endpoint devices. The Windows audio service 
sets the values of these properties. Clients can read these properties, but 
should not set them." Ok, they write: "should not set them". Nevertheless it 
does not read "must not". So I gave it a try.

The PKEY_AudioEngine_DeviceFormat property contains in fact the sampling rate 
settings (in a WAVEFORMATEXTENSIBLE struct) that are configured in the sound 
device control panel. The IPropertyStore interface allows to read and set the 
property as well. But when I do this (you need elevated rights for this) the 
changed settings are not written correctly: As a result the audio device 
control panel will hang when you later on open the respective recording devices 
property tab.

An analysis shows that the sampling rate is stored in registry key 
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture\{device
 GUID}\Properties]. There are two values 
"{f19f064d-082c-4e27-bc73-6882a1bb8e4c},0" and 
"{e4870e26-3cc5-4cd2-ba46-ca0a9a70ed04},0" that are used for storing the 
settings. In fact these values are binaries containing an unknown header and 
the WAVEFORMATEXTENSIBLE struct.

When I change the settings using the control panel, both values will be 
changed. When I change the settings using the property store interface, only 
one of the two values is changed. I consider this as a Vista bug. Later on the 
respective control panel tab is hanging. A reboot of Vista does not help, 
unplug and replug of the device does not help either. The only way to repair 
this is to uninstall the device using the device manager, unplug and replug it. 
Then the device is installed again correctly.

When looking at the registry values I can see that one of the values contains 
the configured sample rate for 16 bit, the other value contains the same 
sampling rate for 32 bit. Knowing this I wrote some test code that changes the 
sampling rate of the device by reading both registry values, decode the 
contained WAVEFORMATEXTENSIBLE struct, adjust the sampling rate if required and 
write it back. This works without problems.

Here is a sample of the not working API (ignoring error handling and clean up):

hr=CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, 
IID_IMMDeviceEnumerator, (void**)&pEnumerator);
hr = pEnumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE, 
&pCollection);
hr=pCollection->GetCount(&count);

for (ULONG i = 0; i < count; i++)
{
    //......
    hr = pCollection->Item(i, &pEndpoint);
    //......
    hr = pEndpoint->OpenPropertyStore(STGM_READWRITE, &pProps);

    PROPVARIANT varConfigBuf;
    PropVariantInit(&varConfigBuf);
    hr = pProps->GetValue(PKEY_AudioEngine_DeviceFormat, &varConfigBuf);
    if( (hr==S_OK) && (varConfigBuf.vt==VT_BLOB) )
    {
        if(varConfigBuf.blob.cbSize>0)
        {
            WAVEFORMATEX 
*pWaveFormatExBlob=(WAVEFORMATEX*)(varConfigBuf.blob.pBlobData);
            WAVEFORMATEXTENSIBLE 
*pWaveFormatExtensibleBlob=(WAVEFORMATEXTENSIBLE*)pWaveFormatExBlob;

            if(bFixSampleRate && (pWaveFormatExBlob->nSamplesPerSec!=8000) )
            {
                pWaveFormatExBlob->nChannels=1;
                pWaveFormatExBlob->nSamplesPerSec=8000;
                
pWaveFormatExBlob->nBlockAlign=pWaveFormatExBlob->nChannels*pWaveFormatExBlob->wBitsPerSample/8;
                
pWaveFormatExBlob->nAvgBytesPerSec=pWaveFormatExBlob->nSamplesPerSec*pWaveFormatExBlob->nBlockAlign;
                
pWaveFormatExtensibleBlob->Samples.wValidBitsPerSample=pWaveFormatExBlob->wBitsPerSample;

                //this works when I run this code with administrative 
privileges; otherwise I get access denied error
                hr=pProps->SetValue(PKEY_AudioEngine_DeviceFormat, 
varConfigBuf);
                if(hr==S_OK)
                {
                    hr=pProps->Commit();
                }
            }
        }
        PropVariantClear(&varConfigBuf);
    }
}

Did anyone try this before?

Best regards
Wolfgang Bruessler
******************

WDMAUDIODEV addresses:
Post message: mailto:wdmaudiodev@xxxxxxxxxxxxx
Subscribe:    mailto:wdmaudiodev-request@xxxxxxxxxxxxx?subject=subscribe
Unsubscribe:  mailto:wdmaudiodev-request@xxxxxxxxxxxxx?subject=unsubscribe
Moderator:    mailto:wdmaudiodev-moderators@xxxxxxxxxxxxx

URL to WDMAUDIODEV page:
http://www.wdmaudiodev.com/

******************

WDMAUDIODEV addresses:
Post message: mailto:wdmaudiodev@xxxxxxxxxxxxx
Subscribe:    mailto:wdmaudiodev-request@xxxxxxxxxxxxx?subject=subscribe
Unsubscribe:  mailto:wdmaudiodev-request@xxxxxxxxxxxxx?subject=unsubscribe
Moderator:    mailto:wdmaudiodev-moderators@xxxxxxxxxxxxx

URL to WDMAUDIODEV page:
http://www.wdmaudiodev.com/

Other related posts: