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