Vista Core API: Changing audio device sample rate

原文來自:

http://www.freelists.org/post/wdmaudiodev/Vista-Core-API-Changing-audio-device-sample-rate-via-PKEY-AudioEngine-DeviceFormat-does-not-work,1

 

Vista Core API: Changing audio device sample rate via PKEY_AudioEngine_DeviceFormat does not work

 

 

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);
    }
}

發佈了5 篇原創文章 · 獲贊 5 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章