コード例 #1
0
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInGuidStr(WCHAR deviceInStrBuffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE])
{
	if (!deviceInStrBuffer)
		return ovrError_InvalidParameter;

	IMMDeviceEnumerator* pEnumerator;
	const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
	const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
	HRESULT hr = CoCreateInstance(
		CLSID_MMDeviceEnumerator, NULL,
		CLSCTX_ALL, IID_IMMDeviceEnumerator,
		(void**)&pEnumerator);
	if (FAILED(hr))
		return ovrError_RuntimeException;

	IMMDevice* pDevice;
	hr = pEnumerator->GetDefaultAudioEndpoint(eCapture, eConsole, &pDevice);
	if (FAILED(hr))
		return ovrError_RuntimeException;

	LPWSTR pGuid;
	hr = pDevice->GetId(&pGuid);
	if (FAILED(hr))
		return ovrError_RuntimeException;

	wcsncpy(deviceInStrBuffer, pGuid, OVR_AUDIO_MAX_DEVICE_STR_SIZE);

	// Cleanup
	pDevice->Release();
	pEnumerator->Release();
	return ovrSuccess;
}
コード例 #2
0
void printVolume()
{
	HRESULT hr;
	bool decibels = false;
	bool scalar = false;
	double newVolume = 10;
	// -------------------------
	CoInitialize(NULL);
	IMMDeviceEnumerator *deviceEnumerator = NULL;
	hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
	IMMDevice *defaultDevice = NULL;

	hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
	deviceEnumerator->Release();
	deviceEnumerator = NULL;

	IAudioEndpointVolume *endpointVolume = NULL;
	hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
	defaultDevice->Release();
	defaultDevice = NULL;

	// -------------------------
	float currentVolume = 0;
	endpointVolume->GetMasterVolumeLevel(&currentVolume);
	printf("Current volume in dB is: %f\n", currentVolume);

	hr = endpointVolume->GetMasterVolumeLevelScalar(&currentVolume);
	printf("Current volume as a scalar is: %f\n", currentVolume);
}
コード例 #3
0
ファイル: wasapiengine.cpp プロジェクト: CUE0/gambatte
static void fillDeviceSelector(QComboBox *const deviceSelector) {
	IMMDeviceEnumerator *pEnumerator = 0;
	IMMDeviceCollection *pCollection = 0;
	UINT count = 0;

	CoCreateInstance(CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, IID_IMMDeviceEnumerator,
	                 reinterpret_cast<void **>(&pEnumerator));
	if (pEnumerator) {
		pEnumerator->EnumAudioEndpoints(eRender,
		                                DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED,
		                                &pCollection);
	}

	if (pCollection && FAILED(pCollection->GetCount(&count)))
		count = 0;

	for (ULONG i = 0; i < count; ++i) {
		IMMDevice *pEndpoint = 0;
		pCollection->Item(i, &pEndpoint);
		if (pEndpoint) {
			addDeviceSelectorItem(deviceSelector, pEndpoint);
			pEndpoint->Release();
		}
	}

	safeRelease(pCollection);
	safeRelease(pEnumerator);
}
コード例 #4
0
ファイル: WASAPI.cpp プロジェクト: arrai/mumble-record
const QHash<QString, QString> WASAPISystem::getDevices(EDataFlow dataflow) {
	QHash<QString, QString> devices;

	HRESULT hr;

	IMMDeviceEnumerator *pEnumerator = NULL;
	IMMDeviceCollection *pCollection = NULL;

	hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), reinterpret_cast<void **>(&pEnumerator));

	if (! pEnumerator || FAILED(hr)) {
		qWarning("WASAPI: Failed to instatiate enumerator");
	} else {
		hr = pEnumerator->EnumAudioEndpoints(dataflow, DEVICE_STATE_ACTIVE, &pCollection);
		if (! pCollection || FAILED(hr)) {
			qWarning("WASAPI: Failed to enumerate");
		} else {
			devices.insert(QString(), tr("Default Device"));

			UINT ndev = 0;
			pCollection->GetCount(&ndev);
			for (unsigned int idx=0;idx<ndev;++idx) {
				IMMDevice *pDevice = NULL;
				IPropertyStore *pStore = NULL;

				pCollection->Item(idx, &pDevice);
				pDevice->OpenPropertyStore(STGM_READ, &pStore);

				LPWSTR strid = NULL;
				pDevice->GetId(&strid);

				PROPVARIANT varName;
				PropVariantInit(&varName);

				pStore->GetValue(PKEY_Device_FriendlyName, &varName);

				devices.insert(QString::fromWCharArray(strid), QString::fromWCharArray(varName.pwszVal));

				PropVariantClear(&varName);
				CoTaskMemFree(strid);

				pStore->Release();
				pDevice->Release();
			}
			pCollection->Release();
		}
		pEnumerator->Release();
	}

	return devices;
}
コード例 #5
0
ファイル: 소스.cpp プロジェクト: rollrat/old-library
bool ChangeVolume(double nVolume,bool bScalar)
{
 
    HRESULT hr=NULL;
    bool decibels = false;
    bool scalar = false;
    double newVolume=nVolume;
 
    CoInitialize(NULL);

		IMMDeviceEnumerator *deviceEnumerator = NULL;
		hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, 
		                      __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
		IMMDevice *defaultDevice = NULL;
 
		hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
		deviceEnumerator->Release();
		deviceEnumerator = NULL;
 
		IAudioEndpointVolume *endpointVolume = NULL;
		hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), 
		     CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
		defaultDevice->Release();
		defaultDevice = NULL;
 
		// -------------------------
		float currentVolume = 0;
		endpointVolume->GetMasterVolumeLevel(&currentVolume);
		//printf("Current volume in dB is: %f\n", currentVolume);

		hr = endpointVolume->GetMasterVolumeLevelScalar(&currentVolume);
		//CString strCur=L"";
		//strCur.Format(L"%f",currentVolume);
		//AfxMessageBox(strCur);

		// printf("Current volume as a scalar is: %f\n", currentVolume);
		if (bScalar==false)
		{
		    hr = endpointVolume->SetMasterVolumeLevel((float)newVolume, NULL);
		}
		else if (bScalar==true)
		{
		    hr = endpointVolume->SetMasterVolumeLevelScalar((float)newVolume, NULL);
		}
		endpointVolume->Release();
 
    CoUninitialize();
 
    return FALSE;
}
コード例 #6
0
HRESULT GetDefaultDeviceID(IMMDeviceEnumerator *pEnum, LPWSTR *ppOutID)
{
        IMMDevice *pDevice = NULL;
        HRESULT hr = pEnum->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
                                
        if(FAILED(hr))
        {
                *ppOutID = NULL;
                return hr;
        }

        hr = pDevice->GetId(ppOutID);
        pDevice->Release();

        return hr;
}
コード例 #7
0
ファイル: VistaVolume.cpp プロジェクト: EventGhost/EventGhost
IAudioEndpointVolume * GetEndpointVolume() {
  HRESULT hr;
  IMMDeviceEnumerator *deviceEnumerator = NULL;
  hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
  IMMDevice *defaultDevice = NULL;

  hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
  deviceEnumerator->Release();
  deviceEnumerator = NULL;

  IAudioEndpointVolume *endpointVolume = NULL;
  hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
  defaultDevice->Release();
  defaultDevice = NULL;
  return endpointVolume;
}
コード例 #8
0
ファイル: audio_driver_wasapi.cpp プロジェクト: 93i/godot
Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) {

	Array list;
	IMMDeviceCollection *devices = NULL;
	IMMDeviceEnumerator *enumerator = NULL;

	list.push_back(String("Default"));

	CoInitialize(NULL);

	HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
	ERR_FAIL_COND_V(hr != S_OK, Array());

	hr = enumerator->EnumAudioEndpoints(p_capture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices);
	ERR_FAIL_COND_V(hr != S_OK, Array());

	UINT count = 0;
	hr = devices->GetCount(&count);
	ERR_FAIL_COND_V(hr != S_OK, Array());

	for (ULONG i = 0; i < count; i++) {
		IMMDevice *device = NULL;

		hr = devices->Item(i, &device);
		ERR_BREAK(hr != S_OK);

		IPropertyStore *props = NULL;
		hr = device->OpenPropertyStore(STGM_READ, &props);
		ERR_BREAK(hr != S_OK);

		PROPVARIANT propvar;
		PropVariantInit(&propvar);

		hr = props->GetValue(PKEY_Device_FriendlyName, &propvar);
		ERR_BREAK(hr != S_OK);

		list.push_back(String(propvar.pwszVal));

		PropVariantClear(&propvar);
		props->Release();
		device->Release();
	}

	devices->Release();
	enumerator->Release();
	return list;
}
コード例 #9
0
ファイル: REV_CAPI_Audio.cpp プロジェクト: LibreVR/Revive
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceOutGuidStr(WCHAR deviceOutStrBuffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE])
{
	REV_TRACE(ovr_GetAudioDeviceOutGuidStr);

	if (!deviceOutStrBuffer)
		return ovrError_InvalidParameter;

	// Query and cache the result
	static WCHAR cachedBuffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE] = {};
	if (wcslen(cachedBuffer) == 0)
	{
		HRESULT com = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

		IMMDeviceEnumerator* pEnumerator;
		const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
		const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
		HRESULT hr = CoCreateInstance(
			CLSID_MMDeviceEnumerator, NULL,
			CLSCTX_ALL, IID_IMMDeviceEnumerator,
			(void**)&pEnumerator);
		if (FAILED(hr))
			return ovrError_AudioComError;

		IMMDevice* pDevice;
		hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
		if (FAILED(hr))
			return ovrError_AudioDeviceNotFound;

		LPWSTR pGuid;
		hr = pDevice->GetId(&pGuid);
		if (FAILED(hr))
			return ovrError_AudioComError;

		wcsncpy(cachedBuffer, pGuid, OVR_AUDIO_MAX_DEVICE_STR_SIZE);

		// Cleanup
		pDevice->Release();
		pEnumerator->Release();
		if (SUCCEEDED(com))
			CoUninitialize();
	}

	wcsncpy(deviceOutStrBuffer, cachedBuffer, OVR_AUDIO_MAX_DEVICE_STR_SIZE);
	return ovrSuccess;
}
コード例 #10
0
AudioEndpoint::AudioEndpoint(IMMDeviceEnumerator *aDeviceEnumerator)
{
	Set(L"\0");

	IMMDevice *pDevice;
	HRESULT hr = aDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
	if (SUCCEEDED(hr))
	{
		LPWSTR id;
		hr = pDevice->GetId(&id);
		if (SUCCEEDED(hr))
		{
			Set(id);
			CoTaskMemFree(id);
		}
		pDevice->Release();
	}
}
コード例 #11
0
IAudioSessionEnumerator* GetAudioSessionEnumerator() {
  IMMDeviceEnumerator* deviceEnumerator = nullptr;
  CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);

  IMMDevice* device = nullptr;
  deviceEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &device);

  IAudioSessionManager2* sessionManager = nullptr;
  device->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL, nullptr, (void**)&sessionManager);

  IAudioSessionEnumerator* enumerator = nullptr;
  sessionManager->GetSessionEnumerator(&enumerator);

  deviceEnumerator->Release();
  device->Release();
  sessionManager->Release();

  return enumerator;
}
コード例 #12
0
ファイル: WinQLAudioSession.cpp プロジェクト: chenbk85/QOR
	//-------------------------------------------------------------------
	//  Initializes the CAudioSessionEventHandler object.
	long CAudioSessionEventHandler::Initialize()
	{
		_WINQ_FCONTEXT( "CAudioSessionEventHandler::Initialize" );
		long hr = 0;

		IMMDeviceEnumerator* pDeviceEnumerator = 0;
		IMMDevice* pDevice = 0;
		IAudioSessionManager* pAudioSessionManager = 0;

		// Get the enumerator for the audio endpoint devices.
		hr = nsWinQAPI::COLE32::Instance().CoCreateInstance( reinterpret_cast< const ::IID& >( CLASS_MMDEVICEENUMERATOR ), 0, CLSCTX_INPROC_SERVER, reinterpret_cast< const ::IID& >( IMMDeviceEnumerator::_IID ), reinterpret_cast< void** >( &pDeviceEnumerator ) );

		if( hr < 0 ) { goto done; }

		// Get the default audio endpoint that the SAR will use.
		hr = pDeviceEnumerator->GetDefaultAudioEndpoint( eRender, eConsole,   // The SAR uses 'eConsole' by default.
			&pDevice
			);

		if( hr < 0 ) { goto done; }

		// Get the session manager for this device.
		hr = pDevice->Activate(  IAudioSessionManager::_IID,  CLSCTX_INPROC_SERVER, 0, (void**) &pAudioSessionManager );
		if( hr < 0 ) { goto done; }

		// Get the audio session. 
		hr = pAudioSessionManager->GetAudioSessionControl(reinterpret_cast< const nsWin32::GUID* >(&NULL_GUID),     // Get the default audio session. 
			0,          // The session is not cross-process.
			&m_pAudioSession 
			);

		if( hr < 0 ) { goto done; }

		hr = pAudioSessionManager->GetSimpleAudioVolume(reinterpret_cast< const nsWin32::GUID* >(&NULL_GUID), 0, &m_pSimpleAudioVolume);

done:

		pDeviceEnumerator->Release();
		pDevice->Release();
		pAudioSessionManager->Release();
		return hr;
	}
