Version
menu_open
link
Wwise SDK 2022.1.12
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 #include <mmdeviceapi.h>
34 
35 namespace AK
36 {
37  namespace Win32
38  {
40  {
41  public:
42  // Default constructor
44  {
45  PropVariantInit(&variant);
46  }
47 
48  // Construct a property from an existing property store
49  DeviceProperty(const PROPERTYKEY &key, IPropertyStore* in_pProps)
50  {
51  PropVariantInit(&variant);
52  if (in_pProps) in_pProps->GetValue(key, &variant);
53  }
54 
55  // Move constructor
57  {
58  variant = other.variant;
59  PropVariantInit(&other.variant);
60  }
61 
62  // Copy construction is not allowed
63  DeviceProperty(const DeviceProperty& other) = delete;
64 
65  // Destructor
67  {
68  PropVariantClear(&variant);
69  }
70 
71  // Move assignment
73  {
74  PropVariantClear(&variant);
75  variant = other.variant;
76  PropVariantInit(&other.variant);
77  return *this;
78  }
79 
80  // Copy assignment is not allowed
81  DeviceProperty& operator=(const DeviceProperty& other) = delete;
82 
83  bool IsEmpty() const { return variant.vt == VT_EMPTY; }
84 
85  PROPVARIANT variant;
86  };
87 
89  {
90  public:
91  // Default constructor
93  : pProps(nullptr)
94  {
95  }
96 
97  // Construct properties from an IMMDevice
98  DeviceProperties(IMMDevice* in_pDevice)
99  {
100  in_pDevice->OpenPropertyStore(STGM_READ, &pProps);
101  }
102 
103  // Move constructor
105  {
106  pProps = other.pProps;
107  other.pProps = nullptr;
108  }
109 
110  // Copy construction is not allowed
111  DeviceProperties(const DeviceProperties& other) = delete;
112 
113  // Destructor
115  {
116  if (pProps)
117  {
118  pProps->Release();
119  pProps = nullptr;
120  }
121  }
122 
123  // Move assignment
125  {
126  if (pProps)
127  pProps->Release();
128  pProps = other.pProps;
129  other.pProps = nullptr;
130  return *this;
131  }
132 
133  // Copy assignment is not allowed
134  DeviceProperties& operator=(const DeviceProperties& other) = delete;
135 
136  bool IsValid() { return pProps != nullptr; }
137 
138  DeviceProperty GetProperty(const PROPERTYKEY& key)
139  {
140  return DeviceProperty(key, pProps);
141  }
142 
143  IPropertyStore* pProps;
144  };
145  class Device
146  {
147  public:
148  // Default constructor
150  : pDevice(nullptr)
152  {
153  }
154 
155  // Move constructor
156  Device(Device&& other)
157  : pDevice(nullptr)
158  {
159  SetDevice(other.pDevice);
160  other.pDevice = nullptr;
161  }
162 
163  Device(const Device& other)
164  : pDevice(nullptr)
165  {
166  *this = other;
167  }
168 
169  // Destructor
171  {
172  if (pDevice)
173  {
174  pDevice->Release();
175  pDevice = nullptr;
176  }
177  }
178 
179  // Move assignment
181  {
182  if (pDevice)
183  {
184  pDevice->Release();
185  pDevice = nullptr; // Do not remove, protects against this == &other
186  }
187  pDevice = other.pDevice;
188  idDevice = other.idDevice;
189  other.pDevice = nullptr;
190  return *this;
191  }
192 
193  Device& operator=(const Device& other)
194  {
195  if (pDevice)
196  {
197  pDevice->Release();
198  pDevice = nullptr; // Do not remove, protects against this == &other
199  }
200  pDevice = other.pDevice;
201  if (pDevice)
202  pDevice->AddRef();
203  idDevice = other.idDevice;
204  return *this;
205  }
206 
207  Device& operator=(IMMDevice* pOther)
208  {
209  SetDevice(pOther);
210  if (pDevice)
211  pDevice->AddRef();
212  return *this;
213  }
214 
215  bool IsValid() const { return pDevice != nullptr; }
216 
218  {
220  }
221 
223  {
224  return DeviceProperties(pDevice);
225  }
226 
227  void ComputeId()
228  {
230  if (pDevice)
231  {
232  //Inlined version of GetDeviceID.
233  LPWSTR pwszID = NULL;
234  if (pDevice->GetId(&pwszID) == S_OK)
235  {
236  char szString[260];
237  AKPLATFORM::AkWideCharToChar(pwszID, 260 - 1, szString);
238  szString[260 - 1] = 0;
239 
240  idDevice = FNVHash32::ComputeLowerCase((const char*)szString);
241  CoTaskMemFree(pwszID);
242  }
243  }
244  }
245 
246  void SetDevice(IMMDevice* in_pNew)
247  {
248  if (pDevice)
249  pDevice->Release();
250  pDevice = in_pNew;
251  ComputeId();
252  }
253 
254  interface IMMDevice* pDevice;
256  };
258  {
259  public:
260  class Iterator
261  {
262  public:
263  Iterator(IMMDeviceCollection* in_pDevices, UINT in_i)
264  : pDevices(in_pDevices)
265  , i(in_i)
266  {
267  }
268 
269  /// + operator</span>
271  {
272  Iterator returnedIt(pDevices, i + inc);
273  return returnedIt;
274  }
275 
276  /// - operator</span>
277  AkUInt32 operator-(Iterator const& rhs) const
278  {
279  return (AkUInt32)(i - rhs.i);
280  }
281 
282  /// ++ operator</span>
284  {
285  ++i;
286  return *this;
287  }
288 
289  /// -- operator</span>
291  {
292  --i;
293  return *this;
294  }
295 
296  /// == operator</span>
297  bool operator ==(const Iterator& in_rOp) const
298  {
299  return (pDevices == in_rOp.pDevices && i == in_rOp.i);
300  }
301 
302  /// != operator</span>
303  bool operator !=(const Iterator& in_rOp) const
304  {
305  return (pDevices != in_rOp.pDevices || i != in_rOp.i);
306  }
307 
309  {
310  Device pDevice;
311  pDevices->Item(i, (IMMDevice**)&pDevice.pDevice); //Transfer the ref
312  if (pDevice.pDevice)
313  pDevice.ComputeId();
314  return pDevice;
315  }
316 
317  interface IMMDeviceCollection* pDevices; //Keep first.
318  UINT i;
319  };
320 
321  DeviceCollection(IMMDeviceEnumerator* pEnumerator)
322  : pDevices(nullptr)
323  , uCount(0)
324  {
325  pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATEMASK_ALL, &pDevices);
326  if (pDevices)
327  pDevices->GetCount(&uCount);
328  }
329  DeviceCollection(IMMDeviceEnumerator* pEnumerator, EDataFlow eFlow, DWORD dwStateMask)
330  : pDevices(nullptr)
331  , uCount(0)
332  {
333 
334  pEnumerator->EnumAudioEndpoints(eFlow, dwStateMask, &pDevices);
335  if (pDevices)
336  pDevices->GetCount(&uCount);
337  }
338 
339  // Move constructor
341  {
342  pDevices = other.pDevices;
343  uCount = other.uCount;
344  other.pDevices = nullptr;
345  other.uCount = 0;
346  }
347 
348  // Copy construction is not allowed
349  DeviceCollection(const DeviceCollection& other) = delete;
350 
351  // Destructor
353  {
354  if (pDevices)
355  {
356  pDevices->Release();
357  pDevices = nullptr;
358  }
359  }
360 
361  // Move assignment
363  {
364  if (pDevices)
365  {
366  pDevices->Release();
367  }
368  pDevices = other.pDevices;
369  uCount = other.uCount;
370  other.pDevices = nullptr;
371  other.uCount = 0;
372  return *this;
373  }
374 
375  // Copy assignment is not allowed
376  DeviceCollection& operator=(const DeviceCollection& other) = delete;
377 
378  bool IsValid() const { return pDevices != nullptr; }
379 
380  UINT Count() const
381  {
382  return uCount;
383  }
384 
386  {
387  Iterator it(pDevices, 0);
388  return it;
389  }
391  {
392  Iterator it(pDevices, uCount);
393  return it;
394  }
395 
396  interface IMMDeviceCollection* pDevices;
397  UINT uCount;
398  };
399 
401  {
402  public:
403 
405  : pEnumerator(nullptr)
406  {
407  CoCreateInstance(
408  __uuidof(MMDeviceEnumerator), NULL,
409  CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
410  (void**)&pEnumerator);
411  }
412 
413  // Move constructor
415  {
416  pEnumerator = other.pEnumerator;
417  other.pEnumerator = nullptr;
418  }
419 
420  // Copy construction is not allowed
421  DeviceEnumerator(const DeviceEnumerator& other) = delete;
422 
423  // Destructor
425  {
426  if (pEnumerator)
427  {
428  pEnumerator->Release();
429  pEnumerator = nullptr;
430  }
431  }
432 
433  // Move assignment
435  {
436  if (pEnumerator)
437  {
438  pEnumerator->Release();
439  }
440  pEnumerator = other.pEnumerator;
441  other.pEnumerator = nullptr;
442  return *this;
443  }
444 
445  // Copy assignment is not allowed
446  DeviceEnumerator& operator=(const DeviceEnumerator& other) = delete;
447 
448  bool IsValid() { return pEnumerator != nullptr; }
449 
450  Device GetDefaultDevice(ERole in_eRole)
451  {
452  Device pDevice;
453  pEnumerator->GetDefaultAudioEndpoint(eRender, in_eRole, (IMMDevice**)&pDevice.pDevice); //Transfer the ref
454  if (pDevice.pDevice)
455  pDevice.ComputeId();
456  return pDevice;
457  }
458 
459  interface IMMDeviceEnumerator* pEnumerator;
460  };
461 
462  /// Interface to access the IMMDevice cache. This avoids driver accesses.
464  {
465  public:
466  virtual AkUInt32 Count() = 0; ///Returns the number of devices. This function can block.
467  virtual Device Item(AkUInt32 in_idx) = 0; ///Gets item in_idx from the cache. Must be smaller than Count(). This function can block.
468  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.
469  virtual void Unlock() = 0; /// For thread safety. See \ref Lock()
470  virtual Device FindDevice(AkUInt32 in_id) = 0; ///Find a device that has this unique ID. The Id is one returned by AK::GetDeviceID.
471  };
472  }
473 };
AkUInt32 idDevice
Definition: AkMMDevice.h:255
AkUInt32 GetDeviceID() const
Definition: AkMMDevice.h:217
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:49
DeviceCollection(IMMDeviceEnumerator *pEnumerator, EDataFlow eFlow, DWORD dwStateMask)
Definition: AkMMDevice.h:329
DeviceProperties(const DeviceProperties &other)=delete
DeviceEnumerator & operator=(const DeviceEnumerator &other)=delete
Iterator(IMMDeviceCollection *in_pDevices, UINT in_i)
Definition: AkMMDevice.h:263
void SetDevice(IMMDevice *in_pNew)
Definition: AkMMDevice.h:246
DeviceProperty GetProperty(const PROPERTYKEY &key)
Definition: AkMMDevice.h:138
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:193
DeviceProperties & operator=(DeviceProperties &&other)
Definition: AkMMDevice.h:124
static const AkDeviceID AK_INVALID_DEVICE_ID
Invalid streaming device ID.
Definition: AkTypes.h:171
DeviceCollection(const DeviceCollection &other)=delete
DeviceProperties GetProperties() const
Definition: AkMMDevice.h:222
interface IMMDevice * pDevice
Definition: AkMMDevice.h:254
#define NULL
Definition: AkTypes.h:46
Device(const Device &other)
Definition: AkMMDevice.h:163
DeviceCollection & operator=(DeviceCollection &&other)
Definition: AkMMDevice.h:362
DeviceCollection(DeviceCollection &&other)
Definition: AkMMDevice.h:340
DeviceProperties & operator=(const DeviceProperties &other)=delete
Interface to access the IMMDevice cache. This avoids driver accesses.
Definition: AkMMDevice.h:464
DeviceProperty(const DeviceProperty &other)=delete
Iterator operator+(AkUInt32 inc) const
Definition: AkMMDevice.h:270
DeviceEnumerator(DeviceEnumerator &&other)
Definition: AkMMDevice.h:414
interface IMMDeviceCollection * pDevices
Definition: AkMMDevice.h:317
interface IMMDeviceEnumerator * pEnumerator
Definition: AkMMDevice.h:459
Device & operator=(Device &&other)
Definition: AkMMDevice.h:180
virtual AkUInt32 Count()=0
interface IMMDeviceCollection * pDevices
Definition: AkMMDevice.h:396
bool IsValid() const
Definition: AkMMDevice.h:215
bool operator!=(const Iterator &in_rOp) const
!= operator</div>
Definition: AkMMDevice.h:303
IPropertyStore * pProps
Definition: AkMMDevice.h:143
DeviceProperty & operator=(const DeviceProperty &other)=delete
AkUInt32 operator-(Iterator const &rhs) const
Definition: AkMMDevice.h:277
DeviceEnumerator(const DeviceEnumerator &other)=delete
Iterator & operator++()
++ operator</div>
Definition: AkMMDevice.h:283
DeviceProperties(IMMDevice *in_pDevice)
Definition: AkMMDevice.h:98
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:297
DeviceProperty(DeviceProperty &&other)
Definition: AkMMDevice.h:56
DeviceCollection(IMMDeviceEnumerator *pEnumerator)
Definition: AkMMDevice.h:321
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:207
DeviceEnumerator & operator=(DeviceEnumerator &&other)
Definition: AkMMDevice.h:434
Device GetDefaultDevice(ERole in_eRole)
Definition: AkMMDevice.h:450
AkForceInline AkInt32 AkWideCharToChar(const wchar_t *in_pszUnicodeString, AkUInt32 in_uiOutBufferSize, char *io_pszAnsiString)
String conversion helper.
DeviceCollection & operator=(const DeviceCollection &other)=delete
Iterator & operator--()
– operator</div>
Definition: AkMMDevice.h:290
static HashParams::HashType ComputeLowerCase(const char *in_pData)
Definition: AkFNVHash.h:130
Device(Device &&other)
Definition: AkMMDevice.h:156
DeviceProperty & operator=(DeviceProperty &&other)
Definition: AkMMDevice.h:72
DeviceProperties(DeviceProperties &&other)
Definition: AkMMDevice.h:104

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