| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- //-------------------------------------------------------------------------
- // File: AecKsBinder.cpp
- //
- // Desciption: Definition of audio devices binding functions
- //
- // Copyright (c) 2004-2006, Microsoft Corporation. All rights reserved.
- //---------------------------------------------------------------------------
- #include "stdafx.h"
- #include "AecKsbinder.h"
- #include "strsafe.h"
- #include "functiondiscoverykeys.h" // PKEY_Device_FriendlyName
- #ifndef IF_FAILED_JUMP
- #define IF_FAILED_JUMP(hr, label) if(FAILED(hr)) goto label;
- #endif
- #ifndef IF_FAILED_RETURN
- #define IF_FAILED_RETURN(hr) if(FAILED(hr)) return hr;
- #endif
- ///////////////////////////////////////////////////////////////////////////
- //
- // Function:
- // DeviceBindTo
- //
- // Description:
- // Bind device to an IAudioClient interface.
- //
- // Parameters:
- // eDataFlow: eRender for render device, eCapture for capture device
- // iDevIdx: Index of device in the enumeration list. If it is -1, use default device
- // ppVoid: pointer pointer to IAudioClient interface.
- // ppszEndpointDeviceId: Device ID. Caller is responsible for freeing memeory
- // using CoTaskMemoryFree. If can be NULL if called doesn't need this info.
- //
- // Return:
- // S_OK if successful
- //
- ///////////////////////////////////////////////////////////////////////////////
- HRESULT DeviceBindTo(
- EDataFlow eDataFlow, // eCapture/eRender
- INT iDevIdx, // Device Index. -1 - default device.
- IAudioClient **ppAudioClient, // pointer pointer to IAudioClient interface
- IAudioEndpointVolume **ppEndpointVolume,
- WCHAR** ppszEndpointDeviceId) // Device ID. Need to be freed in caller with CoTaskMemoryFree if it is not NULL
- {
- HRESULT hResult;
- CComPtr<IMMDeviceEnumerator> spEnumerator;
- CComPtr<IMMDeviceCollection> spEndpoints;
- CComPtr<IMMDevice> spDevice;
- WCHAR *pszDeviceId = NULL;
- if (ppAudioClient == NULL)
- return E_POINTER;
-
- *ppAudioClient = NULL;
- hResult = spEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));
- IF_FAILED_JUMP(hResult, Exit);
- // use default device
- if (iDevIdx < 0 )
- {
- hResult = spEnumerator->GetDefaultAudioEndpoint(eDataFlow, eConsole, &spDevice);
- IF_FAILED_JUMP(hResult, Exit);
- }else{
- // User selected device
- hResult = spEnumerator->EnumAudioEndpoints(eDataFlow, DEVICE_STATE_ACTIVE, &spEndpoints);
- IF_FAILED_JUMP(hResult, Exit);
- hResult = spEndpoints->Item(iDevIdx, &spDevice);
- IF_FAILED_JUMP(hResult, Exit);
- }
- // get device ID and format
- hResult = spDevice->GetId(&pszDeviceId);
- IF_FAILED_JUMP(hResult, Exit);
- // Active device
- hResult = spDevice->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)ppAudioClient);
- IF_FAILED_JUMP(hResult, Exit);
- if (ppEndpointVolume)
- {
- hResult = spDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (void **)ppEndpointVolume);
- IF_FAILED_JUMP(hResult, Exit);
- }
-
- Exit:
- if (ppszEndpointDeviceId)
- *ppszEndpointDeviceId = pszDeviceId;
- else if (pszDeviceId)
- CoTaskMemFree(pszDeviceId);
-
- return hResult;
- }
- ///////////////////////////////////////////////////////////////////////////////
- //
- // Function:
- // GetDeviceNum
- //
- // Description:
- // Enumerate audio device and return the device information.
- //
- // Parameters:
- // eDataFlow: eRender for render device, eCapture for capture device
- // uDevCount: Number of device
- //
- // Return:
- // S_OK if successful
- //
- ///////////////////////////////////////////////////////////////////////////////
- HRESULT GetDeviceNum(EDataFlow eDataFlow, UINT &uDevCount)
- {
- HRESULT hResult = S_OK;
- CComPtr<IMMDeviceEnumerator> spEnumerator;
- CComPtr<IMMDeviceCollection> spEndpoints;
- hResult = spEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));
- IF_FAILED_RETURN(hResult);
- hResult = spEnumerator->EnumAudioEndpoints(eDataFlow, DEVICE_STATE_ACTIVE, &spEndpoints);
- IF_FAILED_RETURN(hResult);
- hResult = spEndpoints->GetCount(&uDevCount);
- IF_FAILED_RETURN(hResult);
- return hResult;
- }
- ///////////////////////////////////////////////////////////////////////////
- //
- // Function:
- // EnumDevice
- //
- // Description:
- // Enumerate audio device and return the device information.
- //
- // Parameters:
- // eDataFlow: eRender for render device, eCapture for capture device
- // uNumElements: Size of audio device info structure array.
- // pDevicInfo: device info structure array. Caller is responsible to allocate and free
- // memory. The array size is specified by uNumElements.
- //
- // Return:
- // S_OK if successful
- //
- ///////////////////////////////////////////////////////////////////////////////
- HRESULT EnumDevice(EDataFlow eDataFlow, UINT uNumElements, AUDIO_DEVICE_INFO *pDevicInfo)
- {
- HRESULT hResult = S_OK;
- TCHAR* pszDeviceId = NULL;
- PROPVARIANT value;
- UINT index, dwCount;
- bool IsMicArrayDevice;
- CComPtr<IMMDeviceEnumerator> spEnumerator;
- CComPtr<IMMDeviceCollection> spEndpoints;
- hResult = spEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));
- IF_FAILED_JUMP(hResult, Exit);
- hResult = spEnumerator->EnumAudioEndpoints(eDataFlow, DEVICE_STATE_ACTIVE, &spEndpoints);
- IF_FAILED_JUMP(hResult, Exit);
- hResult = spEndpoints->GetCount(&dwCount);
- IF_FAILED_JUMP(hResult, Exit);
- if (dwCount != uNumElements)
- return E_INVALIDARG;
- ZeroMemory(pDevicInfo, sizeof(AUDIO_DEVICE_INFO)*uNumElements);
-
- for (index = 0; index < dwCount; index++)
- {
- CComPtr<IMMDevice> spDevice;
- CComPtr<IPropertyStore> spProperties;
- PropVariantInit(&value);
- hResult = spEndpoints->Item(index, &spDevice);
- IF_FAILED_JUMP(hResult, Exit);
-
- hResult = spDevice->GetId(&pszDeviceId);
- IF_FAILED_JUMP(hResult, Exit);
- hResult = spDevice->OpenPropertyStore(STGM_READ, &spProperties);
- IF_FAILED_JUMP(hResult, Exit);
- hResult = spProperties->GetValue(PKEY_Device_FriendlyName, &value);
- IF_FAILED_JUMP(hResult, Exit);
- EndpointIsMicArray(spDevice, IsMicArrayDevice);
- StringCchCopy(pDevicInfo[index].szDeviceID, MAX_STR_LEN-1, pszDeviceId);
- StringCchCopy(pDevicInfo[index].szDeviceName, MAX_STR_LEN-1, value.pszVal);
- pDevicInfo[index].bIsMicArrayDevice = IsMicArrayDevice;
-
- PropVariantClear(&value);
- CoTaskMemFree(pszDeviceId);
- pszDeviceId = NULL;
- }
- Exit:
- return hResult;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Function:
- // DeviceIsMicArray
- //
- // Description:
- // Determines if a given IMMDevice is a microphone array by device ID
- //
- // Returns:
- // S_OK on success
- ///////////////////////////////////////////////////////////////////////////////
- HRESULT DeviceIsMicArray(wchar_t szDeviceId[], bool &bIsMicArray)
- {
- HRESULT hr = S_OK;
-
- if (szDeviceId == NULL)
- return E_INVALIDARG;
-
- CComPtr<IMMDeviceEnumerator> spEnumerator;
- CComPtr<IMMDevice> spDevice;
- hr = spEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));
- IF_FAILED_RETURN(hr);
- hr = spEnumerator->GetDevice(szDeviceId, &spDevice);
- IF_FAILED_RETURN(hr);
- hr = EndpointIsMicArray(spDevice, bIsMicArray);
- return hr;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Function:
- // EndpointIsMicArray
- //
- // Description:
- // Determines if a given IMMDevice is a microphone array by Endpoint pointer
- //
- // Returns:
- // S_OK on success
- ///////////////////////////////////////////////////////////////////////////////
- HRESULT EndpointIsMicArray(IMMDevice* pEndpoint, bool & isMicrophoneArray)
- {
- if (pEndpoint == NULL)
- return E_POINTER;
- GUID subType = {0};
- HRESULT hr = GetJackSubtypeForEndpoint(pEndpoint, &subType);
- isMicrophoneArray = (subType == KSNODETYPE_MICROPHONE_ARRAY) ? true : false;
- return hr;
- }// EndpointIsMicArray()
- ///////////////////////////////////////////////////////////////////////////////
- // Function:
- // GetJackSubtypeForEndpoint
- //
- // Description:
- // Gets the subtype of the jack that the specified endpoint device
- // is plugged into. e.g. if the endpoint is for an array mic, then
- // we would expect the subtype of the jack to be
- // KSNODETYPE_MICROPHONE_ARRAY
- //
- // Return:
- // S_OK if successful
- //
- ///////////////////////////////////////////////////////////////////////////////
- HRESULT GetJackSubtypeForEndpoint(IMMDevice* pEndpoint, GUID* pgSubtype)
- {
- HRESULT hr = S_OK;
- if (pEndpoint == NULL)
- return E_POINTER;
-
- CComPtr<IDeviceTopology> spEndpointTopology;
- CComPtr<IConnector> spPlug;
- CComPtr<IConnector> spJack;
- CComQIPtr<IPart> spJackAsPart;
- // Get the Device Topology interface
- hr = pEndpoint->Activate(__uuidof(IDeviceTopology), CLSCTX_INPROC_SERVER,
- NULL, (void**)&spEndpointTopology);
- IF_FAILED_JUMP(hr, Exit);
- hr = spEndpointTopology->GetConnector(0, &spPlug);
- IF_FAILED_JUMP(hr, Exit);
- hr = spPlug->GetConnectedTo(&spJack);
- IF_FAILED_JUMP(hr, Exit);
- spJackAsPart = spJack;
- hr = spJackAsPart->GetSubType(pgSubtype);
- Exit:
- return hr;
- }//GetJackSubtypeForEndpoint()
- ///////////////////////////////////////////////////////////////////////////////
- // GetInputJack() -- Gets the IPart interface for the input jack on the
- // specified device.
- ///////////////////////////////////////////////////////////////////////////////
- HRESULT GetInputJack(IMMDevice* pDevice, CComPtr<IPart>& spPart)
- {
- HRESULT hr = S_OK;
- if (pDevice == NULL)
- return E_POINTER;
- CComPtr<IDeviceTopology> spTopology;
- CComPtr<IConnector> spPlug;
- CComPtr<IConnector> spJack = NULL;
- // Get the Device Topology interface
- hr = pDevice->Activate(__uuidof(IDeviceTopology),
- CLSCTX_INPROC_SERVER, NULL,
- reinterpret_cast<void**>(&spTopology));
- IF_FAILED_RETURN(hr);
- hr = spTopology->GetConnector(0, &spPlug);
- IF_FAILED_RETURN(hr);
- hr = spPlug->GetConnectedTo(&spJack);
- IF_FAILED_RETURN(hr);
- // QI for the part
- spPart = spJack;
- if (spPart == NULL)
- return E_NOINTERFACE;
-
- return hr;
- }// GetInputJack()
- ///////////////////////////////////////////////////////////////////////////////
- // Function:
- // GetMicArrayGeometry()
- //
- // Description:
- // Obtains the geometry for the specified mic array.
- //
- // Parameters: szDeviceId -- The requested device ID, which can be obtained
- // from calling EnumAudioCaptureDevices()
- //
- // ppGeometry -- Address of the pointer to the mic-array gemometry.
- // Caller is ressponsible for calling CoTaskMemFree()
- // if the call is successfull.
- //
- // cbSize -- size of the geometry structure
- //
- // Returns: S_OK on success
- ///////////////////////////////////////////////////////////////////////////////
- HRESULT GetMicArrayGeometry(wchar_t szDeviceId[], KSAUDIO_MIC_ARRAY_GEOMETRY** ppGeometry, ULONG& cbSize)
- {
- HRESULT hr = S_OK;
- if (szDeviceId == NULL)
- return E_INVALIDARG;
- if (ppGeometry == NULL)
- return E_POINTER;
-
- cbSize = 0;
- CComPtr<IMMDeviceEnumerator> spEnumerator;
- CComPtr<IMMDevice> spDevice;
- CComQIPtr<IPart> spPart;
- bool bIsMicArray;
- hr = spEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));
- IF_FAILED_RETURN(hr);
- hr = spEnumerator->GetDevice(szDeviceId, &spDevice);
- IF_FAILED_RETURN(hr);
- hr = EndpointIsMicArray(spDevice, bIsMicArray);
- IF_FAILED_RETURN(hr);
- if (!bIsMicArray)
- return E_FAIL;
-
- UINT nPartId = 0;
- hr = GetInputJack(spDevice, spPart);
- IF_FAILED_RETURN(hr);
- hr = spPart->GetLocalId(&nPartId);
- IF_FAILED_RETURN(hr);
- CComPtr<IDeviceTopology> spTopology;
- CComPtr<IMMDeviceEnumerator> spEnum;
- CComPtr<IMMDevice> spJackDevice;
- CComPtr<IKsControl> spKsControl;
- wchar_t * pwstrDevice = 0;
- // Get the topology object for the part
- hr = spPart->GetTopologyObject(&spTopology);
- IF_FAILED_RETURN(hr);
- // Get the id of the IMMDevice that this topology object describes.
- hr = spTopology->GetDeviceId(&pwstrDevice);
- IF_FAILED_RETURN(hr);
- // Get an IMMDevice pointer using the ID
- hr = spEnum.CoCreateInstance(__uuidof(MMDeviceEnumerator));
- IF_FAILED_JUMP(hr, Exit);
- hr = spEnum->GetDevice(pwstrDevice, &spJackDevice);
- IF_FAILED_JUMP(hr, Exit);
- // Activate IKsControl on the IMMDevice
- hr = spJackDevice->Activate(__uuidof(IKsControl), CLSCTX_INPROC_SERVER,
- NULL, reinterpret_cast<void**>(&spKsControl));
- IF_FAILED_JUMP(hr, Exit);
- // At this point we can use IKsControl just as we would use DeviceIoControl
- KSP_PIN ksp;
- ULONG cbData = 0;
- ULONG cbGeometry = 0;
- // Inititialize the pin property
- ::ZeroMemory(&ksp, sizeof(ksp));
- ksp.Property.Set = KSPROPSETID_Audio;
- ksp.Property.Id = KSPROPERTY_AUDIO_MIC_ARRAY_GEOMETRY;
- ksp.Property.Flags = KSPROPERTY_TYPE_GET;
- ksp.PinId = nPartId & PARTID_MASK;
- // Get data size by passing NULL
- hr = spKsControl->KsProperty(reinterpret_cast<PKSPROPERTY>(&ksp),
- sizeof(ksp), NULL, 0, &cbGeometry);
- IF_FAILED_JUMP(hr, Exit);
-
- // Allocate memory for the microphone array geometry
- *ppGeometry = reinterpret_cast<KSAUDIO_MIC_ARRAY_GEOMETRY*>
- (::CoTaskMemAlloc(cbGeometry));
- if(*ppGeometry == 0)
- {
- hr = E_OUTOFMEMORY;
- }
- IF_FAILED_JUMP(hr, Exit);
-
- // Now retriev the mic-array structure...
- DWORD cbOut = 0;
- hr = spKsControl->KsProperty(reinterpret_cast<PKSPROPERTY>(&ksp),
- sizeof(ksp), *ppGeometry, cbGeometry,
- &cbOut);
- IF_FAILED_JUMP(hr, Exit);
- cbSize = cbGeometry;
-
- Exit:
- if(pwstrDevice != 0)
- {
- ::CoTaskMemFree(pwstrDevice);
- }
- return hr;
- }//GetMicArrayGeometry()
|