コード例 #13
0
ファイル: MediaPlayer.cpp プロジェクト: quartorz/Hockey
//
//  Utility function to retrieve the session manager for the default audio endpoint.
//
HRESULT CMediaPlayer::GetSessionManager2()
{
    HRESULT hr = S_OK;
    if (_SessionManager2 == NULL)
    {
        IMMDeviceEnumerator *deviceEnumerator;
        IMMDevice *endpoint = NULL;

        //
        //  Start with the default endpoint.
        //
        hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&deviceEnumerator));
        if (SUCCEEDED(hr))
        {
            hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &endpoint);

            deviceEnumerator->Release();
            deviceEnumerator = NULL;
        }
        else
        {
            MessageBox(_AppWindow, L"Unable to instantiate MMDeviceEnumerator", L"Get SessionManager Error", MB_OK);
        }

        if (SUCCEEDED(hr))
        {
            hr = endpoint->Activate(__uuidof(IAudioSessionManager2), CLSCTX_INPROC_SERVER,
                    NULL, reinterpret_cast<void **>(&_SessionManager2));
            endpoint->Release();
            if (FAILED(hr))
            {
                MessageBox(_AppWindow, L"Unable to Activate session manager", L"Get SessionManager Error", MB_OK);
            }
        }
        else
        {
            MessageBox(_AppWindow, L"Unable to get default endpoint", L"Get SessionManager Error", MB_OK);
        }
    }
    return hr;
}
コード例 #14
0
/**
* Initialize the EndpointVolume (volume controller).
*/
void master_volume::loadVolumeController()
{
    m_endpointVolume = nullptr;

    HRESULT hr;
    IMMDeviceEnumerator *deviceEnumerator = nullptr;
    IMMDevice *defaultDevice = nullptr;

    // Get the list of audio devices
    hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
    if (hr != S_OK) {
        logger.Error("master_volume::loadVolumeController(), CoCreateInstance failed with error: " + hr);
        return;
    }

    // Get the default audio device
    hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
    if (hr != S_OK) {
        logger.Error("GetDefaultAudioEndpoint failed with error: " + hr);
        return;
    }

    // Free the device list
    if (deviceEnumerator) {
        deviceEnumerator->Release();
        deviceEnumerator = nullptr;
    }

    // Load EndpointVolume (volume controller)
    hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, (LPVOID *)&m_endpointVolume);
    if (hr != S_OK) {
        logger.Error("master_volume::loadVolumeController(), defaultDevice->Activate failed with error: " + hr);
        return;
    }

    // Release the default device
    if (defaultDevice) {
        defaultDevice->Release();
        defaultDevice = nullptr;
    }
}
コード例 #15
0
ファイル: dllmain.cpp プロジェクト: ukanth/monitores-old
void SetMuteStatus()
{
    HRESULT hr;

    CoInitialize(NULL);
    IMMDeviceEnumerator *deviceEnumerator = NULL;
    hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
    if (!SUCCEEDED(hr)) 
    {
        CoUninitialize();
    }

    IMMDevice *defaultDevice = NULL;

    hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
    deviceEnumerator->Release();
    deviceEnumerator = NULL;
    if (!SUCCEEDED(hr))
    {
        CoUninitialize();
    }

    IAudioEndpointVolume *endpointVolume = NULL;
    hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
    defaultDevice->Release();
    defaultDevice = NULL; 

    if (!SUCCEEDED(hr)) 
    {
        CoUninitialize();
    }

    // -------------------------
	BOOL b;

	endpointVolume->GetMute(&b);
	b=!b;
	endpointVolume->SetMute(b, NULL);
	endpointVolume->Release();
    CoUninitialize();
}
コード例 #16
0
ファイル: SetVolume.cpp プロジェクト: davidcie/SetVolume
void InitializeAudioEndpoint(IAudioEndpointVolume **audioEndpoint) 
{
	HRESULT hr;

	// Initialize the COM library
	CoInitialize(nullptr);

	// Get audio device enumerator
	IMMDeviceEnumerator *deviceEnumerator = nullptr;
	hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
	if (hr != S_OK) {
		printf("Unable to create instance of MMDeviceEnumerator (error code: 0x%08lx)\n", hr);
		CoUninitialize();
		exit(-1);
	}

	// Ask device enumerator for the default audio renderer
	IMMDevice *defaultDevice = nullptr;
	hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
	deviceEnumerator->Release();
	deviceEnumerator = nullptr;
	if (hr != S_OK) {
		printf("Unable to get default audio endpoint (error code: 0x%08lx)\n", hr);
		CoUninitialize();
		exit(-1);
	}
	
	// Ask default audio renderer for volume controller
	//IAudioEndpointVolume *endpointVolume = nullptr;
	hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, (LPVOID *)audioEndpoint);
	defaultDevice->Release();
	defaultDevice = nullptr;
	if (hr != S_OK) {
		printf("Unable to get default audio volume controller (error code: 0x%08lx)\n", hr);
		CoUninitialize();
		exit(-1);
	}
}
void propagateWithRawCurrentFormat(WAVEFORMATEX *toThis) {
	WAVEFORMATEX *pwfx;
	IMMDevice *pMMDevice;
	IAudioClient *pAudioClient;
    HANDLE hTask;
    DWORD nTaskIndex = 0;
    hTask = AvSetMmThreadCharacteristics(L"Capture", &nTaskIndex);

    HRESULT hr = get_default_device(&pMMDevice);
    if (FAILED(hr)) {
        assert(false);
    }
	// activate an (the default, for us, since we want loopback) IAudioClient
    hr = pMMDevice->Activate(
        __uuidof(IAudioClient),
        CLSCTX_ALL, NULL,
        (void**)&pAudioClient
    );
    if (FAILED(hr)) {
        ShowOutput("IMMDevice::Activate(IAudioClient) failed: hr = 0x%08x", hr);
		assert(false);
    }

	hr = pAudioClient->GetMixFormat(&pwfx);
    if (FAILED(hr)) {
        ShowOutput("IAudioClient::GetMixFormat failed: hr = 0x%08x\n", hr);
        CoTaskMemFree(pwfx);
        pAudioClient->Release();
   		assert(false);
    }
	pAudioClient->Stop();
    AvRevertMmThreadCharacteristics(hTask);
    pAudioClient->Release();
    pMMDevice->Release();
	memcpy(toThis, pwfx, sizeof(WAVEFORMATEX));
	CoTaskMemFree(pwfx); 
}
コード例 #18
0
ファイル: MFSound_WASAPI.cpp プロジェクト: TurkeyMan/fuji
static MFDevice *NewDevice(LPCWSTR pwstrDeviceId)
{
	MFDevice *pDev = NULL;
	IMMDevice *pDevice;
	gpEnumerator->GetDevice(pwstrDeviceId, &pDevice);
	if(pDevice)
	{
		// TODO: don't know if it's a capture device or not!
		if(1)
		{
			pDev = MFDevice_AllocDevice(MFDT_AudioRender, NULL);
			pDev->pInternal = gDevices.AllocAndZero();
			GetDeviceInfo(pDevice, pDev);
		}
		else
		{
			pDev = MFDevice_AllocDevice(MFDT_AudioCapture, NULL);
			pDev->pInternal = gCaptureDevices.AllocAndZero();
			GetDeviceInfo(pDevice, pDev);
		}
		pDevice->Release();
	}
	return pDev;
}
コード例 #19
0
void MFAudioEndpointControl::updateEndpoints()
{
    m_defaultEndpoint = QString::fromLatin1("Default");
    m_devices.insert(m_defaultEndpoint, NULL);

    IMMDeviceEnumerator *pEnum = NULL;
    HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
                          NULL, CLSCTX_ALL,
                          __uuidof(IMMDeviceEnumerator),
                         (void**)&pEnum);
    if (SUCCEEDED(hr)) {
        IMMDeviceCollection *pDevices = NULL;
        hr = pEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pDevices);
        if (SUCCEEDED(hr)) {
            UINT count;
            hr = pDevices->GetCount(&count);
            if (SUCCEEDED(hr)) {
                for (UINT i = 0; i < count; ++i) {
                    IMMDevice *pDevice = NULL;
                    hr = pDevices->Item(i, &pDevice);
                    if (SUCCEEDED(hr)) {
                        LPWSTR wstrID = NULL;
                        hr = pDevice->GetId(&wstrID);
                        if (SUCCEEDED(hr)) {
                            QString deviceId = QString::fromWCharArray(wstrID);
                            m_devices.insert(deviceId, wstrID);
                        }
                        pDevice->Release();
                    }
                }
            }
            pDevices->Release();
        }
        pEnum->Release();
    }
}
コード例 #20
0
HRESULT get_specific_device(LPCWSTR szLongName, IMMDevice **ppMMDevice) {
    HRESULT hr = S_OK;

    *ppMMDevice = NULL;
    
    // get an enumerator
    IMMDeviceEnumerator *pMMDeviceEnumerator;

    hr = CoCreateInstance(
        __uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, 
        __uuidof(IMMDeviceEnumerator),
        (void**)&pMMDeviceEnumerator
    );
    if (FAILED(hr)) {
        printf("CoCreateInstance(IMMDeviceEnumerator) failed: hr = 0x%08x\n", hr);
        return hr;
    }

    IMMDeviceCollection *pMMDeviceCollection;

    // get all the active render endpoints
    hr = pMMDeviceEnumerator->EnumAudioEndpoints(
        eRender, DEVICE_STATE_ACTIVE, &pMMDeviceCollection
    );
    pMMDeviceEnumerator->Release();
    if (FAILED(hr)) {
        printf("IMMDeviceEnumerator::EnumAudioEndpoints failed: hr = 0x%08x\n", hr);
        return hr;
    }

    UINT count;
    hr = pMMDeviceCollection->GetCount(&count);
    if (FAILED(hr)) {
        pMMDeviceCollection->Release();
        printf("IMMDeviceCollection::GetCount failed: hr = 0x%08x\n", hr);
        return hr;
    }

    for (UINT i = 0; i < count; i++) {
        IMMDevice *pMMDevice;

        // get the "n"th device
        hr = pMMDeviceCollection->Item(i, &pMMDevice);
        if (FAILED(hr)) {
            pMMDeviceCollection->Release();
            printf("IMMDeviceCollection::Item failed: hr = 0x%08x\n", hr);
            return hr;
        }

        // open the property store on that device
        IPropertyStore *pPropertyStore;
        hr = pMMDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
        if (FAILED(hr)) {
            pMMDevice->Release();
            pMMDeviceCollection->Release();
            printf("IMMDevice::OpenPropertyStore failed: hr = 0x%08x\n", hr);
            return hr;
        }

        // get the long name property
        PROPVARIANT pv; PropVariantInit(&pv);
        hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
        pPropertyStore->Release();
        if (FAILED(hr)) {
            pMMDevice->Release();
            pMMDeviceCollection->Release();
            printf("IPropertyStore::GetValue failed: hr = 0x%08x\n", hr);
            return hr;
        }

        if (VT_LPWSTR != pv.vt) {
            printf("PKEY_Device_FriendlyName variant type is %u - expected VT_LPWSTR", pv.vt);

            PropVariantClear(&pv);
            pMMDevice->Release();
            pMMDeviceCollection->Release();
            return E_UNEXPECTED;
        }

        // is it a match?
        if (0 == _wcsicmp(pv.pwszVal, szLongName)) {
            // did we already find it?
            if (NULL == *ppMMDevice) {
                *ppMMDevice = pMMDevice;
                pMMDevice->AddRef();
            } else {
                printf("Found (at least) two devices named %ls\n", szLongName);
                PropVariantClear(&pv);
                pMMDevice->Release();
                pMMDeviceCollection->Release();
                return E_UNEXPECTED;
            }
        }
        
        pMMDevice->Release();
        PropVariantClear(&pv);
    }
    pMMDeviceCollection->Release();
    
    if (NULL == *ppMMDevice) {
        printf("Could not find a device named %ls\n", szLongName);
        return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
    }

    return S_OK;
}
コード例 #21
0
TBool OhmSenderDriverWindows::FindEndpoint(const char* aManufacturer)
{
	bool uninitialise = true;

	HRESULT hr = CoInitialize(NULL);

	printf("CoInitialize %d\n", hr);

	if (hr == 0x80010106)
	{
		uninitialise = false;
	}
	else if (!SUCCEEDED(hr))
	{
		return (false);
	}

	// Create a multimedia device enumerator.
	hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&iDeviceEnumerator);
		
	printf("CoCreateInstance %d\n", hr);
	
	if (SUCCEEDED(hr))
	{
		IMMDeviceCollection *pDevices;
		
		// Enumerate the output devices.
			
		hr = iDeviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATEMASK_ALL | 0x10000000, &pDevices);
			
		printf("EnumAudioEndpoints %d\n", hr);

		if (SUCCEEDED(hr))
		{
			UINT count;
			
			pDevices->GetCount(&count);
            printf("count: %d\n", count);
				
			if (SUCCEEDED(hr))
			{
				for (unsigned i = 0; i < count; i++)
				{
					IMMDevice *pDevice;
				
					hr = pDevices->Item(i, &pDevice);
						
					if (SUCCEEDED(hr))
					{
						LPWSTR wstrID = NULL;
						
						hr = pDevice->GetId(&wstrID);
                            
                        wprintf(L"id: %s\n", wstrID);
							
						if (SUCCEEDED(hr))
						{
							IPropertyStore *pStore;
							
							hr = pDevice->OpenPropertyStore(STGM_READ, &pStore);
								
							if (SUCCEEDED(hr))
							{
                                PROPVARIANT var;
                                PropVariantInit(&var);
                                hr = pStore->GetValue(PKEY_AudioEndpoint_GUID, &var);
                                wprintf(L"%s\n", var.pwszVal);
                                
								PROPVARIANT friendlyName;
								
								PropVariantInit(&friendlyName);
									
								hr = pStore->GetValue(PKEY_DeviceInterface_FriendlyName, &friendlyName);
                                    
                                wprintf(L"friendlyName: %s\n", friendlyName.pwszVal);
									
								if (SUCCEEDED(hr))
								{
									wchar_t model[200];

									MultiByteToWideChar(CP_ACP, 0, aManufacturer, -1, model, sizeof(model));

									wcscpy(model + wcslen(model), L" Songcast");

									if (!wcscmp(friendlyName.pwszVal, model))
									{
										iSongcastEndpoint.Set(wstrID);
										PropVariantClear(&friendlyName);
										pStore->Release();
										pDevice->Release();
										pDevices->Release();
										if (uninitialise) {
											CoUninitialize();
										}
										return (true);
									}

									PropVariantClear(&friendlyName);
								}

								pStore->Release();
							}
                                
                            CoTaskMemFree(wstrID);
						}
						pDevice->Release();
					}
				}
			}
			pDevices->Release();
		}
		iDeviceEnumerator->Release();
	}

	if (uninitialise) {
		CoUninitialize();
	}

	return (false);
}
コード例 #22
0
ファイル: main.cpp プロジェクト: korha/SoundCardSwitch
//-------------------------------------------------------------------------------------------------
void FMain()
{
    if (const HWND hWnd = FindWindowW(g_wGuidClass, nullptr))
        PostMessageW(hWnd, WM_CLOSE, 0, 0);

    if (SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)))
    {
        IMMDeviceEnumerator *immDeviceEnumerator;
        if (CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), reinterpret_cast<LPVOID*>(&immDeviceEnumerator)) == S_OK)
        {
            IMMDevice *immDeviceDefault;
            if (immDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &immDeviceDefault) == S_OK)
            {
                wchar_t *wIdDefaultOld;
                HRESULT hr = immDeviceDefault->GetId(&wIdDefaultOld);
                immDeviceDefault->Release();
                if (hr == S_OK)
                {
                    IMMDeviceCollection *immDeviceCollection;
                    hr = immDeviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &immDeviceCollection);
                    immDeviceEnumerator->Release();
                    if (hr == S_OK)
                    {
                        UINT iCount;
                        if (immDeviceCollection->GetCount(&iCount) == S_OK)
                        {
                            bool bFail = true;
                            for (UINT i = 0; i < iCount; ++i)
                            {
                                IMMDevice *immDevice;
                                if (immDeviceCollection->Item(i, &immDevice) == S_OK)
                                {
                                    wchar_t *wIdEnum;
                                    hr = immDevice->GetId(&wIdEnum);
                                    immDevice->Release();
                                    if (hr == S_OK)
                                    {
                                        if (FCompareMemoryW(wIdDefaultOld, wIdEnum))
                                        {
                                            bFail = false;
                                            if (++i >= iCount)
                                                i = 0;
                                            hr = immDeviceCollection->Item(i, &immDevice);
                                            immDeviceCollection->Release();
                                            if (hr == S_OK)
                                            {
                                                wchar_t *wIdDefaultNew;
                                                if (immDevice->GetId(&wIdDefaultNew) == S_OK)
                                                {
                                                    IPropertyStore *ipStore;
                                                    hr = immDevice->OpenPropertyStore(STGM_READ, &ipStore);
                                                    immDevice->Release();
                                                    if (hr == S_OK)
                                                    {
                                                        PROPVARIANT propFriendlyName;
                                                        PropVariantInitFix(&propFriendlyName);
                                                        PROPERTYKEY propKeyFriendlyName;
                                                        propKeyFriendlyName.fmtid.Data1 = 0xA45C254E;
                                                        propKeyFriendlyName.fmtid.Data2 = 0xDF1C;
                                                        propKeyFriendlyName.fmtid.Data3 = 0x4EFD;
                                                        FCopyMemory(propKeyFriendlyName.fmtid.Data4);
                                                        propKeyFriendlyName.pid = 14;
                                                        hr = ipStore->GetValue(propKeyFriendlyName, &propFriendlyName);
                                                        ipStore->Release();
                                                        if (SUCCEEDED(hr))
                                                        {
                                                            IPolicyConfig *pPolicyConfig;
                                                            if (CoCreateInstance(__uuidof(CPolicyConfigClient), nullptr, CLSCTX_ALL, (GetVersion() & 0xFF) >= 10 ? __uuidof(IPolicyConfigWin10) : __uuidof(IPolicyConfig), reinterpret_cast<LPVOID*>(&pPolicyConfig)) == S_OK)
                                                            {
                                                                hr = pPolicyConfig->SetDefaultEndpoint(wIdDefaultNew, eConsole);
                                                                if (hr == S_OK)
                                                                {
                                                                    pPolicyConfig->SetDefaultEndpoint(wIdDefaultNew, eMultimedia);
                                                                    pPolicyConfig->SetDefaultEndpoint(wIdDefaultNew, eCommunications);
                                                                }
                                                                pPolicyConfig->Release();
                                                                if (hr == S_OK)
                                                                {
                                                                    WNDCLASSEX wndCl;
                                                                    wndCl.cbSize = sizeof(WNDCLASSEX);
                                                                    wndCl.style = 0;
                                                                    wndCl.lpfnWndProc = WindowProc;
                                                                    wndCl.cbClsExtra = 0;
                                                                    wndCl.cbWndExtra = 0;
                                                                    wndCl.hInstance = GetModuleHandleW(nullptr);
                                                                    wndCl.hIcon = nullptr;
                                                                    wndCl.hCursor = nullptr;
                                                                    wndCl.hbrBackground = nullptr;
                                                                    wndCl.lpszMenuName = nullptr;
                                                                    wndCl.lpszClassName = g_wGuidClass;
                                                                    wndCl.hIconSm = nullptr;

                                                                    if (RegisterClassExW(&wndCl))
                                                                    {
                                                                        if (CreateWindowExW(WS_EX_NOACTIVATE | WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST, g_wGuidClass, nullptr, WS_POPUP | WS_VISIBLE | WS_MAXIMIZE, 0, 0, 0, 0, nullptr, nullptr, wndCl.hInstance, propFriendlyName.pwszVal))
                                                                        {
                                                                            MSG msg;
                                                                            while (GetMessageW(&msg, nullptr, 0, 0) > 0)
                                                                                DispatchMessageW(&msg);
                                                                        }
                                                                        UnregisterClassW(g_wGuidClass, wndCl.hInstance);
                                                                    }
                                                                }
                                                            }
                                                        }
                                                        PropVariantClear(&propFriendlyName);
                                                    }
                                                    CoTaskMemFree(wIdDefaultNew);
                                                }
                                                else
                                                    immDevice->Release();
                                            }
                                            break;
                                        }
                                        CoTaskMemFree(wIdEnum);
                                    }
                                }
                            }
                            if (bFail)
                                immDeviceCollection->Release();
                        }
                        else
                            immDeviceCollection->Release();
                    }
                    CoTaskMemFree(wIdDefaultOld);
                }
                else
                    immDeviceEnumerator->Release();
            }
            else
                immDeviceEnumerator->Release();
        }
        CoUninitialize();
    }
}
コード例 #23
0
void VolumeControl::init()
{
	//initialize audio mixer interface
#if defined (__APPLE__)
	#warning TODO: Not implemented for MacOS yet!!!
#elif defined(__linux__)
	//try to open mixer device
	if (mixerHandle == nullptr)
	{
		snd_mixer_selem_id_alloca(&mixerSelemId);
		//sets simple-mixer index and name
		snd_mixer_selem_id_set_index(mixerSelemId, mixerIndex);
		snd_mixer_selem_id_set_name(mixerSelemId, mixerName);
		//open mixer
		if (snd_mixer_open(&mixerHandle, 0) >= 0)
		{
			LOG(LogDebug) << "VolumeControl::init() - Opened ALSA mixer";
			//ok. attach to defualt card
			if (snd_mixer_attach(mixerHandle, mixerCard) >= 0)
			{
				LOG(LogDebug) << "VolumeControl::init() - Attached to default card";
				//ok. register simple element class
				if (snd_mixer_selem_register(mixerHandle, NULL, NULL) >= 0)
				{
					LOG(LogDebug) << "VolumeControl::init() - Registered simple element class";
					//ok. load registered elements
					if (snd_mixer_load(mixerHandle) >= 0)
					{
						LOG(LogDebug) << "VolumeControl::init() - Loaded mixer elements";
						//ok. find elements now
						mixerElem = snd_mixer_find_selem(mixerHandle, mixerSelemId);
						if (mixerElem != nullptr)
						{
							//wohoo. good to go...
							LOG(LogDebug) << "VolumeControl::init() - Mixer initialized";
						}
						else
						{
							LOG(LogError) << "VolumeControl::init() - Failed to find mixer elements!";
							snd_mixer_close(mixerHandle);
							mixerHandle = nullptr;
						}
					}
					else
					{
						LOG(LogError) << "VolumeControl::init() - Failed to load mixer elements!";
						snd_mixer_close(mixerHandle);
						mixerHandle = nullptr;
					}
				}
				else
				{
					LOG(LogError) << "VolumeControl::init() - Failed to register simple element class!";
					snd_mixer_close(mixerHandle);
					mixerHandle = nullptr;
				}
			}
			else
			{
				LOG(LogError) << "VolumeControl::init() - Failed to attach to default card!";
				snd_mixer_close(mixerHandle);
				mixerHandle = nullptr;
			}
		}
		else
		{
			LOG(LogError) << "VolumeControl::init() - Failed to open ALSA mixer!";
		}
	}
#elif defined(WIN32) || defined(_WIN32)
	//get windows version information
	OSVERSIONINFOEXA osVer = {sizeof(OSVERSIONINFO)};
	::GetVersionExA(reinterpret_cast<LPOSVERSIONINFOA>(&osVer));
	//check windows version
	if(osVer.dwMajorVersion < 6)
	{
		//Windows older than Vista. use mixer API. open default mixer
		if (mixerHandle == nullptr)
		{
			if (mixerOpen(&mixerHandle, 0, NULL, 0, 0) == MMSYSERR_NOERROR)
			{
				//retrieve info on the volume slider control for the "Speaker Out" line
				MIXERLINECONTROLS mixerLineControls;
				mixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
				mixerLineControls.dwLineID = 0xFFFF0000; //Id of "Speaker Out" line
				mixerLineControls.cControls = 1;
				//mixerLineControls.dwControlID = 0x00000000; //Id of "Speaker Out" line's volume slider
				mixerLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; //Get volume control
				mixerLineControls.pamxctrl = &mixerControl;
				mixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
				if (mixerGetLineControls((HMIXEROBJ)mixerHandle, &mixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR)
				{
					LOG(LogError) << "VolumeControl::getVolume() - Failed to get mixer volume control!";
					mixerClose(mixerHandle);
					mixerHandle = nullptr;
				}
			}
			else
			{
				LOG(LogError) << "VolumeControl::init() - Failed to open mixer!";
			}
		}
	}
	else
	{
		//Windows Vista or above. use EndpointVolume API. get device enumerator
		if (endpointVolume == nullptr)
		{
			CoInitialize(nullptr);
			IMMDeviceEnumerator * deviceEnumerator = nullptr;
			CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
			if (deviceEnumerator != nullptr)
			{
				//get default endpoint
				IMMDevice * defaultDevice = nullptr;
				deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
				if (defaultDevice != nullptr)
				{
					//retrieve endpoint volume
					defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, (LPVOID *)&endpointVolume);
					if (endpointVolume == nullptr)
					{
						LOG(LogError) << "VolumeControl::init() - Failed to get default audio endpoint volume!";
					}
					//release default device. we don't need it anymore
					defaultDevice->Release();
				}
				else
				{
					LOG(LogError) << "VolumeControl::init() - Failed to get default audio endpoint!";
				}
				//release device enumerator. we don't need it anymore
				deviceEnumerator->Release();
			}
			else
			{
				LOG(LogError) << "VolumeControl::init() - Failed to get audio endpoint enumerator!";
				CoUninitialize();
			}
		}
	}
#endif
}
コード例 #24
0
void modifyVolume(char ch)
{
	HRESULT hr;
	bool decibels = false;
	bool scalar = true;
	double newVolume = 10;
	// -------------------------
	CoInitialize(NULL);
	IMMDeviceEnumerator *deviceEnumerator = NULL;
	hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
	IMMDevice *defaultDevice = NULL;

	hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &defaultDevice);
	deviceEnumerator->Release();
	deviceEnumerator = NULL;

	IAudioEndpointVolume *endpointVolume = NULL;
	hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
	defaultDevice->Release();
	defaultDevice = NULL;

	// -------------------------
	float currentVolume = 0;
	endpointVolume->GetMasterVolumeLevel(&currentVolume);
	//printf("Current volume in dB is: %f\n", currentVolume);

	hr = endpointVolume->GetMasterVolumeLevelScalar(&currentVolume);

	float min, max, inc;
	endpointVolume->GetVolumeRange(&min, &max, &inc);
	//printf("Current volume as a scalar is: %f\n", currentVolume);

	if (ch == 'u')
		newVolume = currentVolume + 0.1;
	else if (ch == 'd')
		newVolume = currentVolume - 0.1;

	if (ch == 'm')
	{
		endpointVolume->SetMute(TRUE, NULL);
	}
	else if (ch == 'n')
	{
		endpointVolume->SetMute(FALSE, NULL);
	}
	else
	{
		if (decibels)
		{
			hr = endpointVolume->SetMasterVolumeLevel((float)newVolume, NULL);
			//endpointVolume->VolumeStepUp(NULL);
		}
		else if (scalar)
		{
			hr = endpointVolume->SetMasterVolumeLevelScalar((float)newVolume, NULL);
			//endpointVolume->VolumeStepUp(NULL);
		}
	}


	endpointVolume->Release();

	CoUninitialize();
}
コード例 #25
0
ファイル: MFSound_WASAPI.cpp プロジェクト: TurkeyMan/fuji
void MFSound_InitWASAPI()
{
	gDevices.Init(sizeof(MFAudioDevice), 8, 8);
	gCaptureDevices.Init(sizeof(MFAudioCaptureDevice), 8, 8);

	HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&gpEnumerator);
	if(FAILED(hr))
	{
		MFDebug_Assert(false, "Couldn't create multimedia device enumerator!");
		return;
	}

	// enumerate audio devices...
	gpNotification = new MFAudioDeviceNotification;
	gpEnumerator->RegisterEndpointNotificationCallback(gpNotification);

	// enumerate render devices
	IMMDeviceCollection *pDevices;
	gpEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED, &pDevices);
	if(pDevices)
	{
		UINT count;
		pDevices->GetCount(&count);

		for(UINT i=0; i<count; ++i)
		{
			IMMDevice *pDevice;
			pDevices->Item(i, &pDevice);

			MFDevice *pDev = MFDevice_AllocDevice(MFDT_AudioRender, NULL);
			pDev->pInternal = gDevices.AllocAndZero();
			MFAudioDevice &device = *(MFAudioDevice*)pDev->pInternal;

			GetDeviceInfo(pDevice, pDev);

			pDevice->Release();

			MFDebug_Log(0, MFStr("Found audio device: %s, %s - state: %d (%s)", pDev->strings[MFDS_DeviceName], pDev->strings[MFDS_Manufacturer], device.state, pDev->strings[MFDS_ID]));
		}
		pDevices->Release();
	}

	// enumerate capture devices
	gpEnumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED, &pDevices);
	if(pDevices)
	{
		UINT count;
		pDevices->GetCount(&count);

		for(UINT i=0; i<count; ++i)
		{
			IMMDevice *pDevice;
			pDevices->Item(i, &pDevice);

			MFDevice *pDev = MFDevice_AllocDevice(MFDT_AudioCapture, NULL);
			pDev->pInternal = gCaptureDevices.AllocAndZero();
			MFAudioCaptureDevice &device = *(MFAudioCaptureDevice*)pDev->pInternal;

			GetDeviceInfo(pDevice, pDev);

			pDevice->Release();

			MFDebug_Log(0, MFStr("Found audio capture device: %s, %s - state: %d (%s)", pDev->strings[MFDS_DeviceName], pDev->strings[MFDS_Manufacturer], device.state, pDev->strings[MFDS_ID]));
		}
		pDevices->Release();
	}

	// set defaults (this is some awkward windows code!)
	for(int i=0; i<2; ++i)
	{
		for(int j=0; j<3; ++j)
		{
			IMMDevice *pDevice;
			gpEnumerator->GetDefaultAudioEndpoint(gDirection[i], gRole[j], &pDevice);
			if(pDevice)
			{
				wchar_t *pDefaultId;
				pDevice->GetId(&pDefaultId);
				char temp[128];
				MFString_CopyUTF16ToUTF8(temp, pDefaultId);
				MFDevice *pDev = MFDevice_GetDeviceById(temp);
				MFDevice_SetDefaultDevice(gDt[i], gDef[j], pDev);
				CoTaskMemFree(pDefaultId);
				pDevice->Release();
			}
		}
	}
}
コード例 #26
0
	static bool UpdateAudioDucking(bool bDuckingOptOutChecked)
	{
		HRESULT hr = S_OK;

		//  Start with the default endpoint.
		IMMDeviceEnumerator* pDeviceEnumerator = NULL;
		hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
			NULL,
			CLSCTX_INPROC_SERVER,
			IID_PPV_ARGS(&pDeviceEnumerator));

		if (SUCCEEDED(hr))
		{
			{
				IMMDevice* pEndpoint = NULL;
				hr = pDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pEndpoint);
				if (SUCCEEDED(hr))
				{
					LPWSTR Desc;
					pEndpoint->GetId(&Desc);
					UE_LOG(LogVoiceCapture, Display, TEXT("%s ducking on audio device. Desc: %s"), bDuckingOptOutChecked ? TEXT("Disabling") : TEXT("Enabling"), Desc);
					CoTaskMemFree(Desc);

					FAudioDuckingWindows::EnableDuckingOptOut(pEndpoint, bDuckingOptOutChecked);
					pEndpoint->Release();
					pEndpoint = NULL;
				}
			}

			if (0) // reference for enumerating all endpoints in case its necessary
			{
				IMMDeviceCollection* pDeviceCollection = NULL;
				IMMDevice* pCollEndpoint = NULL;
				hr = pDeviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pDeviceCollection);
				if (SUCCEEDED(hr))
				{
					IPropertyStore *pProps = NULL;

					::UINT DeviceCount = 0;
					pDeviceCollection->GetCount(&DeviceCount);
					for (::UINT i = 0; i < DeviceCount; ++i)
					{
						hr = pDeviceCollection->Item(i, &pCollEndpoint);
						if (SUCCEEDED(hr) && pCollEndpoint)
						{
							LPWSTR Desc;
							pCollEndpoint->GetId(&Desc);

							hr = pCollEndpoint->OpenPropertyStore(STGM_READ, &pProps);
							if (SUCCEEDED(hr))
							{
								PROPVARIANT varName;
								// Initialize container for property value.
								PropVariantInit(&varName);

								// Get the endpoint's friendly-name property.
								hr = pProps->GetValue(
									PKEY_Device_FriendlyName, &varName);
								if (SUCCEEDED(hr))
								{
									// Print endpoint friendly name and endpoint ID.
									UE_LOG(LogVoiceCapture, Display, TEXT("%s ducking on audio device [%d]: \"%s\" (%s)"),
										bDuckingOptOutChecked ? TEXT("Disabling") : TEXT("Enabling"),
										i, varName.pwszVal, Desc);

									CoTaskMemFree(Desc);

									Desc = NULL;
									PropVariantClear(&varName);

									pProps->Release();
									pProps = NULL;
								}
							}

							FAudioDuckingWindows::EnableDuckingOptOut(pCollEndpoint, bDuckingOptOutChecked);

							pCollEndpoint->Release();
							pCollEndpoint = NULL;
						}
					}

					pDeviceCollection->Release();
					pDeviceCollection = NULL;
				}
			}

			pDeviceEnumerator->Release();
			pDeviceEnumerator = NULL;
		}

		if (FAILED(hr))
		{
			UE_LOG(LogVoiceCapture, Warning, TEXT("Failed to duck audio endpoint. Error: %0x08x"), hr);
		}

		return SUCCEEDED(hr);
	}
