18#include <mmdeviceapi.h>
21#include <QtCore/qmap.h>
37 m_enumerator(enumerator),
38 m_windowsMediaDevices(windowsMediaDevices),
39 m_deviceState(deviceState)
45 ULONG STDMETHODCALLTYPE
AddRef()
override
47 return InterlockedIncrement(&m_cRef);
50 ULONG STDMETHODCALLTYPE
Release()
override
52 ULONG ulRef = InterlockedDecrement(&m_cRef);
61 if (IID_IUnknown ==
riid) {
63 *ppvInterface = (IUnknown*)
this;
64 }
else if (__uuidof(IMMNotificationClient) ==
riid) {
66 *ppvInterface = (IMMNotificationClient*)
this;
76 if (role == ERole::eMultimedia)
85 if (
it == std::end(m_deviceState)) {
97 if (
it != std::end(m_deviceState)) {
98 if (
it.value() == DEVICE_STATE_ACTIVE)
110 if ((
it.value() == DEVICE_STATE_ACTIVE) != (
newState == DEVICE_STATE_ACTIVE)) {
127 if (flow == EDataFlow::eCapture) {
129 }
else if (flow == EDataFlow::eRender) {
140 if (SUCCEEDED(m_enumerator->GetDevice(deviceID,
device.GetAddressOf()))
141 && SUCCEEDED(
device->QueryInterface(__uuidof(IMMEndpoint), (
void**)endpoint.GetAddressOf()))
142 && SUCCEEDED(endpoint->GetDataFlow(&flow)))
152 CoInitialize(
nullptr);
154 auto hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
nullptr,
155 CLSCTX_INPROC_SERVER,__uuidof(IMMDeviceEnumerator),
156 (
void**)&m_deviceEnumerator);
163 if (SUCCEEDED(m_deviceEnumerator->EnumAudioEndpoints(EDataFlow::eAll, DEVICE_STATEMASK_ALL, devColl.GetAddressOf()))
164 && SUCCEEDED(devColl->GetCount(&
count)))
171 if (SUCCEEDED(devColl->Item(
i,
device.GetAddressOf()))
173 && SUCCEEDED(
device->GetId(
id.address()))) {
180 m_notificationClient =
181 makeComObject<CMMNotificationClient>(
this, m_deviceEnumerator, std::move(devState));
182 m_deviceEnumerator->RegisterEndpointNotificationCallback(m_notificationClient.Get());
185 qWarning() <<
"Audio device change notification disabled";
191 if (m_deviceEnumerator) {
192 m_deviceEnumerator->UnregisterEndpointNotificationCallback(m_notificationClient.Get());
194 if (m_warmUpAudioClient) {
195 HRESULT hr = m_warmUpAudioClient->Stop();
197 qWarning() <<
"Failed to stop audio engine" << hr;
201 m_deviceEnumerator.Reset();
202 m_notificationClient.Reset();
203 m_warmUpAudioClient.Reset();
212 const auto defaultAudioDeviceID = [
this, audioOut]{
213 const auto dataFlow = audioOut ? EDataFlow::eRender : EDataFlow::eCapture;
218 if (SUCCEEDED(m_deviceEnumerator->GetDefaultAudioEndpoint(dataFlow, ERole::eMultimedia, dev.GetAddressOf()))) {
219 if (dev && SUCCEEDED(dev->GetId(
id.address()))) {
228 auto waveDevices = audioOut ? waveOutGetNumDevs() : waveInGetNumDevs();
230 for (
auto waveID = 0u; waveID < waveDevices; waveID++) {
231 auto wave = IntToPtr(waveID);
232 auto waveMessage = [wave, audioOut](UINT msg,
auto p0,
auto p1) {
238 if (waveMessage(DRV_QUERYFUNCTIONINSTANCEIDSIZE, &
len, 0) != MMSYSERR_NOERROR)
242 if (waveMessage(DRV_QUERYFUNCTIONINSTANCEID,
id.
data(),
len) != MMSYSERR_NOERROR)
247 if (FAILED(m_deviceEnumerator->GetDevice(
id.data(),
device.GetAddressOf()))
248 || FAILED(
device->OpenPropertyStore(STGM_READ,
props.GetAddressOf()))) {
253 PropVariantInit(&varName);
260 dev->isDefault = strID == defaultAudioDeviceID;
264 PropVariantClear(&varName);
296 if (m_isAudioClientWarmedUp.exchange(
true))
300 HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
nullptr, CLSCTX_ALL,
301 __uuidof(IMMDeviceEnumerator),
302 reinterpret_cast<void **
>(deviceEnumerator.GetAddressOf()));
304 qWarning() <<
"Failed to create device enumerator" << hr;
309 hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole,
device.GetAddressOf());
311 qWarning() <<
"Failed to retrieve default audio endpoint" << hr;
315 hr =
device->Activate(__uuidof(IAudioClient3), CLSCTX_ALL,
nullptr,
316 reinterpret_cast<void **
>(m_warmUpAudioClient.GetAddressOf()));
318 qWarning() <<
"Failed to activate audio engine" << hr;
323 UINT32 currentPeriodInFrames = 0;
324 hr = m_warmUpAudioClient->GetCurrentSharedModeEnginePeriod(deviceFormat.
address(),
325 ¤tPeriodInFrames);
327 qWarning() <<
"Failed to retrieve the current format and periodicity of the audio engine"
332 UINT32 defaultPeriodInFrames = 0;
333 UINT32 fundamentalPeriodInFrames = 0;
334 UINT32 minPeriodInFrames = 0;
335 UINT32 maxPeriodInFrames = 0;
336 hr = m_warmUpAudioClient->GetSharedModeEnginePeriod(deviceFormat.
get(), &defaultPeriodInFrames,
337 &fundamentalPeriodInFrames,
338 &minPeriodInFrames, &maxPeriodInFrames);
340 qWarning() <<
"Failed to retrieve the range of periodicities supported by the audio engine"
345 hr = m_warmUpAudioClient->InitializeSharedAudioStream(
346 AUDCLNT_SHAREMODE_SHARED, minPeriodInFrames, deviceFormat.
get(),
nullptr);
348 qWarning() <<
"Failed to initialize audio engine stream" << hr;
352 hr = m_warmUpAudioClient->Start();
354 qWarning() <<
"Failed to start audio engine" << hr;
IOBluetoothDevice * device
void emitAudioDevicesChanged(EDataFlow flow)
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR) override
ULONG STDMETHODCALLTYPE Release() override
ULONG STDMETHODCALLTYPE AddRef() override
void emitAudioDevicesChanged(LPCWSTR deviceID)
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR deviceID, DWORD newState) override
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) override
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR deviceID) override
CMMNotificationClient(QWindowsMediaDevices *windowsMediaDevices, ComPtr< IMMDeviceEnumerator > enumerator, QMap< QString, DWORD > &&deviceState)
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY) override
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR deviceID) override
virtual ~CMMNotificationClient()
The QAudioDevice class provides an information about audio devices and their functionality.
Mode
Describes the mode of this device.
const QAudioDevicePrivate * handle() const
iterator insert(const Key &key, const T &value)
size_type remove(const Key &key)
iterator find(const Key &key)
QObject * parent() const
Returns a pointer to the parent object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
QByteArray toUtf8() const &
QSet< QString >::iterator it
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
Combined button and popup list for selecting options.
static QDBusError::ErrorType get(const char *name)
GLenum GLenum GLsizei count
GLenum GLuint GLsizei const GLenum * props
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
IUIViewSettingsInterop __RPC__in REFIID riid
const PROPERTYKEY QMM_PKEY_Device_FriendlyName
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent