Cihaz Olayları (Çekirdek Ses API'leri)
Cihaz olayı, istemcilere ses uç noktası cihazının sistemdeki durumundaki bir değişikliği bildirir. Aşağıda cihaz olaylarının örnekleri verilmiştir:
- Kullanıcı, Cihaz Yöneticisi'nden veya Windows multimedya denetim masasından Mmsys.cplbir ses uç noktası cihazını etkinleştirir veya devre dışı bırakır.
- Kullanıcı sisteme bir ses bağdaştırıcısı ekler veya bir ses bağdaştırıcısını sistemden kaldırır.
- Kullanıcı, bir ses uç noktası cihazını jak iletişim durumu algılamalı bir ses jakına takar veya ses uç noktası cihazını böyle bir jaktan kaldırır.
- Kullanıcı, bir cihaza atanan cihaz rolü değiştirir.
- Cihazın özelliğinin değeri değişir.
Ses bağdaştırıcısının eklenmesi veya kaldırılması, bağdaştırıcıya bağlanan tüm ses uç noktası cihazları için cihaz olayları oluşturur. Önceki listedeki ilk dört öğe, cihaz durumu değişikliklerine örnektir. Ses uç noktası cihazlarının cihaz durumları hakkında daha fazla bilgi için bkz. sabitler DEVICE_STATE_XXX. Jack-presence algılama hakkında daha fazla bilgi için bkz. Ses Uç Noktası Cihazları.
Bir istemci, cihaz olayları gerçekleştiğinde bildirim almak için kaydolabilir. Bu bildirimlere yanıt olarak istemci, belirli bir cihazı kullanma şeklini dinamik olarak değiştirebilir veya belirli bir amaç için kullanılacak farklı bir cihaz seçebilir.
Örneğin, bir uygulama bir dizi USB hoparlör aracılığıyla ses parçası çalıyorsa ve kullanıcı hoparlörlerin USB bağlayıcısının bağlantısını keserse, uygulama bir cihaz olayı bildirimi alır. Olaya yanıt olarak, uygulama bir dizi masaüstü hoparlörünün sistem ana kartındaki tümleşik ses bağdaştırıcısına bağlı olduğunu algılarsa, uygulama masaüstü hoparlörleri aracılığıyla ses parçasını yürütmeye devam edebilir. Bu örnekte, USB hoparlörlerden masaüstü hoparlörlere geçiş, kullanıcının uygulamayı açıkça yeniden yönlendirerek müdahale etmesine gerek kalmadan otomatik olarak gerçekleşir.
Cihaz bildirimlerini almak üzere kaydolmak için istemci, IMMDeviceEnumerator::RegisterEndpointNotificationCallback yöntemini çağırır. İstemci artık bildirim gerektirmediğinde, IMMDeviceEnumerator::UnregisterEndpointNotificationCallback yöntemini çağırarak bunları iptal eder. Her iki yöntem de IMMNotificationClient arabirim örneğine yönelik bir işaretçi olan pClientadlı bir giriş parametresi alır.
IMMNotificationClient arabirimi bir istemci tarafından uygulanır. Arabirim, her biri belirli bir cihaz olayı türü için geri çağırma yordamı görevi görecek çeşitli yöntemler içerir. Ses uç noktası cihazında bir cihaz olayı gerçekleştiğinde, MMDevice modülü şu anda cihaz-olay bildirimlerini almak üzere kayıtlı olan her istemcinin IMMNotificationClient arabiriminde uygun yöntemi çağırır. Bu çağrılar olayın açıklamasını istemcilere iletir. Daha fazla bilgi için bkz. IMMNotificationClient Arabirimi.
Cihaz olay bildirimlerini almak için kaydedilen bir istemci, sistemdeki tüm ses uç noktası cihazlarında gerçekleşen tüm cihaz olay türlerinin bildirimlerini alır. İstemci yalnızca belirli olay türleriyle veya belirli cihazlarda ilgileniyorsa, IMMNotificationClient uygulamasındaki yöntemler olayları uygun şekilde filtrelemelidir.
Windows SDK'sı, IMMNotificationClient Arabirimiiçin çeşitli uygulamalar içeren örnekler sağlar. Daha fazla bilgi için bkz. Çekirdek Ses API'lerini Kullanan sdk örneklerini.
Aşağıdaki kod örneği, IMMNotificationClient arabiriminin olası bir uygulamasını gösterir:
//-----------------------------------------------------------
// 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;
}
Yukarıdaki kod örneğindeki CMMNotificationClient sınıfı, IMMNotificationClient arabiriminin bir uygulamasıdır. IMMNotificationClientIUnknown'den devraldığından, sınıf tanımı AddRef , Releaseve QueryInterfaceIUnknown yöntemlerinin uygulamalarını içerir. Sınıf tanımındaki kalan genel yöntemler IMMNotificationClient arabirimine özgü. Bu yöntemler şunlardır:
- OnDefaultDeviceChanged, kullanıcı bir ses uç noktası cihazının cihaz rolünü değiştirdiğinde çağrılır.
- OnDeviceAdded, kullanıcı sisteme bir ses uç noktası cihazı eklediğinde çağrılır.
- OnDeviceRemoved, kullanıcı sistemden bir ses uç noktası cihazı kaldırdığında çağrılır.
- OnDeviceStateChanged, bir ses uç noktası cihazının cihaz durumu değiştiğinde çağrılır. (Cihaz durumları hakkında daha fazla bilgi için bkz. DEVICE_STATE_ XXX Sabitleri.)
- OnPropertyValueChanged, bir ses uç noktası cihazının özelliğinin değeri değiştiğinde çağrılır.
Bu yöntemlerin her biri pwstrDeviceId bir giriş parametresi alır ve bu bir uç nokta kimliği dizesinin işaretçisidir. Dize, cihaz olayının gerçekleştiği ses uç noktası cihazını tanımlar.
Yukarıdaki kod örneğinde _PrintDeviceName, CMMNotificationClient sınıfında cihazın kolay adını yazdıran özel bir yöntemdir. _PrintDeviceName, giriş parametresi olarak uç nokta kimliği dizesini alır. Dizeyi IMMDeviceEnumerator::GetDevice yöntemine geçirir. GetDevice, cihazı temsil etmek için bir uç nokta cihaz nesnesi oluşturur ve bu nesneye IMMDevice arabirimini sağlar. Ardından _PrintDeviceName IMMDevice::OpenPropertyStore yöntemini çağırarak IPropertyStore arabirimini cihazın özellik deposuna alır. Son olarak, _PrintDeviceName cihazın kolay ad özelliğini almak için IPropertyStore::GetItem yöntemini çağırır. IPropertyStorehakkında daha fazla bilgi için Windows SDK belgelerine bakın.
cihaz olaylarına ek olarak, istemciler ses oturumu olaylarının ve uç nokta birimi olaylarının bildirimlerini almak için kaydolabilir. Daha fazla bilgi için bkz. IAudioSessionEvents Arabirimi ve IAudioEndpointVolumeCallback Arabirimi.
İlgili konular