コード例 #27
0
std::vector<AudioDevice> EnumerateAudioDevices(_Out_opt_ AudioDevice* defaultDevice = nullptr)
{
    UINT32                   deviceCount      = 0;
    IMMDeviceEnumerator     *immDevEnum       = nullptr;
    IMMDeviceCollection     *immDevCollection = nullptr;
    IMMDevice               *immDev           = nullptr;
    std::vector<AudioDevice> vAudioDevices;

    HRESULT hResult = CoCreateInstance(
    __uuidof(MMDeviceEnumerator), NULL,
    CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**) &immDevEnum);

    if (FAILED(hResult)) {
        idLib::Warning( "Failed to get audio enumerator" );
        return std::move(vAudioDevices);
    }

    if (defaultDevice != nullptr)
    {
        ZeroMemory(defaultDevice, sizeof(AudioDevice));

        IMMDevice *defaultImmDev = nullptr;

        // @pjb: get the default audio endpoint and make it the first one in the list
        if (SUCCEEDED(immDevEnum->GetDefaultAudioEndpoint(eRender, eConsole, &defaultImmDev)))
        {
            GetAudioDeviceDetails(defaultImmDev, defaultDevice);
            defaultImmDev->Release();
        }
    }

    hResult = immDevEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &immDevCollection);
    if (FAILED(hResult)) {
        idLib::Warning( "Failed to get audio endpoints" );
        return std::move(vAudioDevices);
    }

    hResult = immDevCollection->GetCount(&deviceCount);
    if (FAILED(hResult)) {
        idLib::Warning( "No audio devices found" );
        return std::move(vAudioDevices);
    }

    for (UINT i = 0; i < deviceCount; i++) {
        AudioDevice ad;

        hResult = immDevCollection->Item(i, &immDev);
        if (SUCCEEDED(hResult)) {
            hResult = GetAudioDeviceDetails(immDev, &ad);
        }

        if (SUCCEEDED(hResult)) {
            vAudioDevices.push_back(ad);
        }

        if (immDev != nullptr) {
            immDev->Release();
        }
    }

    immDevCollection->Release();
    immDevEnum->Release();

    return std::move(vAudioDevices);
}
コード例 #28
0
ファイル: wasapiengine.cpp プロジェクト: CUE0/gambatte
long WasapiEngine::doInit(long rate, int const latency) {
	{
		IMMDevice *pDevice = 0;
		IMMDeviceEnumerator *pEnumerator = 0;
		HRESULT hr;

		if (FAILED(CoCreateInstance(CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL,
		                            IID_IMMDeviceEnumerator,
		                            reinterpret_cast<void **>(&pEnumerator)))) {
			std::cerr << "CoCreateInstance failed" << std::endl;
			return -1;
		}

		if (deviceSelector->count() > 1) {
			hr = pEnumerator->GetDevice(
				deviceSelector->itemData(deviceIndex).value<std::wstring>().c_str(),
				&pDevice);
		} else
			hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);

		pEnumerator->Release();
		if (FAILED(hr)) {
			std::cerr << "pEnumerator->GetDefaultAudioEndpoint failed" << std::endl;
			return -1;
		}

		hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, 0,
		                       reinterpret_cast<void **>(&pAudioClient));
		pDevice->Release();
		if (FAILED(hr)) {
			std::cerr << "pDevice->Activate failed" << std::endl;
			return -1;
		}
	}

	{
		static GUID const ksdataformat_subtype_pcm = {
			WAVE_FORMAT_PCM, 0x0000, 0x0010,
			{ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
		};

		WAVEFORMATEXTENSIBLE wfext;
		std::memset(&wfext, 0, sizeof wfext);
		wfext.Format.cbSize = sizeof wfext - sizeof wfext.Format;
		wfext.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
		wfext.Format.nChannels = 2;
		wfext.Format.nSamplesPerSec = rate;
		wfext.Format.wBitsPerSample = 16;
		wfext.Samples.wValidBitsPerSample = 16;
		wfext.SubFormat = ksdataformat_subtype_pcm;
		wfext.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;

		if (!exclusive_.value()) {
			WAVEFORMATEX *mwfe = 0;
			if (SUCCEEDED(pAudioClient->GetMixFormat(&mwfe)) && mwfe) {
				wfext.Format.nChannels = std::max<int>(mwfe->nChannels, 2);
				wfext.Format.nSamplesPerSec = mwfe->nSamplesPerSec;
				if (mwfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
					wfext.dwChannelMask =
						reinterpret_cast<WAVEFORMATEXTENSIBLE *>(mwfe)->dwChannelMask;
				}

				CoTaskMemFree(mwfe);
			} else
				std::cerr << "pAudioClient->GetMixFormat failed\r\n";

			if (!(eventHandle_ = CreateEventA(0, false, false, 0)))
				std::cerr << "CreateEvent failed\r\n";
		}

		wfext.Format.nBlockAlign = wfext.Format.nChannels * wfext.Format.wBitsPerSample >> 3;
		wfext.Format.nAvgBytesPerSec = wfext.Format.nSamplesPerSec * wfext.Format.nBlockAlign;
		nchannels_ = wfext.Format.nChannels;
		rate = wfext.Format.nSamplesPerSec;

		HRESULT hr = pAudioClient->Initialize(
			exclusive_.value() ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
			eventHandle_ ? AUDCLNT_STREAMFLAGS_EVENTCALLBACK : 0,
			latency * 10000,
			0,
			&wfext.Format,
			0);
		if (FAILED(hr)) {
			std::cerr << "pAudioClient->Initialize failed: " << hr << "\r\n";
			return -1;
		}
	}

	if (eventHandle_ && FAILED(pAudioClient->SetEventHandle(eventHandle_))) {
		std::cerr << "pAudioClient->SetEventHandle failed\r\n";
		return -1;
	}
	if (FAILED(pAudioClient->GetBufferSize(&bufferFrameCount))) {
		std::cerr << "pAudioClient->GetBufferSize failed" << std::endl;
		return -1;
	}
	if (FAILED(pAudioClient->GetService(IID_IAudioRenderClient,
	                                    reinterpret_cast<void **>(&pRenderClient)))) {
		std::cerr << "pAudioClient->GetService failed" << std::endl;
		return -1;
	}
	if (FAILED(pAudioClient->GetService(IID_IAudioClock,
	                                    reinterpret_cast<void **>(&pAudioClock)))) {
		std::cerr << "pAudioClient->GetService failed" << std::endl;
		return -1;
	}

	{
		UINT64 freq = 0;
		pAudioClock->GetFrequency(&freq);
		posFrames = freq / (rate ? rate : 1);
	}

	pos_ = 0;
	est = RateEst(rate, bufferFrameCount);

	return rate;
}
コード例 #29
0
/*
========================
idSoundHardware_XAudio2::Init
========================
*/
void idSoundHardware_XAudio2::Init()
{

	cmdSystem->AddCommand( "listDevices", listDevices_f, 0, "Lists the connected sound devices", NULL );
	
	DWORD xAudioCreateFlags = 0;
	
// RB: not available on Windows 8 SDK
#if !defined(USE_WINRT) && defined(_DEBUG) // (_WIN32_WINNT < 0x0602 /*_WIN32_WINNT_WIN8*/) && defined(_DEBUG)
	xAudioCreateFlags |= XAUDIO2_DEBUG_ENGINE;
#endif
// RB end

	XAUDIO2_PROCESSOR xAudioProcessor = XAUDIO2_DEFAULT_PROCESSOR;
	
// RB: not available on Windows 8 SDK
	if( FAILED( XAudio2Create( &pXAudio2, xAudioCreateFlags, xAudioProcessor ) ) )
	{
#if !defined(USE_WINRT) && defined(_DEBUG) // (_WIN32_WINNT < 0x0602 /*_WIN32_WINNT_WIN8*/) && defined(_DEBUG)
		if( xAudioCreateFlags & XAUDIO2_DEBUG_ENGINE )
		{
			// in case the debug engine isn't installed
			xAudioCreateFlags &= ~XAUDIO2_DEBUG_ENGINE;
			if( FAILED( XAudio2Create( &pXAudio2, xAudioCreateFlags, xAudioProcessor ) ) )
			{
				idLib::FatalError( "Failed to create XAudio2 engine.  Try installing the latest DirectX." );
				return;
			}
		}
		else
#endif
// RB end
		{
			idLib::FatalError( "Failed to create XAudio2 engine.  Try installing the latest DirectX." );
			return;
		}
	}
#ifdef _DEBUG
	XAUDIO2_DEBUG_CONFIGURATION debugConfiguration = { 0 };
	debugConfiguration.TraceMask = XAUDIO2_LOG_WARNINGS;
	debugConfiguration.BreakMask = XAUDIO2_LOG_ERRORS;
	pXAudio2->SetDebugConfiguration( &debugConfiguration );
#endif
	
	// Register the sound engine callback
	pXAudio2->RegisterForCallbacks( &soundEngineCallback );
	soundEngineCallback.hardware = this;
	UINT32 deviceCount = 0;
	DWORD outputSampleRate = 44100; // Max( (DWORD)XAUDIO2FX_REVERB_MIN_FRAMERATE, Min( (DWORD)XAUDIO2FX_REVERB_MAX_FRAMERATE, deviceDetails.OutputFormat.Format.nSamplesPerSec ) );
	
	// RB: not available on Windows 8 SDK
#if defined(USE_WINRT) //(_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)
	
	IMMDeviceEnumerator*     immDevEnum       = nullptr;
	IMMDeviceCollection*     immDevCollection = nullptr;
	IMMDevice*               immDev           = nullptr;
	std::vector<AudioDevice> vAudioDevices;
	
	HRESULT hResult = CoCreateInstance(
						  __uuidof( MMDeviceEnumerator ), NULL,
						  CLSCTX_ALL, __uuidof( IMMDeviceEnumerator ), ( void** ) &immDevEnum );
						  
	if( FAILED( hResult ) )
	{
		idLib::Warning( "Failed to get audio enumerator" );
		pXAudio2->Release();
		pXAudio2 = NULL;
		return;
	}
	
	hResult = immDevEnum->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &immDevCollection );
	if( FAILED( hResult ) )
	{
		idLib::Warning( "Failed to get audio endpoints" );
		pXAudio2->Release();
		pXAudio2 = NULL;
		return;
	}
	
	hResult = immDevCollection->GetCount( &deviceCount );
	if( FAILED( hResult ) )
	{
		idLib::Warning( "No audio devices found" );
		pXAudio2->Release();
		pXAudio2 = NULL;
		return;
	}
	
	for( UINT i = 0; i < deviceCount; i++ )
	{
		IPropertyStore* propStore = nullptr;
		PROPVARIANT     varName;
		PROPVARIANT     varId;
		
		PropVariantInit( &varId );
		PropVariantInit( &varName );
		
		hResult = immDevCollection->Item( i, &immDev );
		if( SUCCEEDED( hResult ) )
		{
			hResult = immDev->OpenPropertyStore( STGM_READ, &propStore );
		}
		if( SUCCEEDED( hResult ) )
		{
			hResult = propStore->GetValue( PKEY_AudioEndpoint_Path, &varId );
		}
		
		if( SUCCEEDED( hResult ) )
		{
			hResult = propStore->GetValue( PKEY_Device_FriendlyName, &varName );
		}
		
		if( SUCCEEDED( hResult ) )
		{
			assert( varId.vt == VT_LPWSTR );
			assert( varName.vt == VT_LPWSTR );
			
			// Now save somewhere the device display name & id
			AudioDevice ad;
			ad.name = varName.pwszVal;
			ad.id   = varId.pwszVal;
			
			vAudioDevices.push_back( ad );
		}
		
		PropVariantClear( &varName );
		PropVariantClear( &varId );
		
		if( propStore != nullptr )
		{
			propStore->Release();
		}
		
		if( immDev != nullptr )
		{
			immDev->Release();
		}
	}
	
	
	immDevCollection->Release();
	immDevEnum->Release();
	
	int preferredDevice = s_device.GetInteger();
	if( !vAudioDevices.empty() )
	{
		if( SUCCEEDED( pXAudio2->CreateMasteringVoice( &pMasterVoice,
					   XAUDIO2_DEFAULT_CHANNELS,
					   outputSampleRate,
					   0,
					   vAudioDevices.at( 0 ).id.c_str(),
					   NULL,
					   AudioCategory_GameEffects ) ) )
		{
			XAUDIO2_VOICE_DETAILS deviceDetails;
			pMasterVoice->GetVoiceDetails( &deviceDetails );
			
			pMasterVoice->SetVolume( DBtoLinear( s_volume_dB.GetFloat() ) );
			
			outputChannels = deviceDetails.InputChannels;
			DWORD win8_channelMask;
			pMasterVoice->GetChannelMask( &win8_channelMask );
			
			channelMask = ( unsigned int )win8_channelMask;
			idLib::Printf( "Using device %s\n", vAudioDevices.at( 0 ).name );
		}
		else
		{
			idLib::Warning( "Failed to create master voice" );
			pXAudio2->Release();
			pXAudio2 = NULL;
			return;
		}
	}
	
