void CAESinkPi::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { m_info.m_channels.Reset(); m_info.m_dataFormats.clear(); m_info.m_sampleRates.clear(); m_info.m_deviceType = AE_DEVTYPE_HDMI; m_info.m_deviceName = "HDMI"; m_info.m_displayName = "HDMI"; m_info.m_displayNameExtra = ""; m_info.m_channels += AE_CH_FL; m_info.m_channels += AE_CH_FR; m_info.m_sampleRates.push_back(48000); m_info.m_dataFormats.push_back(AE_FMT_S16LE); list.push_back(m_info); m_info.m_channels.Reset(); m_info.m_dataFormats.clear(); m_info.m_sampleRates.clear(); m_info.m_deviceType = AE_DEVTYPE_PCM; m_info.m_deviceName = "Analogue"; m_info.m_displayName = "Analogue"; m_info.m_displayNameExtra = ""; m_info.m_channels += AE_CH_FL; m_info.m_channels += AE_CH_FR; m_info.m_sampleRates.push_back(48000); m_info.m_dataFormats.push_back(AE_FMT_S16LE); list.push_back(m_info); }
void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { m_info.m_channels.Reset(); m_info.m_dataFormats.clear(); m_info.m_sampleRates.clear(); // AML devices can do passthough // RK3188 can do passthrough too m_info.m_deviceType = AE_DEVTYPE_HDMI; m_info.m_deviceName = "AudioTrack"; m_info.m_displayName = "android"; m_info.m_displayNameExtra = "audiotrack"; m_info.m_channels += AE_CH_FL; m_info.m_channels += AE_CH_FR; m_info.m_sampleRates.push_back(CJNIAudioTrack::getNativeOutputSampleRate(CJNIAudioManager::STREAM_MUSIC)); m_info.m_dataFormats.push_back(AE_FMT_S16LE); m_info.m_dataFormats.push_back(AE_FMT_AC3); m_info.m_dataFormats.push_back(AE_FMT_DTS); #if 0 //defined(__ARM_NEON__) if (g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_NEON) m_info.m_dataFormats.push_back(AE_FMT_FLOAT); #endif list.push_back(m_info); }
void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { m_info.m_channels.Reset(); m_info.m_dataFormats.clear(); m_info.m_sampleRates.clear(); m_info.m_deviceType = AE_DEVTYPE_PCM; #if defined(HAS_LIBAMCODEC) // AML devices can do passthough if (aml_present()) { m_info.m_deviceType = AE_DEVTYPE_HDMI; m_info.m_dataFormats.push_back(AE_FMT_AC3); m_info.m_dataFormats.push_back(AE_FMT_DTS); } #endif m_info.m_deviceName = "AudioTrack"; m_info.m_displayName = "android"; m_info.m_displayNameExtra = "audiotrack"; m_info.m_channels += AE_CH_FL; m_info.m_channels += AE_CH_FR; m_info.m_sampleRates.push_back(44100); m_info.m_sampleRates.push_back(48000); m_info.m_dataFormats.push_back(AE_FMT_S16LE); #if 0 //defined(__ARM_NEON__) if (g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_NEON) m_info.m_dataFormats.push_back(AE_FMT_FLOAT); #endif list.push_back(m_info); }
void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { m_info.m_channels.Reset(); m_info.m_dataFormats.clear(); m_info.m_sampleRates.clear(); m_info.m_deviceType = AE_DEVTYPE_PCM; m_info.m_deviceName = "AudioTrack"; m_info.m_displayName = "android"; m_info.m_displayNameExtra = "audiotrack"; #ifdef LIMIT_TO_STEREO_AND_5POINT1_AND_7POINT1 if (Has71Support()) m_info.m_channels = AE_CH_LAYOUT_7_1; else m_info.m_channels = AE_CH_LAYOUT_5_1; #else m_info.m_channels = KnownChannels; #endif m_info.m_dataFormats.push_back(AE_FMT_S16LE); m_info.m_sampleRates.push_back(CJNIAudioTrack::getNativeOutputSampleRate(CJNIAudioManager::STREAM_MUSIC)); if (!CXBMCApp::IsHeadsetPlugged()) { m_info.m_deviceType = AE_DEVTYPE_HDMI; int test_sample[] = { 44100, 48000, 96000, 192000 }; int test_sample_sz = sizeof(test_sample) / sizeof(int); for (int i=0; i<test_sample_sz; ++i) { if (IsSupported(test_sample[i], CJNIAudioFormat::CHANNEL_OUT_STEREO, CJNIAudioFormat::ENCODING_PCM_16BIT)) { m_info.m_sampleRates.push_back(test_sample[i]); CLog::Log(LOGDEBUG, "AESinkAUDIOTRACK - %d supported", test_sample[i]); } } m_info.m_dataFormats.push_back(AE_FMT_AC3); m_info.m_dataFormats.push_back(AE_FMT_DTS); } #if 0 //defined(__ARM_NEON__) if (g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_NEON) m_info.m_dataFormats.push_back(AE_FMT_FLOAT); #endif list.push_back(m_info); }
void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { // Clear everything m_info.m_channels.Reset(); m_info.m_dataFormats.clear(); m_info.m_sampleRates.clear(); m_info.m_streamTypes.clear(); m_sink_sampleRates.clear(); m_info.m_deviceType = AE_DEVTYPE_PCM; m_info.m_deviceName = "AudioTrack"; m_info.m_displayName = "android"; m_info.m_displayNameExtra = "audiotrack"; UpdateAvailablePCMCapabilities(); if (!CXBMCApp::IsHeadsetPlugged()) { UpdateAvailablePassthroughCapabilities(); } list.push_back(m_info); }
void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { m_info.m_channels.Reset(); m_info.m_dataFormats.clear(); m_info.m_sampleRates.clear(); m_info.m_deviceType = AE_DEVTYPE_HDMI; m_info.m_deviceName = "AudioTrack"; m_info.m_displayName = "android"; m_info.m_displayNameExtra = "audiotrack"; #ifdef LIMIT_TO_STEREO_AND_5POINT1 m_info.m_channels = AE_CH_LAYOUT_5_1; #else m_info.m_channels = KnownChannels; #endif // MSTAR PATCH BEGIN //m_info.m_sampleRates.push_back(CJNIAudioTrack::getNativeOutputSampleRate(CJNIAudioManager::STREAM_MUSIC)); m_info.m_sampleRates.push_back(44100); m_info.m_sampleRates.push_back(48000); // MSTAR PATCH END m_info.m_dataFormats.push_back(AE_FMT_S16LE); m_info.m_dataFormats.push_back(AE_FMT_AC3); m_info.m_dataFormats.push_back(AE_FMT_DTS); // MSTAR PATCH BEGIN m_info.m_dataFormats.push_back(AE_FMT_EAC3); m_info.m_dataFormats.push_back(AE_FMT_TRUEHD); m_info.m_dataFormats.push_back(AE_FMT_DTSHD); m_info.m_sampleRates.push_back(192000); // MSTAR PATCH END #if 0 //defined(__ARM_NEON__) if (g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_NEON) m_info.m_dataFormats.push_back(AE_FMT_FLOAT); #endif list.push_back(m_info); }
void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { m_info.m_channels.Reset(); m_info.m_dataFormats.clear(); m_info.m_sampleRates.clear(); m_info.m_deviceType = AE_DEVTYPE_PCM; m_info.m_deviceName = "AudioTrack"; m_info.m_displayName = "android"; m_info.m_displayNameExtra = "audiotrack"; #ifdef LIMIT_TO_STEREO_AND_5POINT1_AND_7POINT1 if (Has71Support()) m_info.m_channels = AE_CH_LAYOUT_7_1; else m_info.m_channels = AE_CH_LAYOUT_5_1; #else m_info.m_channels = KnownChannels; #endif m_info.m_dataFormats.push_back(AE_FMT_S16LE); m_sink_sampleRates.clear(); m_sink_sampleRates.insert(CJNIAudioTrack::getNativeOutputSampleRate(CJNIAudioManager::STREAM_MUSIC)); m_info.m_wantsIECPassthrough = true; if (!CXBMCApp::IsHeadsetPlugged()) { m_info.m_deviceType = AE_DEVTYPE_HDMI; m_info.m_dataFormats.push_back(AE_FMT_RAW); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_AC3); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_CORE); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_1024); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_2048); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_512); #if defined(HAS_LIBAMCODEC) if (aml_present()) { // passthrough m_info.m_wantsIECPassthrough = true; m_sink_sampleRates.insert(44100); m_sink_sampleRates.insert(48000); if (HasAmlHD()) { m_sink_sampleRates.insert(96000); m_sink_sampleRates.insert(192000); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_EAC3); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_TRUEHD); } } else #endif { int test_sample[] = { 32000, 44100, 48000, 96000, 192000 }; int test_sample_sz = sizeof(test_sample) / sizeof(int); int encoding = CJNIAudioFormat::ENCODING_PCM_16BIT; if (CJNIAudioManager::GetSDKVersion() >= 21) encoding = CJNIAudioFormat::ENCODING_PCM_FLOAT; for (int i=0; i<test_sample_sz; ++i) { if (IsSupported(test_sample[i], CJNIAudioFormat::CHANNEL_OUT_STEREO, encoding)) { m_sink_sampleRates.insert(test_sample[i]); CLog::Log(LOGDEBUG, "AESinkAUDIOTRACK - %d supported", test_sample[i]); } } if (CJNIAudioManager::GetSDKVersion() >= 23) { m_info.m_wantsIECPassthrough = false; // here only 5.1 would work but we cannot correctly distinguish // m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_EAC3); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD); } if (StringUtils::StartsWithNoCase(CJNIBuild::DEVICE, "foster")) // SATV is ahead of API { m_info.m_wantsIECPassthrough = false; if (CJNIAudioManager::GetSDKVersion() == 22) m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_TRUEHD); } } std::copy(m_sink_sampleRates.begin(), m_sink_sampleRates.end(), std::back_inserter(m_info.m_sampleRates)); } list.push_back(m_info); }
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); }
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); }
void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { m_info.m_channels.Reset(); m_info.m_dataFormats.clear(); m_info.m_sampleRates.clear(); m_info.m_deviceType = AE_DEVTYPE_PCM; m_info.m_deviceName = "AudioTrack"; m_info.m_displayName = "android"; m_info.m_displayNameExtra = "audiotrack"; #ifdef LIMIT_TO_STEREO_AND_5POINT1_AND_7POINT1 if (Has71Support()) m_info.m_channels = AE_CH_LAYOUT_7_1; else m_info.m_channels = AE_CH_LAYOUT_5_1; #else m_info.m_channels = KnownChannels; #endif m_info.m_dataFormats.push_back(AE_FMT_S16LE); m_sink_sampleRates.clear(); m_sink_sampleRates.insert(CJNIAudioTrack::getNativeOutputSampleRate(CJNIAudioManager::STREAM_MUSIC)); m_info.m_wantsIECPassthrough = true; if (!CXBMCApp::IsHeadsetPlugged()) { m_info.m_deviceType = AE_DEVTYPE_HDMI; m_info.m_wantsIECPassthrough = false; m_info.m_dataFormats.push_back(AE_FMT_RAW); if (CJNIAudioFormat::ENCODING_AC3 != -1) { m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_AC3); CLog::Log(LOGDEBUG, "Firmware implements AC3 RAW"); } // EAC3 working on shield, broken on FireTV if (CJNIAudioFormat::ENCODING_E_AC3 != -1) { m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_EAC3); CLog::Log(LOGDEBUG, "Firmware implements EAC3 RAW"); } if (CJNIAudioFormat::ENCODING_DTS != -1) { CLog::Log(LOGDEBUG, "Firmware implements DTS RAW"); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_CORE); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_1024); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_2048); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_512); } if (aml_present() && CJNIAudioManager::GetSDKVersion() < 23) { // passthrough m_info.m_wantsIECPassthrough = true; m_sink_sampleRates.insert(44100); m_sink_sampleRates.insert(48000); if (HasAmlHD()) { m_sink_sampleRates.insert(96000); m_sink_sampleRates.insert(192000); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_EAC3); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_TRUEHD); } } else { bool supports_192khz = false; int test_sample[] = { 32000, 44100, 48000, 88200, 96000, 176400, 192000 }; int test_sample_sz = sizeof(test_sample) / sizeof(int); int encoding = CJNIAudioFormat::ENCODING_PCM_16BIT; if (CJNIAudioManager::GetSDKVersion() >= 21) encoding = CJNIAudioFormat::ENCODING_PCM_FLOAT; for (int i=0; i<test_sample_sz; ++i) { if (IsSupported(test_sample[i], CJNIAudioFormat::CHANNEL_OUT_STEREO, encoding)) { m_sink_sampleRates.insert(test_sample[i]); if (test_sample[i] == 192000) supports_192khz = true; CLog::Log(LOGDEBUG, "AESinkAUDIOTRACK - %d supported", test_sample[i]); } } if (CJNIAudioManager::GetSDKVersion() >= 23) { if (CJNIAudioFormat::ENCODING_DTS_HD != -1) { CLog::Log(LOGDEBUG, "Firmware implements DTS-HD RAW"); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD); } if (CJNIAudioFormat::ENCODING_DOLBY_TRUEHD != -1) { CLog::Log(LOGDEBUG, "Firmware implements TrueHD RAW"); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_TRUEHD); } } // Android v24 and backports can do real IEC API if (CJNIAudioFormat::ENCODING_IEC61937 != -1) { m_info.m_wantsIECPassthrough = true; m_info.m_streamTypes.clear(); m_info.m_dataFormats.push_back(AE_FMT_RAW); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_AC3); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_CORE); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_1024); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_2048); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_512); CLog::Log(LOGDEBUG, "AESinkAUDIOTrack: Using IEC PT mode: %d", CJNIAudioFormat::ENCODING_IEC61937); if (supports_192khz) { m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_EAC3); // Check for IEC 8 channel 192 khz PT int atChannelMask = AEChannelMapToAUDIOTRACKChannelMask(AE_CH_LAYOUT_7_1); if (IsSupported(192000, atChannelMask, CJNIAudioFormat::ENCODING_IEC61937)) { m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_TRUEHD); CLog::Log(LOGDEBUG, "8 Channel PT via IEC61937 is supported"); } } } } std::copy(m_sink_sampleRates.begin(), m_sink_sampleRates.end(), std::back_inserter(m_info.m_sampleRates)); } list.push_back(m_info); }
void CAESinkSNDIO::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { struct sio_hdl *hdl; struct sio_cap cap; if ((hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0)) == nullptr) { CLog::Log(LOGERROR, "CAESinkSNDIO::EnumerateDevicesEx - sio_open"); return; } if (!sio_getcap(hdl, &cap)) { CLog::Log(LOGERROR, "CAESinkSNDIO::EnumerateDevicesEx - sio_getcap"); return; } sio_close(hdl); hdl = nullptr; for (unsigned int i = 0; i < cap.nconf; i++) { CAEDeviceInfo info; sio_cap::sio_conf conf = cap.confs[i]; info.m_deviceName = SIO_DEVANY; info.m_displayName = "sndio"; info.m_displayNameExtra = "#" + std::to_string(i); info.m_deviceType = AE_DEVTYPE_PCM; info.m_wantsIECPassthrough = false; unsigned int maxchan = 0; for (unsigned int j = 0; j < SIO_NCHAN; j++) { if (conf.pchan & (1 << j)) maxchan = MAX(maxchan, cap.pchan[j]); } maxchan = MIN(maxchan, nitems(channelMap)); for (unsigned int j = 0; j < maxchan; j++) info.m_channels += channelMap[j]; for (unsigned int j = 0; j < SIO_NRATE; j++) { if (conf.rate & (1 << j)) { info.m_sampleRates.push_back(cap.rate[j]); } } for (unsigned int j = 0; j < SIO_NENC; j++) { if (conf.enc & (1 << j)) { AEDataFormat format = lookupDataFormat(cap.enc[j].bits, cap.enc[j].bps, cap.enc[j].sig, cap.enc[j].le, cap.enc[j].msb); if (format != AE_FMT_INVALID) info.m_dataFormats.push_back(format); } } list.push_back(info); } }
void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &device, const std::string &description, snd_config_t *config) { snd_pcm_t *pcmhandle = NULL; if (!OpenPCMDevice(device, "", ALSA_MAX_CHANNELS, &pcmhandle, config)) return; snd_pcm_info_t *pcminfo; snd_pcm_info_alloca(&pcminfo); memset(pcminfo, 0, snd_pcm_info_sizeof()); int err = snd_pcm_info(pcmhandle, pcminfo); if (err < 0) { CLog::Log(LOGINFO, "CAESinkALSA - Unable to get pcm_info for \"%s\"", device.c_str()); snd_pcm_close(pcmhandle); } int cardNr = snd_pcm_info_get_card(pcminfo); CAEDeviceInfo info; info.m_deviceName = device; info.m_deviceType = AEDeviceTypeFromName(device); if (cardNr >= 0) { /* "HDA NVidia", "HDA Intel", "HDA ATI HDMI", "SB Live! 24-bit External", ... */ char *cardName; if (snd_card_get_name(cardNr, &cardName) == 0) info.m_displayName = cardName; if (info.m_deviceType == AE_DEVTYPE_HDMI && info.m_displayName.size() > 5 && info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI") { /* We already know this is HDMI, strip it */ info.m_displayName.erase(info.m_displayName.size()-5); } /* "CONEXANT Analog", "USB Audio", "HDMI 0", "ALC889 Digital" ... */ std::string pcminfoName = snd_pcm_info_get_name(pcminfo); /* * Filter "USB Audio", in those cases snd_card_get_name() is more * meaningful already */ if (pcminfoName != "USB Audio") info.m_displayNameExtra = pcminfoName; if (info.m_deviceType == AE_DEVTYPE_HDMI) { /* replace, this was likely "HDMI 0" */ info.m_displayNameExtra = "HDMI"; int dev = snd_pcm_info_get_device(pcminfo); if (dev >= 0) { /* lets see if we can get ELD info */ snd_ctl_t *ctlhandle; std::stringstream sstr; sstr << "hw:" << cardNr; std::string strHwName = sstr.str(); if (snd_ctl_open_lconf(&ctlhandle, strHwName.c_str(), 0, config) == 0) { snd_hctl_t *hctl; if (snd_hctl_open_ctl(&hctl, ctlhandle) == 0) { snd_hctl_load(hctl); bool badHDMI = false; if (!GetELD(hctl, dev, info, badHDMI)) CLog::Log(LOGDEBUG, "CAESinkALSA - Unable to obtain ELD information for device \"%s\" (not supported by device, or kernel older than 3.2)", device.c_str()); /* snd_hctl_close also closes ctlhandle */ snd_hctl_close(hctl); if (badHDMI) { /* * Warn about disconnected devices, but keep them enabled * Detection can go wrong on Intel, Nvidia and on all * AMD (fglrx) hardware, so it is not safe to close those * handles */ CLog::Log(LOGDEBUG, "CAESinkALSA - HDMI device \"%s\" may be unconnected (no ELD data)", device.c_str()); } } else { snd_ctl_close(ctlhandle); } } } } else if (info.m_deviceType == AE_DEVTYPE_IEC958) { /* append instead of replace, pcminfoName is useful for S/PDIF */ if (!info.m_displayNameExtra.empty()) info.m_displayNameExtra += ' '; info.m_displayNameExtra += "S/PDIF"; } else if (info.m_displayNameExtra.empty()) { /* for USB audio, it gets a bit confusing as there is * - "SB Live! 24-bit External" * - "SB Live! 24-bit External, S/PDIF" * so add "Analog" qualifier to the first one */ info.m_displayNameExtra = "Analog"; } /* "default" is a device that will be used for all inputs, while * "@" will be mangled to front/default/surroundXX as necessary */ if (device == "@" || device == "default") { /* Make it "Default (whatever)" */ info.m_displayName = "Default (" + info.m_displayName + (info.m_displayNameExtra.empty() ? "" : " " + info.m_displayNameExtra + ")"); info.m_displayNameExtra = ""; } } else { /* virtual devices: "default", "pulse", ... */ /* description can be e.g. "PulseAudio Sound Server" - for hw devices it is * normally uninteresting, like "HDMI Audio Output" or "Default Audio Device", * so we only use it for virtual devices that have no better display name */ info.m_displayName = description; } snd_pcm_hw_params_t *hwparams; snd_pcm_hw_params_alloca(&hwparams); memset(hwparams, 0, snd_pcm_hw_params_sizeof()); /* ensure we can get a playback configuration for the device */ if (snd_pcm_hw_params_any(pcmhandle, hwparams) < 0) { CLog::Log(LOGINFO, "CAESinkALSA - No playback configurations available for device \"%s\"", device.c_str()); snd_pcm_close(pcmhandle); return; } /* detect the available sample rates */ for (unsigned int *rate = ALSASampleRateList; *rate != 0; ++rate) if (snd_pcm_hw_params_test_rate(pcmhandle, hwparams, *rate, 0) >= 0) info.m_sampleRates.push_back(*rate); /* detect the channels available */ int channels = 0; for (int i = ALSA_MAX_CHANNELS; i >= 1; --i) { /* Reopen the device if needed on the special "surroundXX" cases */ if (info.m_deviceType == AE_DEVTYPE_PCM && (i == 8 || i == 6 || i == 4)) OpenPCMDevice(device, "", i, &pcmhandle, config); if (snd_pcm_hw_params_test_channels(pcmhandle, hwparams, i) >= 0) { channels = i; break; } } if (device == "default" && channels == 2) { /* This looks like the ALSA standard default stereo dmix device, we * probably want to use "@" instead to get surroundXX. */ snd_pcm_close(pcmhandle); EnumerateDevice(list, "@", description, config); return; } CAEChannelInfo alsaChannels; for (int i = 0; i < channels; ++i) { if (!info.m_channels.HasChannel(ALSAChannelMap[i])) info.m_channels += ALSAChannelMap[i]; alsaChannels += ALSAChannelMap[i]; } /* remove the channels from m_channels that we cant use */ info.m_channels.ResolveChannels(alsaChannels); /* detect the PCM sample formats that are available */ for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1)) { if (AE_IS_RAW(i) || i == AE_FMT_MAX) continue; snd_pcm_format_t fmt = AEFormatToALSAFormat(i); if (fmt == SND_PCM_FORMAT_UNKNOWN) continue; if (snd_pcm_hw_params_test_format(pcmhandle, hwparams, fmt) >= 0) info.m_dataFormats.push_back(i); } snd_pcm_close(pcmhandle); list.push_back(info); }
void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list) { /* ensure that ALSA has been initialized */ if(!snd_config) snd_config_update(); snd_ctl_t *ctlhandle; snd_pcm_t *pcmhandle; snd_ctl_card_info_t *ctlinfo; snd_ctl_card_info_alloca(&ctlinfo); memset(ctlinfo, 0, snd_ctl_card_info_sizeof()); snd_pcm_hw_params_t *hwparams; snd_pcm_hw_params_alloca(&hwparams); memset(hwparams, 0, snd_pcm_hw_params_sizeof()); snd_pcm_info_t *pcminfo; snd_pcm_info_alloca(&pcminfo); memset(pcminfo, 0, snd_pcm_info_sizeof()); /* get the sound config */ snd_config_t *config; snd_config_copy(&config, snd_config); std::string strHwName; int n_cards = -1; while (snd_card_next(&n_cards) == 0 && n_cards != -1) { std::stringstream sstr; sstr << "hw:" << n_cards; std::string strHwName = sstr.str(); if (snd_ctl_open_lconf(&ctlhandle, strHwName.c_str(), 0, config) != 0) { CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Unable to open control for device %s", strHwName.c_str()); continue; } if (snd_ctl_card_info(ctlhandle, ctlinfo) != 0) { CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Unable to get card control info for device %s", strHwName.c_str()); snd_ctl_close(ctlhandle); continue; } snd_hctl_t *hctl; if (snd_hctl_open_ctl(&hctl, ctlhandle) != 0) hctl = NULL; snd_hctl_load(hctl); int pcm_index = 0; int iec958_index = 0; int hdmi_index = 0; int dev = -1; while (snd_ctl_pcm_next_device(ctlhandle, &dev) == 0 && dev != -1) { snd_pcm_info_set_device (pcminfo, dev); snd_pcm_info_set_subdevice(pcminfo, 0 ); snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK); if (snd_ctl_pcm_info(ctlhandle, pcminfo) < 0) { CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Skipping device %s,%d as it does not have PCM playback ability", strHwName.c_str(), dev); continue; } int dev_index; sstr.str(std::string()); CAEDeviceInfo info; std::string devname = snd_pcm_info_get_name(pcminfo); bool maybeHDMI = false; /* detect HDMI */ if (devname.find("HDMI") != std::string::npos) { info.m_deviceType = AE_DEVTYPE_HDMI; dev_index = hdmi_index++; sstr << "hdmi"; } else { /* detect IEC958 */ /* some HDMI devices (intel) report Digital for HDMI also */ if (devname.find("Digital") != std::string::npos) maybeHDMI = true; if (maybeHDMI || devname.find("IEC958" ) != std::string::npos) { info.m_deviceType = AE_DEVTYPE_IEC958; dev_index = iec958_index; /* dont increment, it might be HDMI */ sstr << "iec958"; } else { info.m_deviceType = AE_DEVTYPE_PCM; dev_index = pcm_index++; sstr << "hw"; } } /* build the driver string to pass to ALSA */ sstr << ":CARD=" << snd_ctl_card_info_get_id(ctlinfo) << ",DEV=" << dev_index; info.m_deviceName = sstr.str(); /* get the friendly display name*/ info.m_displayName = snd_ctl_card_info_get_name(ctlinfo); info.m_displayNameExtra = devname; /* open the device for testing */ int err = snd_pcm_open_lconf(&pcmhandle, info.m_deviceName.c_str(), SND_PCM_STREAM_PLAYBACK, 0, config); /* if open of possible IEC958 failed and it could be HDMI, try as HDMI */ if (err < 0 && maybeHDMI) { /* check for HDMI if it failed */ sstr.str(std::string()); dev_index = hdmi_index; sstr << "hdmi"; sstr << ":CARD=" << snd_ctl_card_info_get_id(ctlinfo) << ",DEV=" << dev_index; info.m_deviceName = sstr.str(); err = snd_pcm_open_lconf(&pcmhandle, info.m_deviceName.c_str(), SND_PCM_STREAM_PLAYBACK, 0, config); /* if it was valid, increment the index and set the type */ if (err >= 0) { ++hdmi_index; info.m_deviceType = AE_DEVTYPE_HDMI; } } /* if it's still IEC958, increment the index */ if (info.m_deviceType == AE_DEVTYPE_IEC958) ++iec958_index; /* final error check */ if (err < 0) { CLog::Log(LOGINFO, "CAESinkALSA::EnumerateDevicesEx - Unable to open %s for capability detection", strHwName.c_str()); continue; } /* see if we can get ELD for this device */ if (info.m_deviceType == AE_DEVTYPE_HDMI) { bool badHDMI = false; if (hctl && !GetELD(hctl, dev, info, badHDMI)) CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Unable to obtain ELD information for device %s, make sure you have ALSA >= 1.0.25", info.m_deviceName.c_str()); if (badHDMI) { CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Skipping HDMI device %s as it has no ELD data", info.m_deviceName.c_str()); continue; } } /* ensure we can get a playback configuration for the device */ if (snd_pcm_hw_params_any(pcmhandle, hwparams) < 0) { CLog::Log(LOGINFO, "CAESinkALSA::EnumerateDevicesEx - No playback configurations available for device %s", info.m_deviceName.c_str()); snd_pcm_close(pcmhandle); continue; } /* detect the available sample rates */ for (unsigned int *rate = ALSASampleRateList; *rate != 0; ++rate) if (snd_pcm_hw_params_test_rate(pcmhandle, hwparams, *rate, 0) >= 0) info.m_sampleRates.push_back(*rate); /* detect the channels available */ int channels = 0; for (int i = 1; i <= ALSA_MAX_CHANNELS; ++i) if (snd_pcm_hw_params_test_channels(pcmhandle, hwparams, i) >= 0) channels = i; CAEChannelInfo alsaChannels; for (int i = 0; i < channels; ++i) { if (!info.m_channels.HasChannel(ALSAChannelMap[i])) info.m_channels += ALSAChannelMap[i]; alsaChannels += ALSAChannelMap[i]; } /* remove the channels from m_channels that we cant use */ info.m_channels.ResolveChannels(alsaChannels); /* detect the PCM sample formats that are available */ for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1)) { if (AE_IS_RAW(i) || i == AE_FMT_MAX) continue; snd_pcm_format_t fmt = AEFormatToALSAFormat(i); if (fmt == SND_PCM_FORMAT_UNKNOWN) continue; if (snd_pcm_hw_params_test_format(pcmhandle, hwparams, fmt) >= 0) info.m_dataFormats.push_back(i); } snd_pcm_close(pcmhandle); list.push_back(info); } /* snd_hctl_close also closes ctlhandle */ if (hctl) snd_hctl_close(hctl); else snd_ctl_close(ctlhandle); } }
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 CAESinkPi::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { m_info.m_channels.Reset(); m_info.m_dataFormats.clear(); m_info.m_streamTypes.clear(); m_info.m_sampleRates.clear(); m_info.m_deviceType = AE_DEVTYPE_HDMI; m_info.m_deviceName = "HDMI"; m_info.m_displayName = "HDMI"; m_info.m_displayNameExtra = ""; m_info.m_channels += AE_CH_FL; m_info.m_channels += AE_CH_FR; for (unsigned int i=0; i<sizeof PassthroughSampleRates/sizeof *PassthroughSampleRates; i++) m_info.m_sampleRates.push_back(PassthroughSampleRates[i]); m_info.m_dataFormats.push_back(AE_FMT_FLOAT); m_info.m_dataFormats.push_back(AE_FMT_S32NE); m_info.m_dataFormats.push_back(AE_FMT_S16NE); m_info.m_dataFormats.push_back(AE_FMT_S32LE); m_info.m_dataFormats.push_back(AE_FMT_S16LE); m_info.m_dataFormats.push_back(AE_FMT_FLOATP); m_info.m_dataFormats.push_back(AE_FMT_S32NEP); m_info.m_dataFormats.push_back(AE_FMT_S16NEP); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_AC3); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_EAC3); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_CORE); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_2048); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_1024); m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_512); m_info.m_dataFormats.push_back(AE_FMT_RAW); m_info.m_wantsIECPassthrough = true; list.push_back(m_info); m_info.m_channels.Reset(); m_info.m_dataFormats.clear(); m_info.m_streamTypes.clear(); m_info.m_sampleRates.clear(); m_info.m_deviceType = AE_DEVTYPE_PCM; m_info.m_deviceName = "Analogue"; m_info.m_displayName = "Analogue"; m_info.m_displayNameExtra = ""; m_info.m_channels += AE_CH_FL; m_info.m_channels += AE_CH_FR; m_info.m_sampleRates.push_back(48000); m_info.m_dataFormats.push_back(AE_FMT_FLOAT); m_info.m_dataFormats.push_back(AE_FMT_S32LE); m_info.m_dataFormats.push_back(AE_FMT_S16LE); m_info.m_dataFormats.push_back(AE_FMT_FLOATP); m_info.m_dataFormats.push_back(AE_FMT_S32NEP); m_info.m_dataFormats.push_back(AE_FMT_S16NEP); m_info.m_wantsIECPassthrough = true; list.push_back(m_info); m_info.m_channels.Reset(); m_info.m_dataFormats.clear(); m_info.m_streamTypes.clear(); m_info.m_sampleRates.clear(); m_info.m_deviceType = AE_DEVTYPE_PCM; m_info.m_deviceName = "Both"; m_info.m_displayName = "HDMI and Analogue"; m_info.m_displayNameExtra = ""; m_info.m_channels += AE_CH_FL; m_info.m_channels += AE_CH_FR; m_info.m_sampleRates.push_back(48000); m_info.m_dataFormats.push_back(AE_FMT_FLOAT); m_info.m_dataFormats.push_back(AE_FMT_S32LE); m_info.m_dataFormats.push_back(AE_FMT_S16LE); m_info.m_dataFormats.push_back(AE_FMT_FLOATP); m_info.m_dataFormats.push_back(AE_FMT_S32NEP); m_info.m_dataFormats.push_back(AE_FMT_S16NEP); m_info.m_wantsIECPassthrough = true; list.push_back(m_info); }
void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { /* ensure that ALSA has been initialized */ snd_lib_error_set_handler(sndLibErrorHandler); if(!snd_config || force) { if(force) snd_config_update_free_global(); snd_config_update(); } snd_config_t *config; snd_config_copy(&config, snd_config); /* Always enumerate the default device. * Note: If "default" is a stereo device, EnumerateDevice() * will automatically add "@" instead to enable surroundXX mangling. * We don't want to do that if "default" can handle multichannel * itself (e.g. in case of a pulseaudio server). */ EnumerateDevice(list, "default", "", config); void **hints; if (snd_device_name_hint(-1, "pcm", &hints) < 0) { CLog::Log(LOGINFO, "CAESinkALSA - Unable to get a list of devices"); return; } std::string defaultDescription; for (void** hint = hints; *hint != NULL; ++hint) { char *io = snd_device_name_get_hint(*hint, "IOID"); char *name = snd_device_name_get_hint(*hint, "NAME"); char *desc = snd_device_name_get_hint(*hint, "DESC"); if ((!io || strcmp(io, "Output") == 0) && name && strcmp(name, "null") != 0) { std::string baseName = std::string(name); baseName = baseName.substr(0, baseName.find(':')); if (strcmp(name, "default") == 0) { /* added already, but lets get the description if we have one */ if (desc) defaultDescription = desc; } else if (baseName == "front") { /* Enumerate using the surroundXX mangling */ /* do not enumerate basic "front", it is already handled * by the default "@" entry added in the very beginning */ if (strcmp(name, "front") != 0) EnumerateDevice(list, std::string("@") + (name+5), desc ? desc : name, config); } /* Do not enumerate "default", it is already enumerated above. */ /* Do not enumerate the sysdefault or surroundXX devices, those are * always accompanied with a "front" device and it is handled above * as "@". The below devices will be automatically used if available * for a "@" device. */ /* Ubuntu has patched their alsa-lib so that "defaults.namehint.extended" * defaults to "on" instead of upstream "off", causing lots of unwanted * extra devices (many of which are not actually routed properly) to be * found by the enumeration process. Skip them as well ("hw", "dmix", * "plughw", "dsnoop"). */ else if (baseName != "default" && baseName != "sysdefault" && baseName != "surround40" && baseName != "surround41" && baseName != "surround50" && baseName != "surround51" && baseName != "surround71" && baseName != "hw" && baseName != "dmix" && baseName != "plughw" && baseName != "dsnoop") { EnumerateDevice(list, name, desc ? desc : name, config); } } free(io); free(name); free(desc); } snd_device_name_free_hint(hints); /* set the displayname for default device */ if (!list.empty() && list[0].m_deviceName == "default") { /* If we have one from a hint (DESC), use it */ if (!defaultDescription.empty()) list[0].m_displayName = defaultDescription; /* Otherwise use the discovered name or (unlikely) "Default" */ else if (list[0].m_displayName.empty()) list[0].m_displayName = "Default"; } /* lets check uniqueness, we may need to append DEV or CARD to DisplayName */ /* If even a single device of card/dev X clashes with Y, add suffixes to * all devices of both them, for clarity. */ /* clashing card names, e.g. "NVidia", "NVidia_2" */ std::set<std::string> cardsToAppend; /* clashing basename + cardname combinations, e.g. ("hdmi","Nvidia") */ std::set<std::pair<std::string, std::string> > devsToAppend; for (AEDeviceInfoList::iterator it1 = list.begin(); it1 != list.end(); ++it1) { for (AEDeviceInfoList::iterator it2 = it1+1; it2 != list.end(); ++it2) { if (it1->m_displayName == it2->m_displayName && it1->m_displayNameExtra == it2->m_displayNameExtra) { /* something needs to be done */ std::string cardString1 = GetParamFromName(it1->m_deviceName, "CARD"); std::string cardString2 = GetParamFromName(it2->m_deviceName, "CARD"); if (cardString1 != cardString2) { /* card name differs, add identifiers to all devices */ cardsToAppend.insert(cardString1); cardsToAppend.insert(cardString2); continue; } std::string devString1 = GetParamFromName(it1->m_deviceName, "DEV"); std::string devString2 = GetParamFromName(it2->m_deviceName, "DEV"); if (devString1 != devString2) { /* device number differs, add identifiers to all such devices */ devsToAppend.insert(std::make_pair(it1->m_deviceName.substr(0, it1->m_deviceName.find(':')), cardString1)); devsToAppend.insert(std::make_pair(it2->m_deviceName.substr(0, it2->m_deviceName.find(':')), cardString2)); continue; } /* if we got here, the configuration is really weird, just append the whole device string */ it1->m_displayName += " (" + it1->m_deviceName + ")"; it2->m_displayName += " (" + it2->m_deviceName + ")"; } } } for (std::set<std::string>::iterator it = cardsToAppend.begin(); it != cardsToAppend.end(); ++it) { for (AEDeviceInfoList::iterator itl = list.begin(); itl != list.end(); ++itl) { std::string cardString = GetParamFromName(itl->m_deviceName, "CARD"); if (cardString == *it) /* "HDA NVidia (NVidia)", "HDA NVidia (NVidia_2)", ... */ itl->m_displayName += " (" + cardString + ")"; } } for (std::set<std::pair<std::string, std::string> >::iterator it = devsToAppend.begin(); it != devsToAppend.end(); ++it) { for (AEDeviceInfoList::iterator itl = list.begin(); itl != list.end(); ++itl) { std::string baseName = itl->m_deviceName.substr(0, itl->m_deviceName.find(':')); std::string cardString = GetParamFromName(itl->m_deviceName, "CARD"); if (baseName == it->first && cardString == it->second) { std::string devString = GetParamFromName(itl->m_deviceName, "DEV"); /* "HDMI #0", "HDMI #1" ... */ itl->m_displayNameExtra += " #" + devString; } } } }
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); }
void CAESinkOSS::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { int mixerfd; const char * mixerdev = "/dev/mixer"; if ((mixerfd = open(mixerdev, O_RDWR, 0)) == -1) { CLog::Log(LOGNOTICE, "CAESinkOSS::EnumerateDevicesEx - No OSS mixer device present: %s", mixerdev); return; } #if defined(SNDCTL_SYSINFO) && defined(SNDCTL_CARDINFO) oss_sysinfo sysinfo; if (ioctl(mixerfd, SNDCTL_SYSINFO, &sysinfo) == -1) { // hardware not supported // OSSv4 required ? close(mixerfd); return; } for (int i = 0; i < sysinfo.numcards; ++i) { std::stringstream devicepath; std::stringstream devicename; CAEDeviceInfo info; oss_card_info cardinfo; devicepath << "/dev/dsp" << i; info.m_deviceName = devicepath.str(); cardinfo.card = i; if (ioctl(mixerfd, SNDCTL_CARDINFO, &cardinfo) == -1) break; devicename << cardinfo.shortname << " " << cardinfo.longname; info.m_displayName = devicename.str(); if (info.m_displayName.find("HDMI") != std::string::npos) info.m_deviceType = AE_DEVTYPE_HDMI; else if (info.m_displayName.find("Digital") != std::string::npos) info.m_deviceType = AE_DEVTYPE_IEC958; else info.m_deviceType = AE_DEVTYPE_PCM; oss_audioinfo ainfo; memset(&ainfo, 0, sizeof(ainfo)); ainfo.dev = i; if (ioctl(mixerfd, SNDCTL_AUDIOINFO, &ainfo) != -1) { #if 0 if (ainfo.oformats & AFMT_S32_LE) info.m_dataFormats.push_back(AE_FMT_S32LE); if (ainfo.oformats & AFMT_S16_LE) info.m_dataFormats.push_back(AE_FMT_S16LE); #endif for (int j = 0; j < ainfo.max_channels && AE_CH_NULL != OSSChannelMap[j]; ++j) info.m_channels += OSSChannelMap[j]; for (int *rate = OSSSampleRateList; *rate != 0; ++rate) if (*rate >= ainfo.min_rate && *rate <= ainfo.max_rate) info.m_sampleRates.push_back(*rate); } list.push_back(info); } #endif close(mixerfd); }
void CAESinkIntelSMD::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { VERBOSE(); LoadEDID(); int maxChannels; std::vector<AEDataFormat> formats; std::vector<unsigned int> rates; GetEDIDInfo(maxChannels, formats, rates); // most likely TODO(q)- now messed up by quasar? // And now even more messed up by Keyser :) CAEDeviceInfo info; info.m_channels.Reset(); info.m_dataFormats.clear(); info.m_sampleRates.clear(); info.m_deviceType = AE_DEVTYPE_PCM; info.m_deviceName = "All"; info.m_displayName = "All Outputs"; info.m_displayNameExtra = "HDMI/SPDIF/Analog"; info.m_channels += AE_CH_FL; info.m_channels += AE_CH_FR; // support the rates available on HDMI, SPDIF and Analog will already support them std::vector<unsigned int>::const_iterator it, itEnd = rates.end(); for (it = rates.begin(); it != itEnd; ++it) info.m_sampleRates.push_back(*it); info.m_dataFormats.push_back(AE_FMT_S16LE); list.push_back(info); info.m_channels.Reset(); info.m_dataFormats.clear(); //info.m_sampleRates.clear(); info.m_deviceType = AE_DEVTYPE_HDMI; info.m_deviceName = "HDMI"; info.m_displayName = "HDMI"; info.m_displayNameExtra = "HDMI Output"; for (int i = 0; i < maxChannels; ++i) info.m_channels += s_chMap[i]; //info.m_sampleRates.push_back(48000); std::vector<AEDataFormat>::const_iterator itFormat, itFormatEnd = formats.end(); for (itFormat = formats.begin(); itFormat != itFormatEnd; ++itFormat) info.m_dataFormats.push_back(*itFormat); list.push_back(info); info.m_channels.Reset(); info.m_dataFormats.clear(); info.m_sampleRates.clear(); info.m_deviceType = AE_DEVTYPE_IEC958; info.m_deviceName = "SPDIF"; info.m_displayName = "SPDIF"; info.m_displayNameExtra = "Toslink Output"; info.m_channels += AE_CH_FL; info.m_channels += AE_CH_FR; //info.m_sampleRates.push_back(12000); //info.m_sampleRates.push_back(24000); info.m_sampleRates.push_back(32000); info.m_sampleRates.push_back(44100); info.m_sampleRates.push_back(48000); info.m_sampleRates.push_back(88200); info.m_sampleRates.push_back(96000); info.m_sampleRates.push_back(176400); info.m_sampleRates.push_back(192000); info.m_dataFormats.push_back(AE_FMT_S24NE4); info.m_dataFormats.push_back(AE_FMT_LPCM); info.m_dataFormats.push_back(AE_FMT_S16LE); info.m_dataFormats.push_back(AE_FMT_AC3); info.m_dataFormats.push_back(AE_FMT_DTS); info.m_dataFormats.push_back(AE_FMT_EAC3); list.push_back(info); info.m_channels.Reset(); info.m_dataFormats.clear(); info.m_sampleRates.clear(); info.m_deviceType = AE_DEVTYPE_PCM; info.m_deviceName = "Analog"; info.m_displayName = "Analog"; info.m_displayNameExtra = "RCA Outputs"; info.m_channels += AE_CH_FL; info.m_channels += AE_CH_FR; //info.m_sampleRates.push_back(12000); //info.m_sampleRates.push_back(24000); info.m_sampleRates.push_back(32000); info.m_sampleRates.push_back(44100); info.m_sampleRates.push_back(48000); info.m_sampleRates.push_back(88200); info.m_sampleRates.push_back(96000); info.m_sampleRates.push_back(176400); info.m_sampleRates.push_back(192000); info.m_dataFormats.push_back(AE_FMT_S16LE); list.push_back(info); }