LoopbackAudioSource::LoopbackAudioSource() { HRESULT hr; CComPtr<IMMDeviceEnumerator> enumerator; hr = enumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator)); assert(SUCCEEDED(hr)); CComPtr<IMMDevice> device; hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device); assert(SUCCEEDED(hr)); hr = device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr, (void **)&event_client_); assert(SUCCEEDED(hr)); hr = event_client_->GetMixFormat(&format_); assert(SUCCEEDED(hr)); hr = event_client_->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 0, 0, format_, nullptr); assert(SUCCEEDED(hr)); event_handle_ = CreateEventW(nullptr, FALSE, FALSE, nullptr); assert(event_handle_); hr = event_client_->SetEventHandle(event_handle_); assert(SUCCEEDED(hr)); hr = device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr, (void **)&loopback_client_); assert(SUCCEEDED(hr)); hr = loopback_client_->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, 0, 0, format_, nullptr); assert(SUCCEEDED(hr)); hr = loopback_client_->GetService(__uuidof(IAudioCaptureClient), (void **)&capture_client_); assert(SUCCEEDED(hr)); hr = event_client_->Start(); assert(SUCCEEDED(hr)); hr = loopback_client_->Start(); assert(SUCCEEDED(hr)); }
/////////////////////////////////////////////////////////////////////////// // // Function: // DeviceBindTo // // Description: // Bind device to an IAudioClient interface. // // Parameters: // eDataFlow: eRender for render device, eCapture for capture device // iDevIdx: Index of device in the enumeration list. If it is -1, use default device // ppVoid: pointer pointer to IAudioClient interface. // ppszEndpointDeviceId: Device ID. Caller is responsible for freeing memeory // using CoTaskMemoryFree. If can be NULL if called doesn't need this info. // // Return: // S_OK if successful // /////////////////////////////////////////////////////////////////////////////// HRESULT DeviceBindTo( EDataFlow eDataFlow, // eCapture/eRender INT iDevIdx, // Device Index. -1 - default device. IAudioClient **ppAudioClient, // pointer pointer to IAudioClient interface IAudioEndpointVolume **ppEndpointVolume, WCHAR** ppszEndpointDeviceId) // Device ID. Need to be freed in caller with CoTaskMemoryFree if it is not NULL { HRESULT hResult; CComPtr<IMMDeviceEnumerator> spEnumerator; CComPtr<IMMDeviceCollection> spEndpoints; CComPtr<IMMDevice> spDevice; WCHAR *pszDeviceId = NULL; if (ppAudioClient == NULL) return E_POINTER; *ppAudioClient = NULL; hResult = spEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator)); IF_FAILED_JUMP(hResult, Exit); // use default device if (iDevIdx < 0 ) { hResult = spEnumerator->GetDefaultAudioEndpoint(eDataFlow, eConsole, &spDevice); IF_FAILED_JUMP(hResult, Exit); }else{ // User selected device hResult = spEnumerator->EnumAudioEndpoints(eDataFlow, DEVICE_STATE_ACTIVE, &spEndpoints); IF_FAILED_JUMP(hResult, Exit); hResult = spEndpoints->Item(iDevIdx, &spDevice); IF_FAILED_JUMP(hResult, Exit); } // get device ID and format hResult = spDevice->GetId(&pszDeviceId); IF_FAILED_JUMP(hResult, Exit); // Active device hResult = spDevice->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)ppAudioClient); IF_FAILED_JUMP(hResult, Exit); if (ppEndpointVolume) { hResult = spDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (void **)ppEndpointVolume); IF_FAILED_JUMP(hResult, Exit); } Exit: if (ppszEndpointDeviceId) *ppszEndpointDeviceId = pszDeviceId; else if (pszDeviceId) CoTaskMemFree(pszDeviceId); return hResult; }
HRESULT AudioSessionService::RefreshAudioSessions() { CleanUpAudioSessions(); CComPtr<IMMDeviceEnumerator> deviceEnumerator; FAST_FAIL(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&deviceEnumerator))); // TIP: Role parameter is not actually used https://msdn.microsoft.com/en-us/library/windows/desktop/dd371401.aspx CComPtr<IMMDevice> device; FAST_FAIL(deviceEnumerator->GetDefaultAudioEndpoint(EDataFlow::eRender, ERole::eMultimedia, &device)); CComPtr<IAudioSessionManager2> audioSessionManager; FAST_FAIL(device->Activate(__uuidof(IAudioSessionManager2), CLSCTX_INPROC, nullptr, (void**)&audioSessionManager)); CComPtr<IAudioSessionEnumerator> audioSessionEnumerator; FAST_FAIL(audioSessionManager->GetSessionEnumerator(&audioSessionEnumerator)); int sessionCount; FAST_FAIL(audioSessionEnumerator->GetCount(&sessionCount)); for (int i = 0; i < sessionCount; i++) { EarTrumpetAudioSession audioSession; if (SUCCEEDED(CreateEtAudioSessionFromAudioSession(audioSessionEnumerator, i, &audioSession))) { _sessions.push_back(audioSession); } } return S_OK; }
/** Static function to create a template select dialog. **/ void CTemplateSelectDialog::DoDialog() { #ifdef WWHIZ_VSNET CComPtr<EnvDTE::Document> document; g_pDTE->get_ActiveDocument(&document); #endif WWHIZ_VSNET while (g_wwhizTemplateManager->GetCount() == 0) { CTemplateFileListDialog dlg; if (dlg.DoModal() == IDCANCEL) return; } CTemplateSelectDialog dlg; if (dlg.DoModal() == IDCANCEL) return; if (dlg.m_code) { #ifdef WWHIZ_VSNET if (document) document->Activate(); #endif WWHIZ_VSNET WWhizCommands::PutTemplate(*dlg.m_code); } }
HRESULT AudioDeviceService::GetAudioDeviceVolume(LPWSTR deviceId, float* volume) { CComPtr<IMMDevice> device; FAST_FAIL(this->GetDeviceByDeviceId(deviceId, &device)); CComPtr<IAudioEndpointVolume> audioEndpointVol; FAST_FAIL(device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC, nullptr, reinterpret_cast<void**>(&audioEndpointVol))); return audioEndpointVol->GetMasterVolumeLevelScalar(volume); }
HRESULT AudioDeviceService::SetMuteBoolForDevice(LPWSTR deviceId, BOOL value) { CComPtr<IMMDevice> device; FAST_FAIL(this->GetDeviceByDeviceId(deviceId, &device)); CComPtr<IAudioEndpointVolume> audioEndpointVol; FAST_FAIL(device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC, nullptr, reinterpret_cast<void**>(&audioEndpointVol))); return audioEndpointVol->SetMute(value, nullptr); }
bool initAudio(){ if (!IsWindowsVistaOrGreater()) return false; CComPtr<IMMDevice> pDevice; // get Mgr & EndpointVolume CComPtr<IMMDeviceEnumerator> pDeviceEnumerator; // select output device CComPtr<IAudioSessionManager2> pAudioSessionManager2; // get enumerator // Init CoInitializeEx(NULL, COINIT_MULTITHREADED); // Device Enumerator pDeviceEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator)); // get Default Audio Endpoint Device pDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice); // get AudioSessionMgr2 and AudioEndpointVolume pDevice->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL, NULL, (VOID**)&pAudioSessionManager2); pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (VOID**)&pEpVol); // get Audio Session Enumerator pAudioSessionManager2->GetSessionEnumerator(&pAudioSessionEnumerator); return true; }
/* Retrieves the default audio device from the Core Audio API To be used for WASAPI mode To be improved : choose a device (ask albain on doom9/ffdshow-tryout for sample code) */ HRESULT CMpcAudioRenderer::GetDefaultAudioDevice(IAudioClient **ppAudioClient) { HRESULT hr; CComPtr<IMMDeviceEnumerator> enumerator; CComPtr<IMMDevice> device; hr = enumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator)); hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device); hr = device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, reinterpret_cast<void**>(ppAudioClient)); return hr; }
bool FVSAccessorModule::OpenVisualStudioFileAtLineInternal(const FString& FullPath, int32 LineNumber, int32 ColumnNumber) { // Check that the file actually exists first if (!FPaths::FileExists(FullPath)) { OpenFileFailed.Broadcast(FullPath); return false; } // Initialize the com library, if not already by this thread if (!FWindowsPlatformMisc::CoInitialize()) { UE_LOG(LogVSAccessor, Error, TEXT( "ERROR - Could not initialize COM library!" )); return false; } bool bDefer = false, bSuccess = false; CComPtr<EnvDTE::_DTE> DTE; if (AccessVisualStudio(DTE, SolutionPath, Locations)) { // Set Focus on Visual Studio CComPtr<EnvDTE::Window> MainWindow; if (SUCCEEDED(DTE->get_MainWindow(&MainWindow)) && SUCCEEDED(MainWindow->Activate())) { // Get ItemOperations CComPtr<EnvDTE::ItemOperations> ItemOperations; if (SUCCEEDED(DTE->get_ItemOperations(&ItemOperations))) { // Open File auto ANSIPath = StringCast<ANSICHAR>(*FullPath); CComBSTR COMStrFileName(ANSIPath.Get()); CComBSTR COMStrKind(EnvDTE::vsViewKindTextView); CComPtr<EnvDTE::Window> Window; if (SUCCEEDED(ItemOperations->OpenFile(COMStrFileName, COMStrKind, &Window))) { // Scroll to Line Number CComPtr<EnvDTE::Document> Document; CComPtr<IDispatch> SelectionDispatch; CComPtr<EnvDTE::TextSelection> Selection; if (SUCCEEDED(DTE->get_ActiveDocument(&Document)) && SUCCEEDED(Document->get_Selection(&SelectionDispatch)) && SUCCEEDED(SelectionDispatch->QueryInterface(&Selection)) && SUCCEEDED(Selection->GotoLine(LineNumber, true))) { if (ColumnNumber > 0 && SUCCEEDED(Selection->MoveToLineAndOffset(LineNumber, ColumnNumber, false))) { bSuccess = true; } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't goto column number '%i' of line '%i' in '%s'"), ColumnNumber, LineNumber, *FullPath); } } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't goto line number '%i' in '%s'"), LineNumber, *FullPath); } } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't open file '%s'."), *FullPath); } VSLaunchFinished( true ); } else { UE_LOG(LogVSAccessor, Log, TEXT("Couldn't get item operations. Visual Studio may still be initializing."), *FullPath); bDefer = true; } } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't set focus on Visual Studio.")); } } else { bDefer = true; // We can't process until we're in the main thread, if we aren't initially defer until we are if ( IsInGameThread() ) { // If we haven't already attempted to launch VS do so now if (!IsVSLaunchInProgress()) { // If there's no valid instance of VS running, run one if we have it installed if ( !RunVisualStudioAndOpenSolution() ) { bDefer = false; } else { VSLaunchStarted(); } } } } // If we have attempted to launch VS, and it's taken too long, timeout so the user can try again if ( IsVSLaunchInProgress() && ( FPlatformTime::Seconds() - VSLaunchTime ) > 300 ) { // We need todo this incase the process died or was kill prior to the code gaining focus of it bDefer = false; VSLaunchFinished( false ); // We failed to open the solution and file, so lets just use the platforms default opener. FPlatformProcess::LaunchFileInDefaultExternalApplication( *FullPath ); } // Defer the request until VS is available to take hold of if ( bDefer ) { const FString DeferCommand = FString::Printf( TEXT( "OPEN_VS %s %d %d" ), *FullPath, LineNumber, ColumnNumber); LaunchVSDeferred.Broadcast( DeferCommand ); } else { UE_LOG(LogVSAccessor, Warning, TEXT("Couldn't access Visual Studio")); } // Uninitialize the com library, if we initialized it above (don't call if S_FALSE) FWindowsPlatformMisc::CoUninitialize(); return bSuccess; }
// ---------------------------------------------------------------------------- // Function: // CSwapPropPage::OnApply // // Description: // Handle the pressing of the apply button // // Parameters: // hwndDlg - [in] Handle to the dialog box // // Return values: // TRUE to set keyboard focus on control // ---------------------------------------------------------------------------- BOOL CSwapPropPage::OnApply ( HWND hwndDlg ) { HRESULT hr = S_OK; // Commit the settings hr = SetSysFXState(); IF_FAILED_JUMP(hr, Exit); hr = SetSwapSFXState(); IF_FAILED_JUMP(hr, Exit); hr = SetSwapMFXState(); IF_FAILED_JUMP(hr, Exit); hr = SetDelaySFXState(); IF_FAILED_JUMP(hr, Exit); hr = SetDelayMFXState(); IF_FAILED_JUMP(hr, Exit); if (NULL != m_pAudioFXExtParams && NULL != m_pAudioFXExtParams->pFxProperties) { hr = m_pAudioFXExtParams->pFxProperties->Commit(); IF_FAILED_JUMP(hr, Exit); if (m_fReset) { // something changed that forces us to reset the format support CComPtr<IMMDeviceEnumerator> spEnumerator; CComPtr<IMMDevice> spMMDevice; // Create device enumerator and get IMMDevice from the device ID hr = spEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator)); IF_FAILED_JUMP(hr, Exit); hr = spEnumerator->GetDevice(m_pAudioFXExtParams->pwstrEndpointID, &spMMDevice); IF_FAILED_JUMP(hr, Exit); CComPtr<IAudioEndpointFormatControl> spEndpointFormat; hr = spMMDevice->Activate(__uuidof(IAudioEndpointFormatControl), CLSCTX_ALL, NULL, (void **)&spEndpointFormat); IF_FAILED_JUMP(hr, Exit); spEndpointFormat->ResetToDefault(ENDPOINT_FORMAT_RESET_MIX_ONLY); m_fReset = FALSE; } } Exit: if (SUCCEEDED(hr)) { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); } else { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); } return(TRUE); }
/////////////////////////////////////////////////////////////////////////////// // Function: // GetMicArrayGeometry() // // Description: // Obtains the geometry for the specified mic array. // // Parameters: szDeviceId -- The requested device ID, which can be obtained // from calling EnumAudioCaptureDevices() // // ppGeometry -- Address of the pointer to the mic-array gemometry. // Caller is ressponsible for calling CoTaskMemFree() // if the call is successfull. // // cbSize -- size of the geometry structure // // Returns: S_OK on success /////////////////////////////////////////////////////////////////////////////// HRESULT GetMicArrayGeometry(wchar_t szDeviceId[], KSAUDIO_MIC_ARRAY_GEOMETRY** ppGeometry, ULONG& cbSize) { HRESULT hr = S_OK; if (szDeviceId == NULL) return E_INVALIDARG; if (ppGeometry == NULL) return E_POINTER; cbSize = 0; CComPtr<IMMDeviceEnumerator> spEnumerator; CComPtr<IMMDevice> spDevice; CComQIPtr<IPart> spPart; bool bIsMicArray; hr = spEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator)); IF_FAILED_RETURN(hr); hr = spEnumerator->GetDevice(szDeviceId, &spDevice); IF_FAILED_RETURN(hr); hr = EndpointIsMicArray(spDevice, bIsMicArray); IF_FAILED_RETURN(hr); if (!bIsMicArray) return E_FAIL; UINT nPartId = 0; hr = GetInputJack(spDevice, spPart); IF_FAILED_RETURN(hr); hr = spPart->GetLocalId(&nPartId); IF_FAILED_RETURN(hr); CComPtr<IDeviceTopology> spTopology; CComPtr<IMMDeviceEnumerator> spEnum; CComPtr<IMMDevice> spJackDevice; CComPtr<IKsControl> spKsControl; wchar_t * pwstrDevice = 0; // Get the topology object for the part hr = spPart->GetTopologyObject(&spTopology); IF_FAILED_RETURN(hr); // Get the id of the IMMDevice that this topology object describes. hr = spTopology->GetDeviceId(&pwstrDevice); IF_FAILED_RETURN(hr); // Get an IMMDevice pointer using the ID hr = spEnum.CoCreateInstance(__uuidof(MMDeviceEnumerator)); IF_FAILED_JUMP(hr, Exit); hr = spEnum->GetDevice(pwstrDevice, &spJackDevice); IF_FAILED_JUMP(hr, Exit); // Activate IKsControl on the IMMDevice hr = spJackDevice->Activate(__uuidof(IKsControl), CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void**>(&spKsControl)); IF_FAILED_JUMP(hr, Exit); // At this point we can use IKsControl just as we would use DeviceIoControl KSP_PIN ksp; ULONG cbData = 0; ULONG cbGeometry = 0; // Inititialize the pin property ::ZeroMemory(&ksp, sizeof(ksp)); ksp.Property.Set = KSPROPSETID_Audio; ksp.Property.Id = KSPROPERTY_AUDIO_MIC_ARRAY_GEOMETRY; ksp.Property.Flags = KSPROPERTY_TYPE_GET; ksp.PinId = nPartId & PARTID_MASK; // Get data size by passing NULL hr = spKsControl->KsProperty(reinterpret_cast<PKSPROPERTY>(&ksp), sizeof(ksp), NULL, 0, &cbGeometry); IF_FAILED_JUMP(hr, Exit); // Allocate memory for the microphone array geometry *ppGeometry = reinterpret_cast<KSAUDIO_MIC_ARRAY_GEOMETRY*> (::CoTaskMemAlloc(cbGeometry)); if(*ppGeometry == 0) { hr = E_OUTOFMEMORY; } IF_FAILED_JUMP(hr, Exit); // Now retriev the mic-array structure... DWORD cbOut = 0; hr = spKsControl->KsProperty(reinterpret_cast<PKSPROPERTY>(&ksp), sizeof(ksp), *ppGeometry, cbGeometry, &cbOut); IF_FAILED_JUMP(hr, Exit); cbSize = cbGeometry; Exit: if(pwstrDevice != 0) { ::CoTaskMemFree(pwstrDevice); } return hr; }//GetMicArrayGeometry()
HRESULT ClientReader::Initialize(bool IsLoopback, FLOAT SampleRate, HANDLE WaitEvent, CComPtr<IMMDevice> InputDevice, CComPtr<IDXAudioCallback> Callback) { HRESULT hr = S_OK; BYTE* Buffer = nullptr; int error = 0; m_Callback = Callback; //Create the SRC_STATE object m_ResampleState = src_new ( SRC_SINC_FASTEST, //More than adequate for a real time stream 2, //Two channels (stereo) &error ); if (error != 0) { m_Callback->OnObjectFailure ( FILENAME, __LINE__, E_FAIL ); return E_FAIL; } //"Activate" the device (create the IAudioClient interface) hr = InputDevice->Activate ( __uuidof(IAudioClient), CLSCTX_ALL, nullptr, (void**)(&m_Client) ); RETURN_HR(__LINE__); //Retrieves the device period - this is how often new information is provided //to the stream, in 100-nanosecond units. hr = m_Client->GetDevicePeriod ( &m_Period, nullptr ); RETURN_HR(__LINE__); //Retrieves the mix format - this is the format in which the audio endpoint gives //us the data. This data will need to be resampled, so we need to know what form //it's in. hr = m_Client->GetMixFormat ( (WAVEFORMATEX**)(&m_WaveFormat) ); RETURN_HR(__LINE__); //Initialize the client, marking how we're going to be using it hr = m_Client->Initialize ( AUDCLNT_SHAREMODE_SHARED, //Always use shared - exclusive is meant for drivers and is unpredictable otherwise WaitEvent ? AUDCLNT_STREAMFLAGS_EVENTCALLBACK : NULL | //Use an event callback if specified IsLoopback ? AUDCLNT_STREAMFLAGS_LOOPBACK : NULL, //Make this a loopback stream if specified m_Period, //Creates a buffer large enough to store one packet m_Period, //Use the endpoint's periodicity (this can't ve any other value) (WAVEFORMATEX*)(m_WaveFormat), //Pass in the wave format we just retrieved NULL //No audio session stuff ); RETURN_HR(__LINE__); //Create the IAudioCaptureClient interface hr = m_Client->GetService ( IID_PPV_ARGS(&m_CaptureClient) ); RETURN_HR(__LINE__); //If using an event callback mechanism, provide the event handle (this is from CDXAudioStream) if (WaitEvent != NULL) { hr = m_Client->SetEventHandle ( WaitEvent ); RETURN_HR(__LINE__); } //Calculate the number of frames the endpoint is going to give us each period. m_PeriodFrames = (UINT32)(ceil(DOUBLE(m_Period * m_WaveFormat->Format.nSamplesPerSec) / 10000000)); //Calculate the resample ratio - this is the ratio of the output sample rate to the input sample rate, IE //the sample rate specified by the application developer divided by the sample rate used by the endpoint. //This value is used by libsamplerate. m_ResampleRatio = DOUBLE(SampleRate) / DOUBLE(m_WaveFormat->Format.nSamplesPerSec); //Output sample rate / input sample rate return S_OK; }
HRESULT AudioDeviceService::RefreshAudioDevices() { CleanUpAudioDevices(); CComPtr<IMMDeviceEnumerator> deviceEnumerator; FAST_FAIL(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&deviceEnumerator))); CComPtr<IMMDeviceCollection> deviceCollection; FAST_FAIL(deviceEnumerator->EnumAudioEndpoints(EDataFlow::eRender, ERole::eMultimedia, &deviceCollection)); CComPtr<IMMDevice> defaultDevice; FAST_FAIL(deviceEnumerator->GetDefaultAudioEndpoint(EDataFlow::eRender, ERole::eMultimedia, &defaultDevice)); CComHeapPtr<wchar_t> defaultDeviceId; FAST_FAIL(defaultDevice->GetId(&defaultDeviceId)); UINT numDevices; FAST_FAIL(deviceCollection->GetCount(&numDevices)); for (UINT i = 0; i < numDevices; i++) { CComPtr<IMMDevice> device; if (FAILED(deviceCollection->Item(i, &device))) { continue; } CComHeapPtr<wchar_t> deviceId; FAST_FAIL(device->GetId(&deviceId)); CComPtr<IPropertyStore> propertyStore; FAST_FAIL(device->OpenPropertyStore(STGM_READ, &propertyStore)); PROPVARIANT friendlyName; PropVariantInit(&friendlyName); FAST_FAIL(propertyStore->GetValue(PKEY_Device_FriendlyName, &friendlyName)); CComPtr<IAudioEndpointVolume> audioEndpointVol; FAST_FAIL(device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC, nullptr, reinterpret_cast<void**>(&audioEndpointVol))); BOOL isMuted; FAST_FAIL(audioEndpointVol->GetMute(&isMuted)); EarTrumpetAudioDevice audioDevice = {}; FAST_FAIL(SHStrDup(friendlyName.pwszVal, &audioDevice.DisplayName)); FAST_FAIL(SHStrDup(deviceId, &audioDevice.Id)); audioDevice.IsDefault = (wcscmp(defaultDeviceId, deviceId) == 0); audioDevice.IsMuted = !!isMuted; _devices.push_back(audioDevice); PropVariantClear(&friendlyName); } return S_OK; }