#else
	if( pXAudio2->GetDeviceCount( &deviceCount ) != S_OK || deviceCount == 0 )
	{
		idLib::Warning( "No audio devices found" );
		pXAudio2->Release();
		pXAudio2 = NULL;
		return;
	}
	
	idCmdArgs args;
	listDevices_f( args );
	
	int preferredDevice = s_device.GetInteger();
	if( preferredDevice < 0 || preferredDevice >= ( int )deviceCount )
	{
		int preferredChannels = 0;
		for( unsigned int i = 0; i < deviceCount; i++ )
		{
			XAUDIO2_DEVICE_DETAILS deviceDetails;
			if( pXAudio2->GetDeviceDetails( i, &deviceDetails ) != S_OK )
			{
				continue;
			}
	
			if( deviceDetails.Role & DefaultGameDevice )
			{
				// if we find a device the user marked as their preferred 'game' device, then always use that
				preferredDevice = i;
				preferredChannels = deviceDetails.OutputFormat.Format.nChannels;
				break;
			}
	
			if( deviceDetails.OutputFormat.Format.nChannels > preferredChannels )
			{
				preferredDevice = i;
				preferredChannels = deviceDetails.OutputFormat.Format.nChannels;
			}
		}
	}
	
	idLib::Printf( "Using device %d\n", preferredDevice );
	
	XAUDIO2_DEVICE_DETAILS deviceDetails;
	if( pXAudio2->GetDeviceDetails( preferredDevice, &deviceDetails ) != S_OK )
	{
		// One way this could happen is if a device is removed between the loop and this line of code
		// Highly unlikely but possible
		idLib::Warning( "Failed to get device details" );
		pXAudio2->Release();
		pXAudio2 = NULL;
		return;
	}
	
	
	if( FAILED( pXAudio2->CreateMasteringVoice( &pMasterVoice, XAUDIO2_DEFAULT_CHANNELS, outputSampleRate, 0, preferredDevice, NULL ) ) )
	{
		idLib::Warning( "Failed to create master voice" );
		pXAudio2->Release();
		pXAudio2 = NULL;
		return;
	}
	pMasterVoice->SetVolume( DBtoLinear( s_volume_dB.GetFloat() ) );
	
	outputChannels = deviceDetails.OutputFormat.Format.nChannels;
	channelMask = deviceDetails.OutputFormat.dwChannelMask;
	
