Apparaatevenementen (Core Audio-API's)
Een apparaat-gebeurtenis meldt clients van een wijziging in de status van een audio-eindpuntapparaat in het systeem. Hier volgen enkele voorbeelden van apparaatevenementen:
- De gebruiker schakelt een audio-eindpuntapparaat in of uit vanuit Apparaatbeheer of vanuit het Configuratiescherm van Windows multimedia, Mmsys.cpl.
- De gebruiker voegt een audioadapter toe aan het systeem of verwijdert een audioadapter uit het systeem.
- De gebruiker sluit een audio-eindpuntapparaat aan op een audioaansluiting met detectie van jack-presence of verwijdert een audio-eindpuntapparaat van een dergelijke aansluiting.
- De gebruiker wijzigt de apparaatrol die is toegewezen aan een apparaat.
- De waarde van een eigenschap van een apparaat verandert.
Door het toevoegen of verwijderen van een audioadapter worden apparaatevenementen gegenereerd voor alle audio-eindpuntapparaten die verbinding maken met de adapter. De eerste vier items in de voorgaande lijst zijn voorbeelden van apparaatstatuswijzigingen. Zie DEVICE_STATE_XXX Constantsvoor meer informatie over de apparaatstatussen van audio-eindpuntapparaten. Zie Audio-eindpuntapparatenvoor meer informatie over detectie van jack-presence.
Een client kan zich registreren om op de hoogte te worden gesteld wanneer apparaat gebeurtenissen plaatsvinden. Als reactie op deze meldingen kan de client dynamisch de manier wijzigen waarop het een bepaald apparaat gebruikt of een ander apparaat selecteren dat voor een bepaald doel moet worden gebruikt.
Als een toepassing bijvoorbeeld een audiospoor afspeelt via een set USB-luidsprekers en de gebruiker de luidsprekers loskoppelt van de USB-connector, ontvangt de toepassing een melding over apparaatgebeurtenissen. Als de toepassing detecteert dat een set desktopluidsprekers is aangesloten op de geïntegreerde audioadapter op het systeem moederbord, kan de toepassing het afspelen van het audiospoor hervatten via de desktopluidsprekers. In dit voorbeeld vindt de overgang van USB-luidsprekers naar desktopluidsprekers automatisch plaats, zonder dat de gebruiker hoeft in te grijpen door de toepassing expliciet om te leiden.
Als u zich wilt registreren voor het ontvangen van apparaatmeldingen, roept een client de methode IMMDeviceEnumerator::RegisterEndpointNotificationCallback aan methode. Wanneer de client geen meldingen meer nodig heeft, annuleert deze door de methode IMMDeviceEnumerator::UnregisterEndpointNotificationCallback methode aan te roepen. Beide methoden gebruiken een invoerparameter, met de naam pClient, die een aanwijzer is naar een IMMNotificationClient interface-exemplaar.
De IMMNotificationClient interface wordt geïmplementeerd door een client. De interface bevat verschillende methoden, die elk dienen als een callback-routine voor een bepaald type apparaat gebeurtenis. Wanneer een apparaatgebeurtenis optreedt in een audio-eindpuntapparaat, roept de MMDevice-module de juiste methode aan in de IMMNotificationClient interface van elke client die momenteel is geregistreerd voor het ontvangen van apparaatgebeurtenismeldingen. Deze aanroepen geven een beschrijving van de gebeurtenis door aan de clients. Zie IMMNotificationClient Interfacevoor meer informatie.
Een client die is geregistreerd voor het ontvangen van apparaatgebeurtenismeldingen ontvangt meldingen van alle typen apparaatgebeurtenissen die plaatsvinden op alle audio-eindpuntapparaten in het systeem. Als een client alleen geïnteresseerd is in bepaalde gebeurtenistypen of op bepaalde apparaten, moeten de methoden in de IMMNotificationClient implementatie de gebeurtenissen op de juiste wijze filteren.
De Windows SDK biedt voorbeelden met verschillende implementaties voor de IMMNotificationClient Interface. Zie SDK-voorbeelden die gebruikmaken van de Core Audio-API'svoor meer informatie.
In het volgende codevoorbeeld ziet u een mogelijke implementatie van de IMMNotificationClient interface:
//-----------------------------------------------------------
// Example implementation of IMMNotificationClient interface.
// When the status of audio endpoint devices change, the
// MMDevice module calls these methods to notify the client.
//-----------------------------------------------------------
#define SAFE_RELEASE(punk) \
if ((punk) != NULL) \
{ (punk)->Release(); (punk) = NULL; }
class CMMNotificationClient : public IMMNotificationClient
{
LONG _cRef;
IMMDeviceEnumerator *_pEnumerator;
// Private function to print device-friendly name
HRESULT _PrintDeviceName(LPCWSTR pwstrId);
public:
CMMNotificationClient() :
_cRef(1),
_pEnumerator(NULL)
{
}
~CMMNotificationClient()
{
SAFE_RELEASE(_pEnumerator)
}
// IUnknown methods -- AddRef, Release, and QueryInterface
ULONG STDMETHODCALLTYPE AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG STDMETHODCALLTYPE Release()
{
ULONG ulRef = InterlockedDecrement(&_cRef);
if (0 == ulRef)
{
delete this;
}
return ulRef;
}
HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid, VOID **ppvInterface)
{
if (IID_IUnknown == riid)
{
AddRef();
*ppvInterface = (IUnknown*)this;
}
else if (__uuidof(IMMNotificationClient) == riid)
{
AddRef();
*ppvInterface = (IMMNotificationClient*)this;
}
else
{
*ppvInterface = NULL;
return E_NOINTERFACE;
}
return S_OK;
}
// Callback methods for device-event notifications.
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(
EDataFlow flow, ERole role,
LPCWSTR pwstrDeviceId)
{
char *pszFlow = "?????";
char *pszRole = "?????";
_PrintDeviceName(pwstrDeviceId);
switch (flow)
{
case eRender:
pszFlow = "eRender";
break;
case eCapture:
pszFlow = "eCapture";
break;
}
switch (role)
{
case eConsole:
pszRole = "eConsole";
break;
case eMultimedia:
pszRole = "eMultimedia";
break;
case eCommunications:
pszRole = "eCommunications";
break;
}
printf(" -->New default device: flow = %s, role = %s\n",
pszFlow, pszRole);
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId)
{
_PrintDeviceName(pwstrDeviceId);
printf(" -->Added device\n");
return S_OK;
};
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId)
{
_PrintDeviceName(pwstrDeviceId);
printf(" -->Removed device\n");
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(
LPCWSTR pwstrDeviceId,
DWORD dwNewState)
{
char *pszState = "?????";
_PrintDeviceName(pwstrDeviceId);
switch (dwNewState)
{
case DEVICE_STATE_ACTIVE:
pszState = "ACTIVE";
break;
case DEVICE_STATE_DISABLED:
pszState = "DISABLED";
break;
case DEVICE_STATE_NOTPRESENT:
pszState = "NOTPRESENT";
break;
case DEVICE_STATE_UNPLUGGED:
pszState = "UNPLUGGED";
break;
}
printf(" -->New device state is DEVICE_STATE_%s (0x%8.8x)\n",
pszState, dwNewState);
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(
LPCWSTR pwstrDeviceId,
const PROPERTYKEY key)
{
_PrintDeviceName(pwstrDeviceId);
printf(" -->Changed device property "
"{%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x}#%d\n",
key.fmtid.Data1, key.fmtid.Data2, key.fmtid.Data3,
key.fmtid.Data4[0], key.fmtid.Data4[1],
key.fmtid.Data4[2], key.fmtid.Data4[3],
key.fmtid.Data4[4], key.fmtid.Data4[5],
key.fmtid.Data4[6], key.fmtid.Data4[7],
key.pid);
return S_OK;
}
};
// Given an endpoint ID string, print the friendly device name.
HRESULT CMMNotificationClient::_PrintDeviceName(LPCWSTR pwstrId)
{
HRESULT hr = S_OK;
IMMDevice *pDevice = NULL;
IPropertyStore *pProps = NULL;
PROPVARIANT varString;
CoInitialize(NULL);
PropVariantInit(&varString);
if (_pEnumerator == NULL)
{
// Get enumerator for audio endpoint devices.
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
NULL, CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator),
(void**)&_pEnumerator);
}
if (hr == S_OK)
{
hr = _pEnumerator->GetDevice(pwstrId, &pDevice);
}
if (hr == S_OK)
{
hr = pDevice->OpenPropertyStore(STGM_READ, &pProps);
}
if (hr == S_OK)
{
// Get the endpoint device's friendly-name property.
hr = pProps->GetValue(PKEY_Device_FriendlyName, &varString);
}
printf("----------------------\nDevice name: \"%S\"\n"
" Endpoint ID string: \"%S\"\n",
(hr == S_OK) ? varString.pwszVal : L"null device",
(pwstrId != NULL) ? pwstrId : L"null ID");
PropVariantClear(&varString);
SAFE_RELEASE(pProps)
SAFE_RELEASE(pDevice)
CoUninitialize();
return hr;
}
De CMMNotificationClient-klasse in het voorgaande codevoorbeeld is een implementatie van de IMMNotificationClient interface. Omdat IMMNotificationClient overgenomen van IUnknown-, bevat de klassedefinitie implementaties van de IUnknown methoden AddRef, Releaseen QueryInterface. De resterende openbare methoden in de klassedefinitie zijn specifiek voor de IMMNotificationClient interface. Deze methoden zijn:
- OnDefaultDeviceChanged, die wordt aangeroepen wanneer de gebruiker de apparaatrol van een audio-eindpuntapparaat wijzigt.
- OnDeviceAdded, die wordt aangeroepen wanneer de gebruiker een audio-eindpuntapparaat toevoegt aan het systeem.
- OnDeviceRe verplaatst, die wordt aangeroepen wanneer de gebruiker een audio-eindpuntapparaat van het systeem verwijdert.
- OnDeviceStateChanged, die wordt aangeroepen wanneer de apparaatstatus van een audio-eindpuntapparaat wordt gewijzigd. (Zie DEVICE_STATE_ XXX Constantsvoor meer informatie over apparaatstatussen.)
- OnPropertyValueChanged, die wordt aangeroepen wanneer de waarde van een eigenschap van een audio-eindpuntapparaat verandert.
Elk van deze methoden gebruikt een invoerparameter, pwstrDeviceId, die een aanwijzer is naar een eindpunt-id-tekenreeks. De tekenreeks identificeert het audio-eindpuntapparaat waarin de apparaatgebeurtenis heeft plaatsgevonden.
In het voorgaande codevoorbeeld is _PrintDeviceName een privémethode in de klasse CMMNotificationClient waarmee de beschrijvende naam van het apparaat wordt afgedrukt. _PrintDeviceName gebruikt de tekenreeks voor de eindpunt-id als invoerparameter. De tekenreeks wordt doorgegeven aan de methode IMMDeviceEnumerator::GetDevice. GetDevice- maakt een eindpuntapparaatobject dat het apparaat vertegenwoordigt en de IMMDevice-interface voor dat object biedt. Vervolgens roept _PrintDeviceName de IMMDevice::OpenPropertyStore methode aan om de IPropertyStore--interface op te halen naar het eigenschappenarchief van het apparaat. Ten slotte roept _PrintDeviceName de methode IPropertyStore::GetItem aan om de eigenschap beschrijvende naam van het apparaat te verkrijgen. Zie de Windows SDK-documentatie voor meer informatie over IPropertyStore.
Naast apparaatgebeurtenissen kunnen clients zich registreren voor het ontvangen van meldingen van audiosessiegebeurtenissen en eindpuntvolumegebeurtenissen. Zie IAudioSessionEvents Interface en IAudioEndpointVolumeCallback Interfacevoor meer informatie.
Verwante onderwerpen