HRESULT WasapiWrap::DoDeviceEnumeration(void) { HRESULT hr = 0; IMMDeviceEnumerator *deviceEnumerator = nullptr; m_deviceInfo.clear(); HRR(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&deviceEnumerator))); HRR(deviceEnumerator->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &m_deviceCollection)); UINT nDevices = 0; HRG(m_deviceCollection->GetCount(&nDevices)); for (UINT i = 0; i<nDevices; ++i) { wchar_t name[WW_DEVICE_NAME_COUNT]; HRG(DeviceNameGet(m_deviceCollection, i, name, sizeof name)); m_deviceInfo.push_back(WWDeviceInfo(i, name)); } end: SafeRelease(&deviceEnumerator); return hr; }
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); }
// 获取设备音量 int CCoreAudioVolume::GetDevicePlayVol(void) { IMMDeviceEnumerator* pEnumerator; IMMDeviceCollection* pCollection = NULL; IMMDevice *pDevice = NULL; IAudioEndpointVolume *pVolumeAPI=NULL; UINT deviceCount = 0; HRESULT hr; float fVolume = -1; CoInitializeEx( NULL , COINIT_MULTITHREADED ); //实例化 MMDeviceEnumerator 枚举器 hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),(void**)&pEnumerator); if (hr != S_OK) { goto FreeEnumerator; } // 枚举 设备到设备容器 eRander:放音设备,DEVICE_STATE_ACTIVE 为当前已激活的设备,禁用和无连接的用其他状态参数 hr = pEnumerator->EnumAudioEndpoints( eRender , DEVICE_STATE_ACTIVE , &pCollection ); if (hr != S_OK) { goto FreeCollection; } // 设备容器里的总数 hr = pCollection->GetCount(&deviceCount); if (hr != S_OK) { goto FreeCollection; } for (UINT dev=0; dev<deviceCount; dev++) { pDevice = NULL; hr = pCollection->Item(dev,&pDevice); if (hr == S_OK) { if (VerifyDev(pDevice,eRender)) { // 用 pDevice 的 Activate 方法初始一个 IAudioEndpointVolume 接口 hr = pDevice->Activate(__uuidof(IAudioEndpointVolume),CLSCTX_ALL,NULL,(void **)(&pVolumeAPI)); // 使用 IAudioEndpintVolume 的方法获取音量,设置音量,设置静音等 hr = pVolumeAPI->GetMasterVolumeLevelScalar(&fVolume); break; } } } FreeCollection: SAFE_RELEASE(pCollection); FreeEnumerator: SAFE_RELEASE(pEnumerator); CoUninitialize(); if (fVolume > 0) return fVolume*100; else return fVolume; return 0; }
void AudioMasterMind::printDevices() { CoInitialize(NULL); IMMDeviceEnumerator* deviceEnumeratorPtr = NULL; HRESULT hr = CoCreateInstance( __uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&deviceEnumeratorPtr ); if (FAILED(hr)) { BOOST_LOG_TRIVIAL(error) << "Failed to create IMMDeviceEnumerator hr:" << hr; return; } IMMDeviceCollection* deviceCollectionPtr = NULL; hr = deviceEnumeratorPtr->EnumAudioEndpoints(eAll, DEVICE_STATEMASK_ALL, &deviceCollectionPtr); if (FAILED(hr)) { BOOST_LOG_TRIVIAL(error) << "Failed to enumerate audio endpoints "; return; } UINT deviceCount = 0; hr = deviceCollectionPtr->GetCount(&deviceCount); if (FAILED(hr)) { BOOST_LOG_TRIVIAL(error) << "Failed to get the count of devices"; return; } BOOST_LOG_TRIVIAL(info) << "Device Count is: " << deviceCount; for (unsigned int i = 0; i < deviceCount; ++i) { IMMDevice* devicePtr = NULL; hr = deviceCollectionPtr->Item(i, &devicePtr); if (FAILED(hr)) { BOOST_LOG_TRIVIAL(error) << "Failed to get item no. " << i; return; } printDevice(devicePtr); } }
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; }
void _GetCaptureDeviceList(InternalDeviceInfo *pInternalDeviceInfo) { IMMDeviceEnumerator *pEnumerator = pInternalDeviceInfo->pEnumerator; IMMDeviceCollection *pCaptureCollection = NULL; // DEVICE_STATE_DISABLED | DEVICE_STATE_NOTPRESENT seems not work here. // So the google propose using 0x10000000 instead of the tags above. HRESULT hr = pEnumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE | 0x10000000, &pCaptureCollection); // assert(hr == S_OK); SAFE_RELEASE(pInternalDeviceInfo->pCaptureCollection); pInternalDeviceInfo->pCaptureCollection = pCaptureCollection; return; }
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; }
// // Based on the input switches, pick the specified device to use. // bool PickDevice(IMMDevice **DeviceToUse, UINT AudioDeviceIndex) { IMMDeviceEnumerator *deviceEnumerator = NULL; IMMDeviceCollection *deviceCollection = NULL; HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&deviceEnumerator)); PersistentAssert(SUCCEEDED(hr), "CoCreateInstance failed"); IMMDevice *device = NULL; // // The user didn't specify an output device, prompt the user for a device and use that. // hr = deviceEnumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE, &deviceCollection); PersistentAssert(SUCCEEDED(hr), "deviceEnumerator->EnumAudioEndpoints failed"); UINT deviceCount; hr = deviceCollection->GetCount(&deviceCount); PersistentAssert(SUCCEEDED(hr), "deviceCollection->GetCount failed"); for (UINT DeviceIndex = 0 ; DeviceIndex < deviceCount; DeviceIndex++) { String deviceName = GetDeviceName(deviceCollection, DeviceIndex); //Console::WriteLine(String(DeviceIndex) + String(": ") + deviceName); } int deviceIndex = 0; if(AudioDeviceIndex < deviceCount) { deviceIndex = AudioDeviceIndex; } hr = deviceCollection->Item(deviceIndex, DeviceToUse); PersistentAssert(DeviceToUse != NULL && SUCCEEDED(hr), "deviceCollection->Item failed"); SafeRelease(&deviceCollection); SafeRelease(&deviceEnumerator); return true; }
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(); } }
void CAESinkDirectSound::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool force) { CAEDeviceInfo deviceInfo; IMMDeviceEnumerator* pEnumerator = NULL; IMMDeviceCollection* pEnumDevices = NULL; HRESULT hr; /* See if we are on Windows XP */ if (!g_sysinfo.IsWindowsVersionAtLeast(CSysInfo::WindowsVersionVista)) { /* We are on XP - WASAPI not supported - enumerate using DS devices */ LPGUID deviceGUID = NULL; RPC_CSTR cszGUID; std::string szGUID; std::list<DSDevice> DSDeviceList; DirectSoundEnumerate(DSEnumCallback, &DSDeviceList); for(std::list<DSDevice>::iterator itt = DSDeviceList.begin(); itt != DSDeviceList.end(); ++itt) { if (UuidToString((*itt).lpGuid, &cszGUID) != RPC_S_OK) continue; /* could not convert GUID to string - skip device */ deviceInfo.m_channels.Reset(); deviceInfo.m_dataFormats.clear(); deviceInfo.m_sampleRates.clear(); szGUID = (LPSTR)cszGUID; deviceInfo.m_deviceName = "{" + szGUID + "}"; deviceInfo.m_displayName = (*itt).name; deviceInfo.m_displayNameExtra = std::string("DirectSound: ") + (*itt).name; deviceInfo.m_deviceType = AE_DEVTYPE_PCM; deviceInfo.m_channels = layoutsByChCount[2]; deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_FLOAT)); deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3)); deviceInfo.m_sampleRates.push_back((DWORD) 96000); deviceInfoList.push_back(deviceInfo); } RpcStringFree(&cszGUID); return; } /* Windows Vista or later - supporting WASAPI device probing */ hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr) UINT uiCount = 0; hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.") hr = pEnumDevices->GetCount(&uiCount); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.") for (UINT i = 0; i < uiCount; i++) { IMMDevice *pDevice = NULL; IPropertyStore *pProperty = NULL; PROPVARIANT varName; PropVariantInit(&varName); deviceInfo.m_channels.Reset(); deviceInfo.m_dataFormats.clear(); deviceInfo.m_sampleRates.clear(); hr = pEnumDevices->Item(i, &pDevice); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint failed."); goto failed; } hr = pDevice->OpenPropertyStore(STGM_READ, &pProperty); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint properties failed."); SAFE_RELEASE(pDevice); goto failed; } hr = pProperty->GetValue(PKEY_Device_FriendlyName, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint device name failed."); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); goto failed; } std::string strFriendlyName = localWideToUtf(varName.pwszVal); PropVariantClear(&varName); hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint GUID failed."); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); goto failed; } std::string strDevName = localWideToUtf(varName.pwszVal); PropVariantClear(&varName); hr = pProperty->GetValue(PKEY_AudioEndpoint_FormFactor, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint form factor failed."); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); goto failed; } std::string strWinDevType = winEndpoints[(EndpointFormFactor)varName.uiVal].winEndpointType; AEDeviceType aeDeviceType = winEndpoints[(EndpointFormFactor)varName.uiVal].aeDeviceType; PropVariantClear(&varName); /* In shared mode Windows tells us what format the audio must be in. */ IAudioClient *pClient; hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pClient); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Activate device failed (%s)", WASAPIErrToStr(hr)); goto failed; } //hr = pClient->GetMixFormat(&pwfxex); hr = pProperty->GetValue(PKEY_AudioEngine_DeviceFormat, &varName); if (SUCCEEDED(hr) && varName.blob.cbSize > 0) { WAVEFORMATEX* smpwfxex = (WAVEFORMATEX*)varName.blob.pBlobData; deviceInfo.m_channels = layoutsByChCount[std::max(std::min(smpwfxex->nChannels, (WORD) DS_SPEAKER_COUNT), (WORD) 2)]; deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_FLOAT)); deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3)); deviceInfo.m_sampleRates.push_back(std::min(smpwfxex->nSamplesPerSec, (DWORD) 192000)); } else { CLog::Log(LOGERROR, __FUNCTION__": Getting DeviceFormat failed (%s)", WASAPIErrToStr(hr)); } pClient->Release(); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); deviceInfo.m_deviceName = strDevName; deviceInfo.m_displayName = strWinDevType.append(strFriendlyName); deviceInfo.m_displayNameExtra = std::string("DirectSound: ").append(strFriendlyName); deviceInfo.m_deviceType = aeDeviceType; deviceInfoList.push_back(deviceInfo); } // since AE takes the first device in deviceInfoList as default audio device we need // to sort it in order to use the real default device if(deviceInfoList.size() > 1) { std::string strDD = GetDefaultDevice(); for (AEDeviceInfoList::iterator itt = deviceInfoList.begin(); itt != deviceInfoList.end(); ++itt) { CAEDeviceInfo devInfo = *itt; if(devInfo.m_deviceName == strDD) { deviceInfoList.erase(itt); deviceInfoList.insert(deviceInfoList.begin(), devInfo); break; } } } return; failed: if (FAILED(hr)) CLog::Log(LOGERROR, __FUNCTION__": Failed to enumerate WASAPI endpoint devices (%s).", WASAPIErrToStr(hr)); SAFE_RELEASE(pEnumDevices); SAFE_RELEASE(pEnumerator); }
Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit) { WAVEFORMATEX *pwfex; IMMDeviceEnumerator *enumerator = NULL; IMMDevice *device = NULL; CoInitialize(NULL); HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); if (p_device->device_name == "Default") { hr = enumerator->GetDefaultAudioEndpoint(p_capture ? eCapture : eRender, eConsole, &device); } else { IMMDeviceCollection *devices = NULL; hr = enumerator->EnumAudioEndpoints(p_capture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); LPWSTR strId = NULL; bool found = false; UINT count = 0; hr = devices->GetCount(&count); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); for (ULONG i = 0; i < count && !found; 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); if (p_device->device_name == String(propvar.pwszVal)) { hr = device->GetId(&strId); ERR_BREAK(hr != S_OK); found = true; } PropVariantClear(&propvar); props->Release(); device->Release(); } if (found) { hr = enumerator->GetDevice(strId, &device); } if (strId) { CoTaskMemFree(strId); } if (device == NULL) { hr = enumerator->GetDefaultAudioEndpoint(p_capture ? eCapture : eRender, eConsole, &device); } } if (reinit) { // In case we're trying to re-initialize the device prevent throwing this error on the console, // otherwise if there is currently no device available this will spam the console. if (hr != S_OK) { return ERR_CANT_OPEN; } } else { ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); } hr = enumerator->RegisterEndpointNotificationCallback(¬if_client); SAFE_RELEASE(enumerator) if (hr != S_OK) { ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error"); } hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&p_device->audio_client); SAFE_RELEASE(device) if (reinit) { if (hr != S_OK) { return ERR_CANT_OPEN; } } else { ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); } hr = p_device->audio_client->GetMixFormat(&pwfex); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); // Since we're using WASAPI Shared Mode we can't control any of these, we just tag along p_device->channels = pwfex->nChannels; p_device->format_tag = pwfex->wFormatTag; p_device->bits_per_sample = pwfex->wBitsPerSample; p_device->frame_size = (p_device->bits_per_sample / 8) * p_device->channels; if (p_device->format_tag == WAVE_FORMAT_EXTENSIBLE) { WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE *)pwfex; if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_PCM) { p_device->format_tag = WAVE_FORMAT_PCM; } else if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) { p_device->format_tag = WAVE_FORMAT_IEEE_FLOAT; } else { ERR_PRINT("WASAPI: Format not supported"); ERR_FAIL_V(ERR_CANT_OPEN); } } else { if (p_device->format_tag != WAVE_FORMAT_PCM && p_device->format_tag != WAVE_FORMAT_IEEE_FLOAT) { ERR_PRINT("WASAPI: Format not supported"); ERR_FAIL_V(ERR_CANT_OPEN); } } DWORD streamflags = 0; if (mix_rate != pwfex->nSamplesPerSec) { streamflags |= AUDCLNT_STREAMFLAGS_RATEADJUST; pwfex->nSamplesPerSec = mix_rate; pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nChannels * (pwfex->wBitsPerSample / 8); } hr = p_device->audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, p_capture ? REFTIMES_PER_SEC : 0, 0, pwfex, NULL); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); if (p_capture) { hr = p_device->audio_client->GetService(IID_IAudioCaptureClient, (void **)&p_device->capture_client); } else { hr = p_device->audio_client->GetService(IID_IAudioRenderClient, (void **)&p_device->render_client); } ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); // Free memory CoTaskMemFree(pwfex); SAFE_RELEASE(device) return OK; }
void CAESinkWASAPI::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool force) { IMMDeviceEnumerator* pEnumerator = NULL; IMMDeviceCollection* pEnumDevices = NULL; IMMDevice* pDefaultDevice = NULL; CAEDeviceInfo deviceInfo; CAEChannelInfo deviceChannels; LPWSTR pwszID = NULL; std::wstring wstrDDID; WAVEFORMATEXTENSIBLE wfxex = {0}; HRESULT hr; hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr) UINT uiCount = 0; // get the default audio endpoint if(pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDefaultDevice) == S_OK) { if(pDefaultDevice->GetId(&pwszID) == S_OK) { wstrDDID = pwszID; CoTaskMemFree(pwszID); } SAFE_RELEASE(pDefaultDevice); } // enumerate over all audio endpoints hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.") hr = pEnumDevices->GetCount(&uiCount); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.") for (UINT i = 0; i < uiCount; i++) { IMMDevice *pDevice = NULL; IPropertyStore *pProperty = NULL; PROPVARIANT varName; PropVariantInit(&varName); deviceInfo.m_channels.Reset(); deviceInfo.m_dataFormats.clear(); deviceInfo.m_sampleRates.clear(); hr = pEnumDevices->Item(i, &pDevice); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint failed."); goto failed; } hr = pDevice->OpenPropertyStore(STGM_READ, &pProperty); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint properties failed."); SAFE_RELEASE(pDevice); goto failed; } hr = pProperty->GetValue(PKEY_Device_FriendlyName, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint device name failed."); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); goto failed; } std::string strFriendlyName = localWideToUtf(varName.pwszVal); PropVariantClear(&varName); hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName); if(FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed."); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); goto failed; } std::string strDevName = localWideToUtf(varName.pwszVal); PropVariantClear(&varName); hr = pProperty->GetValue(PKEY_AudioEndpoint_FormFactor, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint form factor failed."); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); goto failed; } std::string strWinDevType = winEndpoints[(EndpointFormFactor)varName.uiVal].winEndpointType; AEDeviceType aeDeviceType = winEndpoints[(EndpointFormFactor)varName.uiVal].aeDeviceType; PropVariantClear(&varName); hr = pProperty->GetValue(PKEY_AudioEndpoint_PhysicalSpeakers, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint speaker layout failed."); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); goto failed; } unsigned int uiChannelMask = std::max(varName.uintVal, (unsigned int) KSAUDIO_SPEAKER_STEREO); deviceChannels.Reset(); for (unsigned int c = 0; c < WASAPI_SPEAKER_COUNT; c++) { if (uiChannelMask & WASAPIChannelOrder[c]) deviceChannels += AEChannelNames[c]; } PropVariantClear(&varName); IAudioClient *pClient; hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pClient); if (SUCCEEDED(hr)) { /* Test format DTS-HD */ wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); wfxex.Format.nSamplesPerSec = 192000; wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND; wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD; wfxex.Format.wBitsPerSample = 16; wfxex.Samples.wValidBitsPerSample = 16; wfxex.Format.nChannels = 8; wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3); wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign; hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL); if (SUCCEEDED(hr)) deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTSHD)); /* Test format Dolby TrueHD */ wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP; hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL); if (SUCCEEDED(hr)) deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_TRUEHD)); /* Test format Dolby EAC3 */ wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS; wfxex.Format.nChannels = 2; wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3); wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign; hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL); if (SUCCEEDED(hr)) deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_EAC3)); /* Test format DTS */ wfxex.Format.nSamplesPerSec = 48000; wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1; wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS; wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3); wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign; hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL); if (SUCCEEDED(hr)) deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTS)); /* Test format Dolby AC3 */ wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL; hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL); if (SUCCEEDED(hr)) deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3)); /* Test format AAC */ wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_AAC; hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL); if (SUCCEEDED(hr)) deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AAC)); /* Test format for PCM format iteration */ wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO; wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; for (int p = AE_FMT_FLOAT; p > AE_FMT_INVALID; p--) { if (p < AE_FMT_FLOAT) wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) p); wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3); wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign; if (p <= AE_FMT_S24NE4 && p >= AE_FMT_S24BE4) { wfxex.Samples.wValidBitsPerSample = 24; } else { wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample; } hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL); if (SUCCEEDED(hr)) deviceInfo.m_dataFormats.push_back((AEDataFormat) p); } /* Test format for sample rate iteration */ wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO; wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; wfxex.Format.wBitsPerSample = 16; wfxex.Samples.wValidBitsPerSample = 16; wfxex.Format.nChannels = 2; wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3); wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign; for (int j = 0; j < WASAPISampleRateCount; j++) { wfxex.Format.nSamplesPerSec = WASAPISampleRates[j]; wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign; hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL); if (SUCCEEDED(hr)) deviceInfo.m_sampleRates.push_back(WASAPISampleRates[j]); } /* Test format for channels iteration */ wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO; wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; wfxex.Format.nSamplesPerSec = 48000; wfxex.Format.wBitsPerSample = 16; wfxex.Samples.wValidBitsPerSample = 16; wfxex.Format.nChannels = 2; wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3); wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign; bool hasLpcm = false; // Try with KSAUDIO_SPEAKER_DIRECTOUT for (unsigned int k = WASAPI_SPEAKER_COUNT; k > 0; k--) { wfxex.dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT; wfxex.Format.nChannels = k; wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3); wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign; hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL); if (SUCCEEDED(hr)) { if (k > 3) // Add only multichannel LPCM { deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM); hasLpcm = true; } break; } } /* Try with reported channel mask */ for (unsigned int k = WASAPI_SPEAKER_COUNT; k > 0; k--) { wfxex.dwChannelMask = uiChannelMask; wfxex.Format.nChannels = k; wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3); wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign; hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL); if (SUCCEEDED(hr)) { if ( !hasLpcm && k > 3) // Add only multichannel LPCM { deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM); hasLpcm = true; } break; } } /* Try with specific speakers configurations */ for (unsigned int i = 0; i < ARRAYSIZE(layoutsList); i++) { unsigned int nmbOfCh; wfxex.dwChannelMask = ChLayoutToChMask(layoutsList[i], &nmbOfCh); wfxex.Format.nChannels = nmbOfCh; wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3); wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign; hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL); if (SUCCEEDED(hr)) { if ( deviceChannels.Count() < nmbOfCh) deviceChannels = layoutsList[i]; if ( !hasLpcm && nmbOfCh > 3) // Add only multichannel LPCM { deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM); hasLpcm = true; } } } pClient->Release(); } else { CLog::Log(LOGDEBUG, __FUNCTION__": Failed to activate device for passthrough capability testing."); } deviceInfo.m_deviceName = strDevName; deviceInfo.m_displayName = strWinDevType.append(strFriendlyName); deviceInfo.m_displayNameExtra = std::string("WASAPI: ").append(strFriendlyName); deviceInfo.m_deviceType = aeDeviceType; deviceInfo.m_channels = deviceChannels; /* Store the device info */ deviceInfoList.push_back(deviceInfo); if(pDevice->GetId(&pwszID) == S_OK) { if(wstrDDID.compare(pwszID) == 0) { deviceInfo.m_deviceName = std::string("default"); deviceInfo.m_displayName = std::string("default"); deviceInfo.m_displayNameExtra = std::string(""); deviceInfoList.push_back(deviceInfo); } CoTaskMemFree(pwszID); } SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); }
bool CAESinkWASAPI::Initialize(AEAudioFormat &format, std::string &device) { if (m_initialized) return false; m_device = device; bool bdefault = false; /* Save requested format */ /* Clear returned format */ sinkReqFormat = format.m_dataFormat; sinkRetFormat = AE_FMT_INVALID; IMMDeviceEnumerator* pEnumerator = NULL; IMMDeviceCollection* pEnumDevices = NULL; HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr) /* Get our device. First try to find the named device. */ UINT uiCount = 0; hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.") hr = pEnumDevices->GetCount(&uiCount); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.") if(StringUtils::EndsWithNoCase(device, std::string("default"))) bdefault = true; if(!bdefault) { for (UINT i = 0; i < uiCount; i++) { IPropertyStore *pProperty = NULL; PROPVARIANT varName; hr = pEnumDevices->Item(i, &m_pDevice); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint failed.") hr = m_pDevice->OpenPropertyStore(STGM_READ, &pProperty); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.") hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed."); SAFE_RELEASE(pProperty); goto failed; } std::string strDevName = localWideToUtf(varName.pwszVal); if (device == strDevName) i = uiCount; else SAFE_RELEASE(m_pDevice); PropVariantClear(&varName); SAFE_RELEASE(pProperty); } } SAFE_RELEASE(pEnumDevices); if (!m_pDevice) { if(!bdefault) CLog::Log(LOGINFO, __FUNCTION__": Could not locate the device named \"%s\" in the list of WASAPI endpoint devices. Trying the default device...", device.c_str()); hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_pDevice); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not retrieve the default WASAPI audio endpoint.") IPropertyStore *pProperty = NULL; PROPVARIANT varName; hr = m_pDevice->OpenPropertyStore(STGM_READ, &pProperty); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.") hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName); device = localWideToUtf(varName.pwszVal); PropVariantClear(&varName); SAFE_RELEASE(pProperty); } SAFE_RELEASE(pEnumerator); hr = m_pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&m_pAudioClient); EXIT_ON_FAILURE(hr, __FUNCTION__": Activating the WASAPI endpoint device failed.") if (!InitializeExclusive(format)) { CLog::Log(LOGINFO, __FUNCTION__": Could not Initialize Exclusive with that format"); goto failed; } /* get the buffer size and calculate the frames for AE */ m_pAudioClient->GetBufferSize(&m_uiBufferLen); format.m_frames = m_uiBufferLen; format.m_frameSamples = format.m_frames * format.m_channelLayout.Count(); m_format = format; sinkRetFormat = format.m_dataFormat; hr = m_pAudioClient->GetService(IID_IAudioRenderClient, (void**)&m_pRenderClient); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not initialize the WASAPI render client interface.") m_needDataEvent = CreateEvent(NULL, FALSE, FALSE, NULL); hr = m_pAudioClient->SetEventHandle(m_needDataEvent); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not set the WASAPI event handler."); m_initialized = true; m_isDirty = false; // allow feeding less samples than buffer size // if the device is opened exclusive and event driven, provided samples must match buffersize // ActiveAE tries to align provided samples with buffer size but cannot guarantee (e.g. transcoding) // this can be avoided by dropping the event mode which has not much benefit; SoftAE polls anyway delete [] m_pBuffer; m_pBuffer = new uint8_t[format.m_frames * format.m_frameSize]; m_bufferPtr = 0; return true; failed: CLog::Log(LOGERROR, __FUNCTION__": WASAPI initialization failed."); SAFE_RELEASE(pEnumDevices); SAFE_RELEASE(pEnumerator); SAFE_RELEASE(m_pRenderClient); SAFE_RELEASE(m_pAudioClient); SAFE_RELEASE(m_pDevice); if(m_needDataEvent) { CloseHandle(m_needDataEvent); m_needDataEvent = 0; } return false; }
bool CWin32WASAPI::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, bool bIsMusic, bool bAudioPassthrough) { CLog::Log(LOGDEBUG, __FUNCTION__": endpoint device %s", device.c_str()); //First check if the version of Windows we are running on even supports WASAPI. if (!g_sysinfo.IsVistaOrHigher()) { CLog::Log(LOGERROR, __FUNCTION__": WASAPI output requires Vista or higher."); return false; } //Only one exclusive stream may be initialized at one time. if(m_bIsAllocated) { CLog::Log(LOGERROR, __FUNCTION__": Cannot create more then one WASAPI stream at one time."); return false; } int layoutChannels = 0; if(!bAudioPassthrough) { //If no channel map is specified, use the default. if(!channelMap) channelMap = (PCMChannels *)wasapi_default_channel_layout[iChannels - 1]; PCMChannels *outLayout = m_remap.SetInputFormat(iChannels, channelMap, uiBitsPerSample / 8); for(PCMChannels *channel = outLayout; *channel != PCM_INVALID; channel++) ++layoutChannels; //Expand monural to stereo as most devices don't seem to like 1 channel PCM streams. //Stereo sources should be sent explicitly as two channels so that the external hardware //can apply ProLogic/5CH Stereo/etc processing on it. if(iChannels <= 2) { BuildChannelMapping(2, (PCMChannels *)wasapi_default_channel_layout[1]); layoutChannels = 2; m_remap.SetOutputFormat(2, m_SpeakerOrder, false); } else //Do the standard remapping. { BuildChannelMapping(layoutChannels, outLayout); m_remap.SetOutputFormat(layoutChannels, m_SpeakerOrder, false); } } m_bPlaying = false; m_bPause = false; m_bMuting = false; m_uiChannels = iChannels; m_uiBitsPerSample = uiBitsPerSample; m_bPassthrough = bAudioPassthrough; m_nCurrentVolume = g_settings.m_nVolumeLevel; m_pcmAmplifier.SetVolume(m_nCurrentVolume); WAVEFORMATEXTENSIBLE wfxex = {0}; //fill waveformatex ZeroMemory(&wfxex, sizeof(WAVEFORMATEXTENSIBLE)); wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); wfxex.Format.nChannels = layoutChannels; wfxex.Format.nSamplesPerSec = uiSamplesPerSec; if (bAudioPassthrough == true) { wfxex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; wfxex.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; wfxex.SubFormat = _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF; wfxex.Format.wBitsPerSample = 16; wfxex.Format.nChannels = 2; } else { wfxex.dwChannelMask = m_uiSpeakerMask; wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; wfxex.Format.wBitsPerSample = uiBitsPerSample; } wfxex.Samples.wValidBitsPerSample = uiBitsPerSample == 32 ? 24 : uiBitsPerSample; wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3); wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign; m_uiAvgBytesPerSec = wfxex.Format.nAvgBytesPerSec; m_uiBytesPerFrame = wfxex.Format.nBlockAlign; m_uiBytesPerSrcFrame = bAudioPassthrough ? m_uiBytesPerFrame : iChannels * wfxex.Format.wBitsPerSample >> 3; IMMDeviceEnumerator* pEnumerator = NULL; IMMDeviceCollection* pEnumDevices = NULL; //Shut down Directsound. g_audioContext.SetActiveDevice(CAudioContext::NONE); HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %i", hr) //Get our device. //First try to find the named device. UINT uiCount = 0; hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.") hr = pEnumDevices->GetCount(&uiCount); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.") for(UINT i = 0; i < uiCount; i++) { IPropertyStore *pProperty = NULL; PROPVARIANT varName; hr = pEnumDevices->Item(i, &m_pDevice); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint failed.") hr = m_pDevice->OpenPropertyStore(STGM_READ, &pProperty); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.") hr = pProperty->GetValue(PKEY_Device_FriendlyName, &varName); if(FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint device name failed."); SAFE_RELEASE(pProperty); goto failed; } CStdStringW strRawDevName(varName.pwszVal); CStdString strDevName; g_charsetConverter.wToUTF8(strRawDevName, strDevName); if(device == strDevName) i = uiCount; else SAFE_RELEASE(m_pDevice); PropVariantClear(&varName); SAFE_RELEASE(pProperty); } SAFE_RELEASE(pEnumDevices); if(!m_pDevice) { CLog::Log(LOGDEBUG, __FUNCTION__": Could not locate the device named \"%s\" in the list of WASAPI endpoint devices. Trying the default device...", device.c_str()); hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_pDevice); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not retrieve the default WASAPI audio endpoint.") }
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); }
void CAESinkDirectSound::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool force) { CAEDeviceInfo deviceInfo; IMMDeviceEnumerator* pEnumerator = NULL; IMMDeviceCollection* pEnumDevices = NULL; HRESULT hr; std::string strDD = GetDefaultDevice(); /* Windows Vista or later - supporting WASAPI device probing */ hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr) UINT uiCount = 0; hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.") hr = pEnumDevices->GetCount(&uiCount); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.") for (UINT i = 0; i < uiCount; i++) { IMMDevice *pDevice = NULL; IPropertyStore *pProperty = NULL; PROPVARIANT varName; PropVariantInit(&varName); deviceInfo.m_channels.Reset(); deviceInfo.m_dataFormats.clear(); deviceInfo.m_sampleRates.clear(); hr = pEnumDevices->Item(i, &pDevice); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint failed."); goto failed; } hr = pDevice->OpenPropertyStore(STGM_READ, &pProperty); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint properties failed."); SAFE_RELEASE(pDevice); goto failed; } hr = pProperty->GetValue(PKEY_Device_FriendlyName, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint device name failed."); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); goto failed; } std::string strFriendlyName = localWideToUtf(varName.pwszVal); PropVariantClear(&varName); hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint GUID failed."); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); goto failed; } std::string strDevName = localWideToUtf(varName.pwszVal); PropVariantClear(&varName); hr = pProperty->GetValue(PKEY_AudioEndpoint_FormFactor, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint form factor failed."); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); goto failed; } std::string strWinDevType = winEndpoints[(EndpointFormFactor)varName.uiVal].winEndpointType; AEDeviceType aeDeviceType = winEndpoints[(EndpointFormFactor)varName.uiVal].aeDeviceType; PropVariantClear(&varName); /* In shared mode Windows tells us what format the audio must be in. */ IAudioClient *pClient; hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pClient); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Activate device failed (%s)", WASAPIErrToStr(hr)); goto failed; } //hr = pClient->GetMixFormat(&pwfxex); hr = pProperty->GetValue(PKEY_AudioEngine_DeviceFormat, &varName); if (SUCCEEDED(hr) && varName.blob.cbSize > 0) { WAVEFORMATEX* smpwfxex = (WAVEFORMATEX*)varName.blob.pBlobData; deviceInfo.m_channels = layoutsByChCount[std::max(std::min(smpwfxex->nChannels, (WORD) DS_SPEAKER_COUNT), (WORD) 2)]; deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_FLOAT)); deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3)); deviceInfo.m_sampleRates.push_back(std::min(smpwfxex->nSamplesPerSec, (DWORD) 192000)); } else { CLog::Log(LOGERROR, __FUNCTION__": Getting DeviceFormat failed (%s)", WASAPIErrToStr(hr)); } pClient->Release(); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); deviceInfo.m_deviceName = strDevName; deviceInfo.m_displayName = strWinDevType.append(strFriendlyName); deviceInfo.m_displayNameExtra = std::string("DirectSound: ").append(strFriendlyName); deviceInfo.m_deviceType = aeDeviceType; deviceInfoList.push_back(deviceInfo); // add the default device with m_deviceName = default if(strDD == strDevName) { deviceInfo.m_deviceName = std::string("default"); deviceInfo.m_displayName = std::string("default"); deviceInfo.m_displayNameExtra = std::string(""); deviceInfoList.push_back(deviceInfo); } } return; failed: if (FAILED(hr)) CLog::Log(LOGERROR, __FUNCTION__": Failed to enumerate WASAPI endpoint devices (%s).", WASAPIErrToStr(hr)); SAFE_RELEASE(pEnumDevices); SAFE_RELEASE(pEnumerator); }
void CAESinkDirectSound::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList) { CAEDeviceInfo deviceInfo; OSVERSIONINFO osvi; IMMDeviceEnumerator* pEnumerator = NULL; IMMDeviceCollection* pEnumDevices = NULL; WAVEFORMATEX* pwfxex = NULL; HRESULT hr; /* See if we are on Windows XP */ ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); if (osvi.dwMajorVersion == 5) { /* We are on XP - WASAPI not supported - enumerate using DS devices */ LPGUID deviceGUID = NULL; RPC_CSTR cszGUID; std::string szGUID; std::list<DSDevice> DSDeviceList; DirectSoundEnumerate(DSEnumCallback, &DSDeviceList); for(std::list<DSDevice>::iterator itt = DSDeviceList.begin(); itt != DSDeviceList.end(); itt++) { if (UuidToString((*itt).lpGuid, &cszGUID) != RPC_S_OK) continue; /* could not convert GUID to string - skip device */ deviceInfo.m_channels.Reset(); deviceInfo.m_dataFormats.clear(); deviceInfo.m_sampleRates.clear(); szGUID = (LPSTR)cszGUID; deviceInfo.m_deviceName = "{" + szGUID + "}"; deviceInfo.m_displayName = (*itt).name; deviceInfo.m_displayNameExtra = std::string("DirectSound: ") + (*itt).name; deviceInfo.m_deviceType = AE_DEVTYPE_PCM; deviceInfo.m_channels = layoutsByChCount[2]; deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_FLOAT)); deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3)); deviceInfo.m_sampleRates.push_back((DWORD) 96000); deviceInfoList.push_back(deviceInfo); } RpcStringFree(&cszGUID); return; } /* Windows Vista or later - supporting WASAPI device probing */ hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr) UINT uiCount = 0; hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.") hr = pEnumDevices->GetCount(&uiCount); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.") for (UINT i = 0; i < uiCount; i++) { IMMDevice *pDevice = NULL; IPropertyStore *pProperty = NULL; PROPVARIANT varName; PropVariantInit(&varName); deviceInfo.m_channels.Reset(); deviceInfo.m_dataFormats.clear(); deviceInfo.m_sampleRates.clear(); hr = pEnumDevices->Item(i, &pDevice); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint failed."); goto failed; } hr = pDevice->OpenPropertyStore(STGM_READ, &pProperty); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint properties failed."); SAFE_RELEASE(pDevice); goto failed; } hr = pProperty->GetValue(PKEY_Device_FriendlyName, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint device name failed."); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); goto failed; } std::wstring strRawFriendlyName(varName.pwszVal); std::string strFriendlyName = std::string(strRawFriendlyName.begin(), strRawFriendlyName.end()); PropVariantClear(&varName); hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint GUID failed."); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); goto failed; } std::wstring strRawDevName(varName.pwszVal); std::string strDevName = std::string(strRawDevName.begin(), strRawDevName.end()); PropVariantClear(&varName); hr = pProperty->GetValue(PKEY_AudioEndpoint_FormFactor, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of DirectSound endpoint form factor failed."); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); goto failed; } std::string strWinDevType = winEndpoints[(EndpointFormFactor)varName.uiVal].winEndpointType; AEDeviceType aeDeviceType = winEndpoints[(EndpointFormFactor)varName.uiVal].aeDeviceType; PropVariantClear(&varName); /* In shared mode Windows tells us what format the audio must be in. */ IAudioClient *pClient; hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pClient); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Activate device failed (%s)", WASAPIErrToStr(hr)); } //hr = pClient->GetMixFormat(&pwfxex); hr = pProperty->GetValue(PKEY_AudioEngine_DeviceFormat, &varName); if (SUCCEEDED(hr)) { WAVEFORMATEX* smpwfxex = (WAVEFORMATEX*)varName.blob.pBlobData; deviceInfo.m_channels = layoutsByChCount[std::min(smpwfxex->nChannels, (WORD) 2)]; deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_FLOAT)); deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3)); deviceInfo.m_sampleRates.push_back(std::min(smpwfxex->nSamplesPerSec, (DWORD) 96000)); } else { CLog::Log(LOGERROR, __FUNCTION__": GetMixFormat failed (%s)", WASAPIErrToStr(hr)); } pClient->Release(); SAFE_RELEASE(pDevice); SAFE_RELEASE(pProperty); deviceInfo.m_deviceName = strDevName; deviceInfo.m_displayName = strWinDevType.append(strFriendlyName); deviceInfo.m_displayNameExtra = std::string("DirectSound: ").append(strFriendlyName); deviceInfo.m_deviceType = aeDeviceType; /* Now logged by AESinkFactory on startup */ //CLog::Log(LOGDEBUG,"Audio Device %d: %s", i, ((std::string)deviceInfo).c_str()); deviceInfoList.push_back(deviceInfo); } return; failed: if (FAILED(hr)) CLog::Log(LOGERROR, __FUNCTION__": Failed to enumerate WASAPI endpoint devices (%s).", WASAPIErrToStr(hr)); SAFE_RELEASE(pEnumDevices); SAFE_RELEASE(pEnumerator); }
SexyAL_device *SexyALI_WASAPISH_Open(const char *id, SexyAL_format *format, SexyAL_buffering *buffering) { SexyAL_device *dev; WASWrap *w; IMMDeviceEnumerator *immdeven = NULL; WAVEFORMATEXTENSIBLE wfe; HRESULT hr; if(!(dev = (SexyAL_device *)calloc(1, sizeof(SexyAL_device)))) { printf("calloc failed.\n"); return(NULL); } timeBeginPeriod(1); w = (WASWrap *)calloc(1, sizeof(WASWrap)); dev->private_data = w; if(!w) { printf("calloc failed.\n"); Cleanup(dev); return(NULL); } // // // hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if(hr != S_OK && hr != S_FALSE) { printf("CoInitializeEx() failed: 0x%08x\n", (unsigned)hr); Cleanup(dev); return(NULL); } //printf("NOODLES: 0x%08x 0x%08x\n", LV_CLSID_MMDeviceEnumerator.Data1, LV_IID_IMMDeviceEnumerator.Data1); TRYHR(CoCreateInstance(LV_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, LV_IID_IMMDeviceEnumerator, (void**)&immdeven)); if(id == NULL) { TRYHR(immdeven->GetDefaultAudioEndpoint(eRender, eConsole, &w->immdev)); } else { IMMDeviceCollection *devcoll = NULL; UINT numdevs = 0; wchar_t *id16 = (wchar_t *)calloc(strlen(id) + 1, sizeof(wchar_t)); w->immdev = NULL; MultiByteToWideChar(CP_UTF8, 0, id, -1, id16, strlen(id) + 1); TRYHR(immdeven->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devcoll)); TRYHR(devcoll->GetCount(&numdevs)); for(UINT i = 0; i < numdevs && w->immdev == NULL; i++) { IMMDevice *tmpdev = NULL; IPropertyStore *props = NULL; PROPVARIANT prop_fname; PropVariantInit(&prop_fname); TRYHR(devcoll->Item(i, &tmpdev)); TRYHR(tmpdev->OpenPropertyStore(STGM_READ, &props)); TRYHR(props->GetValue(LV_PKEY_Device_FriendlyName, &prop_fname)); printf("Device: %S\n", prop_fname.pwszVal); if(!wcscmp(id16, prop_fname.pwszVal)) w->immdev = tmpdev; else { tmpdev->Release(); tmpdev = NULL; } PropVariantClear(&prop_fname); if(props != NULL) { props->Release(); props = NULL; } } if(id16 != NULL) { free(id16); id16 = NULL; } if(devcoll != NULL) { devcoll->Release(); devcoll = NULL; } if(w->immdev == NULL) { puts("Device not found!"); Cleanup(dev); return(NULL); } } TRYHR(w->immdev->Activate(LV_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&w->ac)); { WAVEFORMATEX *mf = NULL; TRYHR(w->ac->GetMixFormat(&mf)); memcpy(&wfe, mf, std::min<unsigned>(sizeof(WAVEFORMATEXTENSIBLE), sizeof(WAVEFORMATEX) + mf->cbSize)); if(wfe.Format.cbSize > 22) wfe.Format.cbSize = 22; wfe.Format.wBitsPerSample = 16; wfe.Format.nBlockAlign = (wfe.Format.nChannels * wfe.Format.wBitsPerSample) / 8; wfe.Format.nAvgBytesPerSec = wfe.Format.nSamplesPerSec * wfe.Format.nBlockAlign; if(wfe.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) { wfe.Samples.wValidBitsPerSample = wfe.Format.wBitsPerSample; wfe.SubFormat = LV_KSDATAFORMAT_SUBTYPE_PCM; } else { wfe.Format.wFormatTag = WAVE_FORMAT_PCM; } CoTaskMemFree(mf); } format->rate = wfe.Format.nSamplesPerSec; format->sampformat = ((wfe.Format.wBitsPerSample >> 3) << 4) | 1; if(wfe.Format.wBitsPerSample == 32) format->sampformat |= 2; format->channels = wfe.Format.nChannels; format->revbyteorder = false; format->noninterleaved = false; // // // { REFERENCE_TIME raw_ac_latency; int32_t des_effbuftime = buffering->ms ? buffering->ms : 52; int32_t des_effbufsize = (int64_t)des_effbuftime * wfe.Format.nSamplesPerSec / 1000; int32_t des_realbuftime = des_effbuftime + 40; //printf("%u\n", wfe.Format.wFormatTag); //printf("%u\n", wfe.Format.nChannels); //printf("%u\n", wfe.Format.nSamplesPerSec); //printf("%u\n", wfe.Format.wBitsPerSample); //printf("%u\n", wfe.Format.nBlockAlign); //printf("%u\n", wfe.Format.nAvgBytesPerSec); TRYHR(w->ac->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, (REFERENCE_TIME)des_realbuftime * 10000, 0, (WAVEFORMATEX*)&wfe, NULL)); TRYHR(w->ac->GetBufferSize(&w->bfc)); TRYHR(w->ac->GetStreamLatency(&raw_ac_latency)); w->BufferBPF = wfe.Format.wBitsPerSample / 8 * wfe.Format.nChannels; buffering->buffer_size = std::min<int32_t>(des_effbufsize, w->bfc); buffering->period_size = 0; buffering->latency = buffering->buffer_size + (((int64_t)raw_ac_latency * format->rate + 5000000) / 10000000); buffering->bt_gran = 0; } if(!(w->evt = CreateEvent(NULL, FALSE, FALSE, NULL))) { printf("Error creating event.\n"); Cleanup(dev); return(NULL); } if((w->avrt_dll = LoadLibrary("avrt.dll")) != NULL) { if(!(w->p_AvSetMmThreadCharacteristicsA = (HANDLE WINAPI (*)(LPCSTR, LPDWORD))(GetProcAddress(w->avrt_dll, "AvSetMmThreadCharacteristicsA")))) { printf("Error getting pointer to AvSetMmThreadCharacteristicsA.\n"); Cleanup(dev); return(NULL); } if(!(w->p_AvRevertMmThreadCharacteristics = (BOOL WINAPI (*)(HANDLE))(GetProcAddress(w->avrt_dll, "AvRevertMmThreadCharacteristics")))) { printf("Error getting pointer to AvRevertMmThreadCharacteristics.\n"); Cleanup(dev); return(NULL); } } TRYHR(w->ac->SetEventHandle(w->evt)); TRYHR(w->ac->GetService(LV_IID_IAudioRenderClient, (void**)&w->arc)); memcpy(&dev->buffering, buffering, sizeof(SexyAL_buffering)); memcpy(&dev->format, format, sizeof(SexyAL_format)); dev->RawWrite = RawWrite; dev->RawCanWrite = RawCanWrite; dev->RawClose = Close; dev->Pause = Pause; // // Clear buffer. // { BYTE *bd; TRYHR(w->arc->GetBuffer(w->bfc, &bd)); memset(bd, 0, w->bfc * w->BufferBPF); w->arc->ReleaseBuffer(w->bfc, 0); } #if 0 { UINT32 paddie = 0; printf("buffer_size=%u\n", buffering->buffer_size); printf("bfc=%u\n", w->bfc); w->ac->GetCurrentPadding(&paddie); printf("paddie=%u\n", paddie); printf("snoo=%d\n", (int)buffering->buffer_size - paddie); } #endif TRYHR(w->ac->Start()); if(QueryPerformanceFrequency(&w->qpc_freq) == 0) { printf("QueryPerformanceFrequency() failed.\n"); Cleanup(dev); return(NULL); } //printf("qpc_freq=%f\n", (double)w->qpc_freq.QuadPart); w->AThreadRunning = true; if(!(w->AThread = CreateThread(NULL, 0, AThreadMain, dev, CREATE_SUSPENDED, NULL))) { printf("Error creating thread.\n"); Cleanup(dev); return(NULL); } InitializeCriticalSection(&w->crit); ResumeThread(w->AThread); return(dev); }
/* ======================== 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 }
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; }
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; }
// // Based on the input switches, pick the specified device to use. // bool PickDevice(IMMDevice **DeviceToUse, bool *IsDefaultDevice, ERole *DefaultDeviceRole) { HRESULT hr; bool retValue = true; IMMDeviceEnumerator *deviceEnumerator = NULL; IMMDeviceCollection *deviceCollection = NULL; *IsDefaultDevice = false; // Assume we're not using the default device. hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&deviceEnumerator)); if (FAILED(hr)) { printf("Unable to instantiate device enumerator: %x\n", hr); retValue = false; goto Exit; } IMMDevice *device = NULL; // // First off, if none of the console switches was specified, use the console device. // if (!UseConsoleDevice && !UseCommunicationsDevice && !UseMultimediaDevice && OutputEndpoint == NULL) { // // The user didn't specify an output device, prompt the user for a device and use that. // hr = deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &deviceCollection); if (FAILED(hr)) { printf("Unable to retrieve device collection: %x\n", hr); retValue = false; goto Exit; } printf("Select an output device:\n"); printf(" 0: Default Console Device\n"); printf(" 1: Default Communications Device\n"); printf(" 2: Default Multimedia Device\n"); UINT deviceCount; hr = deviceCollection->GetCount(&deviceCount); if (FAILED(hr)) { printf("Unable to get device collection length: %x\n", hr); retValue = false; goto Exit; } for (UINT i = 0 ; i < deviceCount ; i += 1) { LPWSTR deviceName; deviceName = GetDeviceName(deviceCollection, i); if (deviceName == NULL) { retValue = false; goto Exit; } printf(" %d: %S\n", i + 3, deviceName); free(deviceName); } wchar_t choice[10]; _getws_s(choice); // Note: Using the safe CRT version of _getws. long deviceIndex; wchar_t *endPointer; deviceIndex = wcstoul(choice, &endPointer, 0); if (deviceIndex == 0 && endPointer == choice) { printf("unrecognized device index: %S\n", choice); retValue = false; goto Exit; } switch (deviceIndex) { case 0: UseConsoleDevice = 1; break; case 1: UseCommunicationsDevice = 1; break; case 2: UseMultimediaDevice = 1; break; default: hr = deviceCollection->Item(deviceIndex - 3, &device); if (FAILED(hr)) { printf("Unable to retrieve device %d: %x\n", deviceIndex - 3, hr); retValue = false; goto Exit; } break; } } else if (OutputEndpoint != NULL) { hr = deviceEnumerator->GetDevice(OutputEndpoint, &device); if (FAILED(hr)) { printf("Unable to get endpoint for endpoint %S: %x\n", OutputEndpoint, hr); retValue = false; goto Exit; } } if (device == NULL) { ERole deviceRole = eConsole; // Assume we're using the console role. if (UseConsoleDevice) { deviceRole = eConsole; } else if (UseCommunicationsDevice) { deviceRole = eCommunications; } else if (UseMultimediaDevice) { deviceRole = eMultimedia; } hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, deviceRole, &device); if (FAILED(hr)) { printf("Unable to get default device for role %d: %x\n", deviceRole, hr); retValue = false; goto Exit; } *IsDefaultDevice = true; *DefaultDeviceRole = deviceRole; } *DeviceToUse = device; retValue = true; Exit: SafeRelease(&deviceCollection); SafeRelease(&deviceEnumerator); return retValue; }
//------------------------------------------------------------------------------------------------- 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(); } }
BOOL SetDefaultAudioDevice_Vista(LPCTSTR lpszHardwareId, LPCTSTR lpszName) { HRESULT hr = S_FALSE; BOOL bSuccessful = FALSE; IMMDeviceEnumerator *pDeviceEnumerator = NULL; IMMDeviceCollection* pCollection = NULL; IPolicyConfigVista *pPolicyConfigVista = NULL; do { CElcAudioDeviceEnumerator enumerator; if (!enumerator.Enumerate(FALSE)) break; CElcDeviceItem * pAudioItem = enumerator.FindItemByPnpId(lpszHardwareId, lpszName); if (!pAudioItem) break; if (FAILED(CoCreateInstance( __uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&pDeviceEnumerator))) { break; } if (FAILED(pDeviceEnumerator->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &pCollection))) { break; } LPWSTR lpszId = NULL; UINT nCount = 0; pCollection->GetCount(&nCount); for (UINT i=0; i<nCount; i++) { IMMDevice* pDevice = NULL; if (SUCCEEDED(pCollection->Item(i, &pDevice))) { pDevice->GetId(&lpszId); SAFE_RELEASE(pDevice); LPCWSTR lpszIdDup = lpszId + 17; if (pAudioItem->m_strDeviceId.CompareNoCase(lpszIdDup) == 0) break; CoTaskMemFree(lpszId); lpszId = NULL; } } if (lpszId && SUCCEEDED(CoCreateInstance( __uuidof(CPolicyConfigVistaClient), NULL, CLSCTX_ALL, __uuidof(IPolicyConfigVista), (LPVOID *)&pPolicyConfigVista))) { if (SUCCEEDED(pPolicyConfigVista->SetDefaultEndpoint(lpszId, eMultimedia)) && SUCCEEDED(pPolicyConfigVista->SetDefaultEndpoint(lpszId, eCommunications))) bSuccessful = TRUE; } if (lpszId) CoTaskMemFree(lpszId); } while (0); SAFE_RELEASE(pPolicyConfigVista); SAFE_RELEASE(pCollection); SAFE_RELEASE(pDeviceEnumerator); return bSuccessful; }
int __cdecl wmain(void) { HRESULT hr = CoInitialize(NULL); if (FAILED(hr)) { LOG(L"Failed CoInitializeEx: hr = 0x%08x", hr); return __LINE__; } CoUninitializeOnExit cuoe; // get active devices IMMDeviceEnumerator *pEnum = NULL; hr = CoCreateInstance( __uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnum ); if (FAILED(hr)) { LOG(L"Couldn't get device enumerator: hr = 0x%08x", hr); return __LINE__; } ReleaseOnExit releaseEnum(pEnum); IMMDeviceCollection *pDeviceCollection = NULL; hr = pEnum->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED, &pDeviceCollection); if (FAILED(hr)) { LOG(L"Couldn't get device collection: hr = 0x%08x", hr); return __LINE__; } ReleaseOnExit releaseDeviceCollection(pDeviceCollection); UINT nDevices = 0; hr = pDeviceCollection->GetCount(&nDevices); if (FAILED(hr)) { LOG(L"Couldn't get device collection count: hr = 0x%08x", hr); return __LINE__; } for (UINT i = 0; i < nDevices; i++) { IMMDevice *pDevice = NULL; hr = pDeviceCollection->Item(i, &pDevice); if (FAILED(hr)) { LOG(L"Couldn't get device: hr = 0x%08x", hr); return __LINE__; } ReleaseOnExit releaseDevice(pDevice); IMMEndpoint *pEndpoint = NULL; hr = pDevice->QueryInterface(IID_PPV_ARGS(&pEndpoint)); if (FAILED(hr)) { LOG(L"Couldn't get endpoint: hr = 0x%08x", hr); return __LINE__; } ReleaseOnExit releaseEndpoint(pEndpoint); EDataFlow eDirection = eAll; hr = pEndpoint->GetDataFlow(&eDirection); if (FAILED(hr)) { LOG(L"Couldn't get data flow: hr = 0x%08x", hr); return __LINE__; } LOG(L"%s endpoint", StringFromDataFlow(eDirection)); IPropertyStore *pPropertyStore = NULL; hr = pDevice->OpenPropertyStore(STGM_READ, &pPropertyStore); if (FAILED(hr)) { LOG(L"Couldn't get property store: hr = 0x%08x", hr); return __LINE__; } ReleaseOnExit releasePropertyStore(pPropertyStore); // get the long name property PROPVARIANT pv; PropVariantInit(&pv); hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv); if (FAILED(hr)) { LOG(L"Couldn't get friendly name: hr = 0x%08x", hr); return hr; } PropVariantClearOnExit clearPropVariant(&pv); LOG(L"Name: %s", pv.pwszVal); // get the ID WCHAR *wszId = NULL; hr = pDevice->GetId(&wszId); if (FAILED(hr)) { LOG(L"Couldn't get device ID: hr = 0x%08x", hr); return __LINE__; } CoTaskMemFreeOnExit releaseId(wszId); LOG(L"Endpoint ID: %s", wszId); // get device topology object for that endpoint IDeviceTopology *pDT = NULL; hr = pDevice->Activate(__uuidof(IDeviceTopology), CLSCTX_ALL, NULL, (void**)&pDT); if (FAILED(hr)) { LOG(L"Couldn't get device topology object: hr = 0x%08x", hr); return __LINE__; } ReleaseOnExit releaseDT(pDT); // get the single connector for that endpoint IConnector *pConnector = NULL; hr = pDT->GetConnector(0, &pConnector); if (FAILED(hr)) { LOG(L"Couldn't get the connector on the endpoint: hr = 0x%08x", hr); return __LINE__; } ReleaseOnExit releaseConnector(pConnector); // QI on the device's connector for IPart IPart *pPart = NULL; hr = pConnector->QueryInterface(IID_PPV_ARGS(&pPart)); if (FAILED(hr)) { LOG(L"Couldn't get the part: hr = 0x%08x", hr); return __LINE__; } ReleaseOnExit releasePart(pPart); // all the real work is done in this function // follow the connector from this trivial endpoint topology // over to the rest of the topologies hr = WalkTreeFromPart(pPart, eDirection, true, 1); if (FAILED(hr)) { LOG(L"Couldn't walk the tree: hr = 0x%08x", hr); return __LINE__; } LOG(L""); } return 0; }
bool EnumBuiltinDevices_w64(const uint32_t deviceType, STUDIO_LINK_DEVICE_LIST* devices) { PRECONDITION_RETURN(deviceType != INVALID_DEVICE_TYPE, false); PRECONDITION_RETURN(devices != 0, false); bool result = false; HRESULT hr = CoInitialize(0); if(SUCCEEDED(hr)) { IMMDeviceEnumerator* pDeviceEnumerator = 0; hr = CoCreateInstance(CLSID_MMDeviceEnumerator, 0, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); if(SUCCEEDED(hr) && (pDeviceEnumerator != 0)) { EDataFlow dataFlow = eAll; if(deviceType == HEADPHONE) { dataFlow = eRender; } else if(deviceType == MICROPHONE) { dataFlow = eCapture; } IMMDeviceCollection* pDeviceCollection = 0; hr = pDeviceEnumerator->EnumAudioEndpoints(dataFlow, DEVICE_STATE_ACTIVE, &pDeviceCollection); if(SUCCEEDED(hr) && (pDeviceCollection != 0)) { UINT deviceCount = 0; hr = pDeviceCollection->GetCount(&deviceCount); if(SUCCEEDED(hr)) { size_t foundDevices = 0; for(UINT i = 0; (i < deviceCount) && (foundDevices < deviceCount); i++) { IMMDevice* pDevice = 0; hr = pDeviceCollection->Item(i, &pDevice); if(SUCCEEDED(hr) && (pDevice != 0)) { IPropertyStore* pProperties = 0; hr = pDevice->OpenPropertyStore(STGM_READ, &pProperties); if(SUCCEEDED(hr)) { PROPVARIANT deviceFormatProperty; PropVariantInit(&deviceFormatProperty); hr = pProperties->GetValue(PKEY_AudioEngine_DeviceFormat, &deviceFormatProperty); if(SUCCEEDED(hr) && (VT_BLOB == deviceFormatProperty.vt)) { WAVEFORMATEX* deviceFormat = (WAVEFORMATEX*)deviceFormatProperty.blob.pBlobData; devices->devices[foundDevices].channelCount = deviceFormat->nChannels; devices->devices[foundDevices].sampleRate = deviceFormat->nSamplesPerSec; if((WAVE_FORMAT_EXTENSIBLE == deviceFormat->wFormatTag) && (deviceFormat->cbSize >= 22)) { //WAVEFORMATEXTENSIBLE* extensibleDeviceFormat = (WAVEFORMATEXTENSIBLE*)deviceFormat; } PropVariantClear(&deviceFormatProperty); PROPVARIANT deviceNameProperty; PropVariantInit(&deviceNameProperty); hr = pProperties->GetValue(PKEY_Device_FriendlyName, &deviceNameProperty); if(SUCCEEDED(hr)) { PWSTR deviceName = 0; hr = PropVariantToStringAlloc(deviceNameProperty, &deviceName); if(SUCCEEDED(hr)) { memset(devices->devices[foundDevices].name, 0, STUDIO_LINK_DEVICE_NAME_LENGTH); size_t numOfCharsConverted = 0; const size_t deviceNameLength = wcslen(deviceName); wcstombs_s(&numOfCharsConverted, devices->devices[foundDevices].name, STUDIO_LINK_DEVICE_NAME_LENGTH, deviceName, deviceNameLength); foundDevices++; CoTaskMemFree(deviceName); deviceName = 0; } PropVariantClear(&deviceNameProperty); } } SafeRelease(pProperties); } SafeRelease(pDevice); } } devices->deviceCount = foundDevices; } SafeRelease(pDeviceCollection); } SafeRelease(pDeviceEnumerator); } CoUninitialize(); } if(devices->deviceCount > 0) { result = true; } return result; }
bool CAESinkWASAPI::Initialize(AEAudioFormat &format, std::string &device) { if (m_initialized) return false; CLog::Log(LOGDEBUG, __FUNCTION__": Initializing WASAPI Sink Rev. 1.0.5"); m_device = device; /* Save requested format */ /* Clear returned format */ sinkReqFormat = format.m_dataFormat; sinkRetFormat = AE_FMT_INVALID; IMMDeviceEnumerator* pEnumerator = NULL; IMMDeviceCollection* pEnumDevices = NULL; HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr) //Get our device. //First try to find the named device. UINT uiCount = 0; hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.") hr = pEnumDevices->GetCount(&uiCount); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.") for (UINT i = 0; i < uiCount; i++) { IPropertyStore *pProperty = NULL; PROPVARIANT varName; hr = pEnumDevices->Item(i, &m_pDevice); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint failed.") hr = m_pDevice->OpenPropertyStore(STGM_READ, &pProperty); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.") hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName); if (FAILED(hr)) { CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed."); SAFE_RELEASE(pProperty); goto failed; } std::wstring strRawDevName(varName.pwszVal); std::string strDevName = std::string(strRawDevName.begin(), strRawDevName.end()); //g_charsetConverter.ucs2CharsetToStringCharset(strRawDevName, strDevName.c_str()); if (device == strDevName) i = uiCount; else SAFE_RELEASE(m_pDevice); PropVariantClear(&varName); SAFE_RELEASE(pProperty); } SAFE_RELEASE(pEnumDevices); if (!m_pDevice) { CLog::Log(LOGINFO, __FUNCTION__": Could not locate the device named \"%s\" in the list of WASAPI endpoint devices. Trying the default device...", device.c_str()); hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_pDevice); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not retrieve the default WASAPI audio endpoint.") IPropertyStore *pProperty = NULL; PROPVARIANT varName; hr = m_pDevice->OpenPropertyStore(STGM_READ, &pProperty); EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.") hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName); std::wstring strRawDevName(varName.pwszVal); std::string strDevName = std::string(strRawDevName.begin(), strRawDevName.end()); PropVariantClear(&varName); SAFE_RELEASE(pProperty); } //We are done with the enumerator. SAFE_RELEASE(pEnumerator); hr = m_pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&m_pAudioClient); EXIT_ON_FAILURE(hr, __FUNCTION__": Activating the WASAPI endpoint device failed.") if (!InitializeExclusive(format)) { CLog::Log(LOGINFO, __FUNCTION__": Could not Initialize Exclusive with that format"); goto failed; } /* get the buffer size and calculate the frames for AE */ m_pAudioClient->GetBufferSize(&m_uiBufferLen); format.m_frames = m_uiBufferLen; format.m_frameSamples = format.m_frames * format.m_channelLayout.Count(); m_format = format; sinkRetFormat = format.m_dataFormat; CLog::Log(LOGDEBUG, __FUNCTION__": Buffer Size = %d Bytes", m_uiBufferLen * format.m_frameSize); hr = m_pAudioClient->GetService(IID_IAudioRenderClient, (void**)&m_pRenderClient); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not initialize the WASAPI render client interface.") m_needDataEvent = CreateEvent(NULL, FALSE, FALSE, NULL); hr = m_pAudioClient->SetEventHandle(m_needDataEvent); EXIT_ON_FAILURE(hr, __FUNCTION__": Could not set the WASAPI event handler."); m_initialized = true; m_isDirty = false; return true; failed: CLog::Log(LOGERROR, __FUNCTION__": WASAPI initialization failed."); SAFE_RELEASE(pEnumDevices); SAFE_RELEASE(pEnumerator); SAFE_RELEASE(m_pRenderClient); SAFE_RELEASE(m_pAudioClient); SAFE_RELEASE(m_pDevice); CloseHandle(m_needDataEvent); return false; }
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); }
RTC::ReturnCode_t RTCKinect::onActivated(RTC::UniqueId ec_id) { /** * The configured values should be reflected to the initialization process. * * m_enable_camera -> camera image * m_enable_depth -> depth image * m_player_index -> player index detection * * important: if player indexing is enabled, depth map image is limited up to 320x240 */ DWORD dwFlag = NUI_INITIALIZE_FLAG_USES_SKELETON; if(m_enable_camera) { dwFlag |= NUI_INITIALIZE_FLAG_USES_COLOR; } if(m_enable_depth) { if(m_player_index) { dwFlag |= NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX; } else { dwFlag |= NUI_INITIALIZE_FLAG_USES_DEPTH; } } HRESULT hr = NuiInitialize(dwFlag); if( FAILED( hr ) ) { std::cout << "NUI Initialize Failed." << std::endl; return RTC::RTC_ERROR; } if(m_depth_width == 640 && m_depth_height == 480 && m_enable_depth && m_player_index) { std::cout << "If PlayerIndex and Depth Map is ON, resolution should be 320X240" << std::endl; return RTC::RTC_ERROR; } NUI_IMAGE_RESOLUTION eResolution; if(m_camera_width == 640 && m_camera_height == 480) { eResolution = NUI_IMAGE_RESOLUTION_640x480; } else { std::cout << "Invalid Image Resolution" << std::endl; return RTC::RTC_ERROR; } if(m_enable_camera) { hr = NuiImageStreamOpen(::NUI_IMAGE_TYPE_COLOR, eResolution, 0, 2, NULL, &m_pVideoStreamHandle ); if( FAILED( hr ) ) { std::cout << "NUI Image Stream Open Failed." << std::endl; return RTC::RTC_ERROR; } } if(m_depth_width == 640 && m_depth_height == 480) { eResolution = NUI_IMAGE_RESOLUTION_640x480; } else if(m_depth_width == 320 && m_depth_height == 240) { eResolution = NUI_IMAGE_RESOLUTION_320x240; } else { std::cout << "Invalid Image Resolution" << std::endl; return RTC::RTC_ERROR; } if(m_enable_depth) { if(m_player_index) { hr = NuiImageStreamOpen(::NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX, eResolution, 0, 2, NULL, &m_pDepthStreamHandle ); } else { hr = NuiImageStreamOpen(::NUI_IMAGE_TYPE_DEPTH, eResolution, 0, 2, NULL, &m_pDepthStreamHandle ); } } if( FAILED( hr ) ) { std::cout << "NUI Image Stream Open Failed." << std::endl; return RTC::RTC_ERROR; } this->m_image.width = m_camera_width; this->m_image.height = m_camera_height; this->m_image.pixels.length(m_camera_width*m_camera_height*3); this->m_depth.width = m_depth_width; this->m_depth.height = m_depth_height; this->m_depth.pixels.length(m_depth_width*m_depth_height*3); /** * Initialization for raw sound input. */ if (m_enable_microphone) { UINT deviceCount; IMMDeviceEnumerator *deviceEnumerator = NULL; IMMDeviceCollection *deviceCollection = NULL; hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&deviceEnumerator)); if (FAILED(hr)) { std::cout << "Unable to instantiate device enumerator." << std::endl; return RTC::RTC_ERROR; } hr = deviceEnumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE, &deviceCollection); if (FAILED(hr)) { std::cout << "Unable to retrieve device collection." << std::endl; return RTC::RTC_ERROR; } hr = deviceCollection->GetCount(&deviceCount); if (FAILED(hr)) { std::cout << "Unable to get device collection length." << std::endl; return RTC::RTC_ERROR; } for (UINT i = 0; i < deviceCount; i++) { IPropertyStore *propertyStore; PROPVARIANT friendlyName; IMMDevice *endpoint; PropVariantInit(&friendlyName); hr = deviceCollection->Item(i, &endpoint); if (FAILED(hr)) { std::cout << "Unable to get device collection item." << std::endl; return RTC::RTC_ERROR; } hr = endpoint->OpenPropertyStore(STGM_READ, &propertyStore); if (FAILED(hr)) { std::cout << "Unable to open device property store." << std::endl; return RTC::RTC_ERROR; } hr = propertyStore->GetValue(PKEY_Device_FriendlyName, &friendlyName); SafeRelease(&propertyStore); if (FAILED(hr)) { std::cout << "Unable to retrieve friendly name for device." << std::endl; return RTC::RTC_ERROR; } std::cout << "Scanning for Kinect Audio device..." << std::endl; if (friendlyName.vt == VT_LPWSTR) { wprintf(L" %s\n", friendlyName.pwszVal); if (wcscmp(friendlyName.pwszVal, L"Kinect USB Audio") != 0) { std::cout << " Found Kinect Audio device" << std::endl; m_pAudioEndpoint = endpoint; m_pAudioEndpoint->AddRef(); PropVariantClear(&friendlyName); SafeRelease(&endpoint); break; } } PropVariantClear(&friendlyName); SafeRelease(&endpoint); } SafeRelease(&deviceCollection); SafeRelease(&deviceEnumerator); m_AudioShutdownEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (m_AudioShutdownEvent == NULL) { std::cout << "Unable to create shutdown event." << std::endl; return RTC::RTC_ERROR; } hr = m_pAudioEndpoint->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&m_pAudioClient)); if (FAILED(hr)) { std::cout << "Unable to activate audio client." << std::endl; return RTC::RTC_ERROR; } hr = m_pAudioClient->GetMixFormat(&m_pAudioMixFormat); if (FAILED(hr)) { std::cout << "Unable to get mix format on audio client." << std::endl; return RTC::RTC_ERROR; } m_AudioFrameSize = (m_pAudioMixFormat->wBitsPerSample / 8) * m_pAudioMixFormat->nChannels; m_AudioCaptureBufferSize = m_pAudioMixFormat->nSamplesPerSec * 5 * m_AudioFrameSize; m_pAudioCaptureBuffer = new (std::nothrow) BYTE[m_AudioCaptureBufferSize]; if (m_pAudioCaptureBuffer == NULL) { std::cout << "Unable to allocate capture buffer." << std::endl; return RTC::RTC_ERROR; } m_AudioCurrentCaptureIndex = 0; std::cout << "Audio capture format (" << m_pAudioMixFormat->nChannels << " channels, " << m_pAudioMixFormat->wBitsPerSample << " bits)"<< std::endl; m_AudioLatency = 10; hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST, m_AudioLatency*10000, 0, m_pAudioMixFormat, NULL); if (FAILED(hr)) { std::cout << "Unable to initialize audio client." << std::endl; return RTC::RTC_ERROR; } hr = m_pAudioClient->GetService(IID_PPV_ARGS(&m_pAudioCaptureClient)); if (FAILED(hr)) { std::cout << "Unable to get audio capture client." << std::endl; return RTC::RTC_ERROR; } m_AudioCaptureThread = CreateThread(NULL, 0, AudioCaptureThread, this, 0, NULL); if (m_AudioCaptureThread == NULL) { std::cout << "Unable to create transport thread: " << GetLastError() << std::endl; return RTC::RTC_ERROR; } hr = m_pAudioClient->Start(); if (FAILED(hr)) { std::cout << "Unable to start audio capture client." << std::endl; return RTC::RTC_ERROR; } } return RTC::RTC_OK; }
void GetAudioDevices(AudioDeviceList &deviceList, AudioDeviceType deviceType) { const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); IMMDeviceEnumerator *mmEnumerator; HRESULT err; err = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&mmEnumerator); if(FAILED(err)) { AppWarning(TEXT("GetAudioDevices: Could not create IMMDeviceEnumerator")); return; } //------------------------------------------------------- AudioDeviceInfo *info; if(deviceType == ADT_RECORDING) { info = deviceList.devices.CreateNew(); info->strID = TEXT("Disable"); info->strName = Str("Disable"); } info = deviceList.devices.CreateNew(); info->strID = TEXT("Default"); info->strName = Str("Default"); //------------------------------------------------------- IMMDeviceCollection *collection; EDataFlow audioDeviceType; switch(deviceType) { case ADT_RECORDING: audioDeviceType = eCapture; break; case ADT_PLAYBACK: audioDeviceType = eRender; break; default: audioDeviceType = eAll; break; } err = mmEnumerator->EnumAudioEndpoints(audioDeviceType, DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED, &collection); if(FAILED(err)) { AppWarning(TEXT("GetAudioDevices: Could not enumerate audio endpoints")); SafeRelease(mmEnumerator); return; } UINT count; if(SUCCEEDED(collection->GetCount(&count))) { for(UINT i=0; i<count; i++) { IMMDevice *device; if(SUCCEEDED(collection->Item(i, &device))) { CWSTR wstrID; if(SUCCEEDED(device->GetId((LPWSTR*)&wstrID))) { IPropertyStore *store; if(SUCCEEDED(device->OpenPropertyStore(STGM_READ, &store))) { PROPVARIANT varName; PropVariantInit(&varName); if(SUCCEEDED(store->GetValue(PKEY_Device_FriendlyName, &varName))) { CWSTR wstrName = varName.pwszVal; AudioDeviceInfo *info = deviceList.devices.CreateNew(); info->strID = wstrID; info->strName = wstrName; } } CoTaskMemFree((LPVOID)wstrID); } SafeRelease(device); } } } //------------------------------------------------------- SafeRelease(collection); SafeRelease(mmEnumerator); }