#endif // #if (_WIN32_WINNT < 0x0602 /*_WIN32_WINNT_WIN8*/)
	
	idSoundVoice::InitSurround( outputChannels, channelMask );
	
	// ---------------------
	// Create VU Meter Effect
	// ---------------------
	IUnknown* vuMeter = NULL;
	XAudio2CreateVolumeMeter( &vuMeter, 0 );
	
	XAUDIO2_EFFECT_DESCRIPTOR descriptor;
	descriptor.InitialState = true;
	descriptor.OutputChannels = outputChannels;
	descriptor.pEffect = vuMeter;
	
	XAUDIO2_EFFECT_CHAIN chain;
	chain.EffectCount = 1;
	chain.pEffectDescriptors = &descriptor;
	
	pMasterVoice->SetEffectChain( &chain );
	
	vuMeter->Release();
	
	// ---------------------
	// Create VU Meter Graph
	// ---------------------
	
	vuMeterRMS = console->CreateGraph( outputChannels );
	vuMeterPeak = console->CreateGraph( outputChannels );
	// DG: make sure they're not NULL (as it's currently the case with the cegui-based console)
	if( vuMeterRMS && vuMeterPeak )
	{
		vuMeterRMS->Enable( false );
		vuMeterPeak->Enable( false );
		
		memset( vuMeterPeakTimes, 0, sizeof( vuMeterPeakTimes ) );
		
		vuMeterPeak->SetFillMode( idDebugGraph::GRAPH_LINE );
		vuMeterPeak->SetBackgroundColor( idVec4( 0.0f, 0.0f, 0.0f, 0.0f ) );
		
		vuMeterRMS->AddGridLine( 0.500f, idVec4( 0.5f, 0.5f, 0.5f, 1.0f ) );
		vuMeterRMS->AddGridLine( 0.250f, idVec4( 0.5f, 0.5f, 0.5f, 1.0f ) );
		vuMeterRMS->AddGridLine( 0.125f, idVec4( 0.5f, 0.5f, 0.5f, 1.0f ) );
		
		const char* channelNames[] = { "L", "R", "C", "S", "Lb", "Rb", "Lf", "Rf", "Cb", "Ls", "Rs" };
		for( int i = 0, ci = 0; ci < sizeof( channelNames ) / sizeof( channelNames[0] ); ci++ )
		{
			if( ( channelMask & BIT( ci ) ) == 0 )
			{
				continue;
			}
			vuMeterRMS->SetLabel( i, channelNames[ci] );
			i++;
		}
	}
	
	// ---------------------
	// Create submix buffer
	// ---------------------
	if( FAILED( pXAudio2->CreateSubmixVoice( &pSubmixVoice, 1, outputSampleRate, 0, 0, NULL, NULL ) ) )
	{
		idLib::FatalError( "Failed to create submix voice" );
	}
	
	// XAudio doesn't really impose a maximum number of voices
	voices.SetNum( voices.Max() );
	freeVoices.SetNum( voices.Max() );
	zombieVoices.SetNum( 0 );
	for( int i = 0; i < voices.Num(); i++ )
	{
		freeVoices[i] = &voices[i];
	}
