Version
menu_open
Wwise SDK 2023.1.5
AkMMDevice.h
Go to the documentation of this file.
1 /*******************************************************************************
2 The content of this file includes portions of the AUDIOKINETIC Wwise Technology
3 released in source code form as part of the SDK installer package.
4 
5 Commercial License Usage
6 
7 Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
8 may use this file in accordance with the end user license agreement provided
9 with the software or, alternatively, in accordance with the terms contained in a
10 written agreement between you and Audiokinetic Inc.
11 
12 Apache License Usage
13 
14 Alternatively, this file may be used under the Apache License, Version 2.0 (the
15 "Apache License"); you may not use this file except in compliance with the
16 Apache License. You may obtain a copy of the Apache License at
17 http://www.apache.org/licenses/LICENSE-2.0.
18 
19 Unless required by applicable law or agreed to in writing, software distributed
20 under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
21 OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
22 the specific language governing permissions and limitations under the License.
23 
24  Copyright (c) 2024 Audiokinetic Inc.
25 *******************************************************************************/
26 
27 // AkMMDevice.h -- C++ RIAA object wrappers for Win32 MMDevice enumeration APIs
28 
29 #pragma once
30 
33 
34 // Fix for Windows SDK 10.0.17763.0
35 #if !defined(_DEBUG)
36 namespace Microsoft {
37  namespace WRL {
38  namespace Details {
39  template <typename T>
40  inline void CheckForDuplicateEntries() {}
41  }
42  }
43 }
44 #endif
45 
46 #include <mmdeviceapi.h>
47 
48 namespace AK
49 {
50  namespace Win32
51  {
53  {
54  public:
55  // Default constructor
57  {
58  PropVariantInit(&variant);
59  }
60 
61  // Construct a property from an existing property store
62  DeviceProperty(const PROPERTYKEY &key, IPropertyStore* in_pProps)
63  {
64  PropVariantInit(&variant);
65  if (in_pProps) in_pProps->GetValue(key, &variant);
66  }
67 
68  // Move constructor
70  {
71  variant = other.variant;
72  PropVariantInit(&other.variant);
73  }
74 
75  // Copy construction is not allowed
76  DeviceProperty(const DeviceProperty& other) = delete;
77 
78  // Destructor
80  {
81  PropVariantClear(&variant);
82  }
83 
84  // Move assignment
86  {
87  PropVariantClear(&variant);
88  variant = other.variant;
89  PropVariantInit(&other.variant);
90  return *this;
91  }
92 
93  // Copy assignment is not allowed
94  DeviceProperty& operator=(const DeviceProperty& other) = delete;
95 
96  bool IsEmpty() const { return variant.vt == VT_EMPTY; }
97 
98  PROPVARIANT variant;
99  };
100 
102  {
103  public:
104  // Default constructor
106  : pProps(nullptr)
107  {
108  }
109 
110  // Construct properties from an IMMDevice
111  DeviceProperties(IMMDevice* in_pDevice)
112  {
113  in_pDevice->OpenPropertyStore(STGM_READ, &pProps);
114  }
115 
116  // Move constructor
118  {
119  pProps = other.pProps;
120  other.pProps = nullptr;
121  }
122 
123  // Copy construction is not allowed
124  DeviceProperties(const DeviceProperties& other) = delete;
125 
126  // Destructor
128  {
129  if (pProps)
130  {
131  pProps->Release();
132  pProps = nullptr;
133  }
134  }
135 
136  // Move assignment
138  {
139  if (pProps)
140  pProps->Release();
141  pProps = other.pProps;
142  other.pProps = nullptr;
143  return *this;
144  }
145 
146  // Copy assignment is not allowed
147  DeviceProperties& operator=(const DeviceProperties& other) = delete;
148 
149  bool IsValid() { return pProps != nullptr; }
150 
151  DeviceProperty GetProperty(const PROPERTYKEY& key)
152  {
153  return DeviceProperty(key, pProps);
154  }
155 
156  IPropertyStore* pProps;
157  };
158  class Device
159  {
160  public:
161  // Default constructor
163  : pDevice(nullptr)
165  {
166  }
167 
168  // Move constructor
169  Device(Device&& other)
170  : pDevice(nullptr)
171  {
172  SetDevice(other.pDevice);
173  other.pDevice = nullptr;
174  }
175 
176  Device(const Device& other)
177  : pDevice(nullptr)
178  {
179  *this = other;
180  }
181 
182  // Destructor
184  {
185  if (pDevice)
186  {
187  pDevice->Release();
188  pDevice = nullptr;
189  }
190  }
191 
192  // Move assignment
194  {
195  if (pDevice)
196  {
197  pDevice->Release();
198  pDevice = nullptr; // Do not remove, protects against this == &other
199  }
200  pDevice = other.pDevice;
201  idDevice = other.idDevice;
202  other.pDevice = nullptr;
203  return *this;
204  }
205 
206  Device& operator=(const Device& other)
207  {
208  if (pDevice)
209  {
210  pDevice->Release();
211  pDevice = nullptr; // Do not remove, protects against this == &other
212  }
213  pDevice = other.pDevice;
214  if (pDevice)
215  pDevice->AddRef();
216  idDevice = other.idDevice;
217  return *this;
218  }
219 
220  Device& operator=(IMMDevice* pOther)
221  {
222  SetDevice(pOther);
223  if (pDevice)
224  pDevice->AddRef();
225  return *this;
226  }
227 
228  bool IsValid() const { return pDevice != nullptr; }
229 
231  {
233  }
234 
236  {
237  return DeviceProperties(pDevice);
238  }
239 
240  void ComputeId()
241  {
243  if (pDevice)
244  {
245  //Inlined version of GetDeviceID.
246  LPWSTR pwszID = NULL;
247  if (pDevice->GetId(&pwszID) == S_OK)
248  {
249  char szString[260];
250  AKPLATFORM::AkWideCharToChar(pwszID, 260 - 1, szString);
251  szString[260 - 1] = 0;
252 
253  idDevice = FNVHash32::ComputeLowerCase((const char*)szString);
254  CoTaskMemFree(pwszID);
255  }
256  }
257  }
258 
259  void SetDevice(IMMDevice* in_pNew)
260  {
261  if (pDevice)
262  pDevice->Release();
263  pDevice = in_pNew;
264  ComputeId();
265  }
266 
267  interface IMMDevice* pDevice;
269  };
271  {
272  public:
273  class Iterator
274  {
275  public:
276  Iterator(IMMDeviceCollection* in_pDevices, UINT in_i)
277  : pDevices(in_pDevices)
278  , i(in_i)
279  {
280  }
281 
282  /// + operator</span>
284  {
285  Iterator returnedIt(pDevices, i + inc);
286  return returnedIt;
287  }
288 
289  /// - operator</span>
290  AkUInt32 operator-(Iterator const& rhs) const
291  {
292  return (AkUInt32)(i - rhs.i);
293  }
294 
295  /// ++ operator</span>
297  {
298  ++i;
299  return *this;
300  }
301 
302  /// -- operator</span>
304  {
305  --i;
306  return *this;
307  }
308 
309  /// == operator</span>
310  bool operator ==(const Iterator& in_rOp) const
311  {
312  return (pDevices == in_rOp.pDevices && i == in_rOp.i);
313  }
314 
315  /// != operator</span>
316  bool operator !=(const Iterator& in_rOp) const
317  {
318  return (pDevices != in_rOp.pDevices || i != in_rOp.i);
319  }
320 
322  {
323  Device pDevice;
324  pDevices->Item(i, (IMMDevice**)&pDevice.pDevice); //Transfer the ref
325  if (pDevice.pDevice)
326  pDevice.ComputeId();
327  return pDevice;
328  }
329 
330  interface IMMDeviceCollection* pDevices; //Keep first.
331  UINT i;
332  };
333 
334  DeviceCollection(IMMDeviceEnumerator* pEnumerator)
335  : pDevices(nullptr)
336  , uCount(0)
337  {
338  pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATEMASK_ALL, &pDevices);
339  if (pDevices)
340  pDevices->GetCount(&uCount);
341  }
342  DeviceCollection(IMMDeviceEnumerator* pEnumerator, EDataFlow eFlow, DWORD dwStateMask)
343  : pDevices(nullptr)
344  , uCount(0)
345  {
346 
347  pEnumerator->EnumAudioEndpoints(eFlow, dwStateMask, &pDevices);
348  if (pDevices)
349  pDevices->GetCount(&uCount);
350  }
351 
352  // Move constructor
354  {
355  pDevices = other.pDevices;
356  uCount = other.uCount;
357  other.pDevices = nullptr;
358  other.uCount = 0;
359  }
360 
361  // Copy construction is not allowed
362  DeviceCollection(const DeviceCollection& other) = delete;
363 
364  // Destructor
366  {
367  if (pDevices)
368  {
369  pDevices->Release();
370  pDevices = nullptr;
371  }
372  }
373 
374  // Move assignment
376  {
377  if (pDevices)
378  {
379  pDevices->Release();
380  }
381  pDevices = other.pDevices;
382  uCount = other.uCount;
383  other.pDevices = nullptr;
384  other.uCount = 0;
385  return *this;
386  }
387 
388  // Copy assignment is not allowed
389  DeviceCollection& operator=(const DeviceCollection& other) = delete;
390 
391  bool IsValid() const { return pDevices != nullptr; }
392 
393  UINT Count() const
394  {
395  return uCount;
396  }
397 
399  {
400  Iterator it(pDevices, 0);
401  return it;
402  }
404  {
405  Iterator it(pDevices, uCount);
406  return it;
407  }
408 
409  interface IMMDeviceCollection* pDevices;
410  UINT uCount;
411  };
412 
414  {
415  public:
416 
418  : pEnumerator(nullptr)
419  {
420  CoCreateInstance(
421  __uuidof(MMDeviceEnumerator), NULL,
422  CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
423  (void**)&pEnumerator);
424  }
425 
426  // Move constructor
428  {
429  pEnumerator = other.pEnumerator;
430  other.pEnumerator = nullptr;
431  }
432 
433  // Copy construction is not allowed
434  DeviceEnumerator(const DeviceEnumerator& other) = delete;
435 
436  // Destructor
438  {
439  if (pEnumerator)
440  {
441  pEnumerator->Release();
442  pEnumerator = nullptr;
443  }
444  }
445 
446  // Move assignment
448  {
449  if (pEnumerator)
450  {
451  pEnumerator->Release();
452  }
453  pEnumerator = other.pEnumerator;
454  other.pEnumerator = nullptr;
455  return *this;
456  }
457 
458  // Copy assignment is not allowed
459  DeviceEnumerator& operator=(const DeviceEnumerator& other) = delete;
460 
461  bool IsValid() { return pEnumerator != nullptr; }
462 
463  Device GetDefaultDevice(ERole in_eRole)
464  {
465  Device pDevice;
466  pEnumerator->GetDefaultAudioEndpoint(eRender, in_eRole, (IMMDevice**)&pDevice.pDevice); //Transfer the ref
467  if (pDevice.pDevice)
468  pDevice.ComputeId();
469  return pDevice;
470  }
471 
472  interface IMMDeviceEnumerator* pEnumerator;
473  };
474 
475  /// Interface to access the IMMDevice cache. This avoids driver accesses.
477  {
478  public:
479  virtual AkUInt32 Count() = 0; ///Returns the number of devices. This function can block.
480  virtual Device Item(AkUInt32 in_idx) = 0; ///Gets item in_idx from the cache. Must be smaller than Count(). This function can block.
481  virtual void Lock() = 0; /// For thread safety. If you iterate through all the devices, lock the enumerator to avoid changes. However, if only accessing one single item, Item() is thread safe in itself.
482  virtual void Unlock() = 0; /// For thread safety. See \ref Lock()
483  virtual Device FindDevice(AkUInt32 in_id) = 0; ///Find a device that has this unique ID. The Id is one returned by AK::GetDeviceID.
484  };
485  }
486 };
AkUInt32 idDevice
Definition: AkMMDevice.h:268
AkUInt32 GetDeviceID() const
Definition: AkMMDevice.h:230
Audiokinetic namespace.
virtual Device Item(AkUInt32 in_idx)=0
Returns the number of devices. This function can block.
DeviceProperty(const PROPERTYKEY &key, IPropertyStore *in_pProps)
Definition: AkMMDevice.h:62
DeviceCollection(IMMDeviceEnumerator *pEnumerator, EDataFlow eFlow, DWORD dwStateMask)
Definition: AkMMDevice.h:342
DeviceProperties(const DeviceProperties &other)=delete
DeviceEnumerator & operator=(const DeviceEnumerator &other)=delete
Iterator(IMMDeviceCollection *in_pDevices, UINT in_i)
Definition: AkMMDevice.h:276
void SetDevice(IMMDevice *in_pNew)
Definition: AkMMDevice.h:259
DeviceProperty GetProperty(const PROPERTYKEY &key)
Definition: AkMMDevice.h:151
virtual void Lock()=0
Gets item in_idx from the cache. Must be smaller than Count(). This function can block.
Device & operator=(const Device &other)
Definition: AkMMDevice.h:206
DeviceProperties & operator=(DeviceProperties &&other)
Definition: AkMMDevice.h:137
static const AkDeviceID AK_INVALID_DEVICE_ID
Invalid streaming device ID.
Definition: AkTypes.h:103
DeviceCollection(const DeviceCollection &other)=delete
DeviceProperties GetProperties() const
Definition: AkMMDevice.h:235
interface IMMDevice * pDevice
Definition: AkMMDevice.h:267
#define NULL
Definition: AkTypes.h:46
Device(const Device &other)
Definition: AkMMDevice.h:176
DeviceCollection & operator=(DeviceCollection &&other)
Definition: AkMMDevice.h:375
DeviceCollection(DeviceCollection &&other)
Definition: AkMMDevice.h:353
DeviceProperties & operator=(const DeviceProperties &other)=delete
Interface to access the IMMDevice cache. This avoids driver accesses.
Definition: AkMMDevice.h:477
DeviceProperty(const DeviceProperty &other)=delete
Iterator operator+(AkUInt32 inc) const
Definition: AkMMDevice.h:283
DeviceEnumerator(DeviceEnumerator &&other)
Definition: AkMMDevice.h:427
interface IMMDeviceCollection * pDevices
Definition: AkMMDevice.h:330
interface IMMDeviceEnumerator * pEnumerator
Definition: AkMMDevice.h:472
Device & operator=(Device &&other)
Definition: AkMMDevice.h:193
virtual AkUInt32 Count()=0
interface IMMDeviceCollection * pDevices
Definition: AkMMDevice.h:409
bool IsValid() const
Definition: AkMMDevice.h:228
bool operator!=(const Iterator &in_rOp) const
!= operator</div>
Definition: AkMMDevice.h:316
IPropertyStore * pProps
Definition: AkMMDevice.h:156
DeviceProperty & operator=(const DeviceProperty &other)=delete
AkUInt32 operator-(Iterator const &rhs) const
Definition: AkMMDevice.h:290
DeviceEnumerator(const DeviceEnumerator &other)=delete
Iterator & operator++()
++ operator</div>
Definition: AkMMDevice.h:296
DeviceProperties(IMMDevice *in_pDevice)
Definition: AkMMDevice.h:111
virtual void Unlock()=0
For thread safety. If you iterate through all the devices, lock the enumerator to avoid changes....
bool operator==(const Iterator &in_rOp) const
== operator</div>
Definition: AkMMDevice.h:310
DeviceProperty(DeviceProperty &&other)
Definition: AkMMDevice.h:69
DeviceCollection(IMMDeviceEnumerator *pEnumerator)
Definition: AkMMDevice.h:334
uint32_t AkUInt32
Unsigned 32-bit integer.
virtual Device FindDevice(AkUInt32 in_id)=0
For thread safety. See Lock()
Device & operator=(IMMDevice *pOther)
Definition: AkMMDevice.h:220
DeviceEnumerator & operator=(DeviceEnumerator &&other)
Definition: AkMMDevice.h:447
Device GetDefaultDevice(ERole in_eRole)
Definition: AkMMDevice.h:463
AkForceInline AkInt32 AkWideCharToChar(const wchar_t *in_pszUnicodeString, AkUInt32 in_uiOutBufferSize, char *io_pszAnsiString)
String conversion helper.
DeviceCollection & operator=(const DeviceCollection &other)=delete
void CheckForDuplicateEntries()
Definition: AkMMDevice.h:40
Iterator & operator--()
– operator</div>
Definition: AkMMDevice.h:303
static HashParams::HashType ComputeLowerCase(const char *in_pData)
Definition: AkFNVHash.h:130
Device(Device &&other)
Definition: AkMMDevice.h:169
DeviceProperty & operator=(DeviceProperty &&other)
Definition: AkMMDevice.h:85
DeviceProperties(DeviceProperties &&other)
Definition: AkMMDevice.h:117

Was this page helpful?

Need Support?

Questions? Problems? Need more info? Contact us, and we can help!

Visit our Support page

Tell us about your project. We're here to help.

Register your project and we'll help you get started with no strings attached!

Get started with Wwise