// RB end
}
コード例 #30
0
HRESULT list_devices() {
    HRESULT hr = S_OK;

    // get an enumerator
    IMMDeviceEnumerator *pMMDeviceEnumerator;

    hr = CoCreateInstance(
        __uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, 
        __uuidof(IMMDeviceEnumerator),
        (void**)&pMMDeviceEnumerator
    );
    if (FAILED(hr)) {
        printf("CoCreateInstance(IMMDeviceEnumerator) failed: hr = 0x%08x\n", hr);
        return hr;
    }

    IMMDeviceCollection *pMMDeviceCollection;

    // get all the active render endpoints
    hr = pMMDeviceEnumerator->EnumAudioEndpoints(
        eRender, DEVICE_STATE_ACTIVE, &pMMDeviceCollection
    );
    pMMDeviceEnumerator->Release();
    if (FAILED(hr)) {
        printf("IMMDeviceEnumerator::EnumAudioEndpoints failed: hr = 0x%08x\n", hr);
        return hr;
    }

    UINT count;
    hr = pMMDeviceCollection->GetCount(&count);
    if (FAILED(hr)) {
        pMMDeviceCollection->Release();
        printf("IMMDeviceCollection::GetCount failed: hr = 0x%08x\n", hr);
        return hr;
    }
    printf("Active render endpoints found: %u\n", count);

    for (UINT i = 0; i < count; i++) {
        IMMDevice *pMMDevice;

        // get the "n"th device
        hr = pMMDeviceCollection->Item(i, &pMMDevice);
        if (FAILED(hr)) {
            pMMDeviceCollection->Release();
            printf("IMMDeviceCollection::Item failed: hr = 0x%08x\n", hr);
            return hr;
        }

        // open the property store on that device
        IPropertyStore *pPropertyStore;
        hr = pMMDevice->OpenPropertyStore(STGM_READ, &pPropertyStore);
        pMMDevice->Release();
        if (FAILED(hr)) {
            pMMDeviceCollection->Release();
            printf("IMMDevice::OpenPropertyStore failed: hr = 0x%08x\n", hr);
            return hr;
        }

        // get the long name property
        PROPVARIANT pv; PropVariantInit(&pv);
        hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv);
        pPropertyStore->Release();
        if (FAILED(hr)) {
            pMMDeviceCollection->Release();
            printf("IPropertyStore::GetValue failed: hr = 0x%08x\n", hr);
            return hr;
        }

        if (VT_LPWSTR != pv.vt) {
            printf("PKEY_Device_FriendlyName variant type is %u - expected VT_LPWSTR", pv.vt);

            PropVariantClear(&pv);
            pMMDeviceCollection->Release();
            return E_UNEXPECTED;
        }

        printf("    %ls\n", pv.pwszVal);
        
        PropVariantClear(&pv);
    }    
    pMMDeviceCollection->Release();
    
    return S_OK;
}