Wwise Version
Wwise SDK 2021.1.4
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.4 Build: 7707
25  Copyright (c) 2006-2021 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  pDevice->Release();
185  pDevice = other.pDevice;
186  idDevice = other.idDevice;
187  other.pDevice = nullptr;
188  return *this;
189  }
190 
191  Device& operator=(const Device& other)
192  {
193  if (pDevice)
194  pDevice->Release();
195  pDevice = other.pDevice;
196  if (pDevice)
197  pDevice->AddRef();
198  idDevice = other.idDevice;
199  return *this;
200  }
201 
202  Device& operator=(IMMDevice* pOther)
203  {
204  SetDevice(pOther);
205  pDevice->AddRef();
206  return *this;
207  }
208 
209  bool IsValid() const { return pDevice != nullptr; }
210 
212  {
214  }
215 
217  {
218  return DeviceProperties(pDevice);
219  }
220 
221  void ComputeId()
222  {
224  if (pDevice)
225  {
226  //Inlined version of GetDeviceID.
227  LPWSTR pwszID = NULL;
228  if (pDevice->GetId(&pwszID) == S_OK)
229  {
230  char szString[260];
231  AKPLATFORM::AkWideCharToChar(pwszID, 260 - 1, szString);
232  szString[260 - 1] = 0;
233 
234  idDevice = FNVHash32::ComputeLowerCase((const char*)szString);
235  CoTaskMemFree(pwszID);
236  }
237  }
238  }
239 
240  void SetDevice(IMMDevice* in_pNew)
241  {
242  if (pDevice)
243  pDevice->Release();
244  pDevice = in_pNew;
245  ComputeId();
246  }
247 
248  interface IMMDevice* pDevice;
250  };
252  {
253  public:
254  class Iterator
255  {
256  public:
257  Iterator(IMMDeviceCollection* in_pDevices, UINT in_i)
258  : pDevices(in_pDevices)
259  , i(in_i)
260  {
261  }
262 
263  /// + operator</span>
265  {
266  Iterator returnedIt(pDevices, i + inc);
267  return returnedIt;
268  }
269 
270  /// - operator</span>
271  AkUInt32 operator-(Iterator const& rhs) const
272  {
273  return (AkUInt32)(i - rhs.i);
274  }
275 
276  /// ++ operator</span>
278  {
279  ++i;
280  return *this;
281  }
282 
283  /// -- operator</span>
285  {
286  --i;
287  return *this;
288  }
289 
290  /// == operator</span>
291  bool operator ==(const Iterator& in_rOp) const
292  {
293  return (pDevices == in_rOp.pDevices && i == in_rOp.i);
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 
303  {
304  Device pDevice;
305  pDevices->Item(i, (IMMDevice**)&pDevice.pDevice); //Transfer the ref
306  if (pDevice.pDevice)
307  pDevice.ComputeId();
308  return pDevice;
309  }
310 
311  interface IMMDeviceCollection* pDevices; //Keep first.
312  UINT i;
313  };
314 
315  DeviceCollection(IMMDeviceEnumerator* pEnumerator)
316  : pDevices(nullptr)
317  , uCount(0)
318  {
319  pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATEMASK_ALL, &pDevices);
320  if (pDevices)
321  pDevices->GetCount(&uCount);
322  }
323  DeviceCollection(IMMDeviceEnumerator* pEnumerator, EDataFlow eFlow, DWORD dwStateMask)
324  : pDevices(nullptr)
325  , uCount(0)
326  {
327 
328  pEnumerator->EnumAudioEndpoints(eFlow, dwStateMask, &pDevices);
329  if (pDevices)
330  pDevices->GetCount(&uCount);
331  }
332 
333  // Move constructor
335  {
336  pDevices = other.pDevices;
337  uCount = other.uCount;
338  other.pDevices = nullptr;
339  other.uCount = 0;
340  }
341 
342  // Copy construction is not allowed
343  DeviceCollection(const DeviceCollection& other) = delete;
344 
345  // Destructor
347  {
348  if (pDevices)
349  {
350  pDevices->Release();
351  pDevices = nullptr;
352  }
353  }
354 
355  // Move assignment
357  {
358  if (pDevices)
359  {
360  pDevices->Release();
361  }
362  pDevices = other.pDevices;
363  uCount = other.uCount;
364  other.pDevices = nullptr;
365  other.uCount = 0;
366  return *this;
367  }
368 
369  // Copy assignment is not allowed
370  DeviceCollection& operator=(const DeviceCollection& other) = delete;
371 
372  bool IsValid() const { return pDevices != nullptr; }
373 
374  UINT Count() const
375  {
376  return uCount;
377  }
378 
380  {
381  Iterator it(pDevices, 0);
382  return it;
383  }
385  {
386  Iterator it(pDevices, uCount);
387  return it;
388  }
389 
390  interface IMMDeviceCollection* pDevices;
391  UINT uCount;
392  };
393 
395  {
396  public:
397 
399  : pEnumerator(nullptr)
400  {
401  CoCreateInstance(
402  __uuidof(MMDeviceEnumerator), NULL,
403  CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
404  (void**)&pEnumerator);
405  }
406 
407  // Move constructor
409  {
410  pEnumerator = other.pEnumerator;
411  other.pEnumerator = nullptr;
412  }
413 
414  // Copy construction is not allowed
415  DeviceEnumerator(const DeviceEnumerator& other) = delete;
416 
417  // Destructor
419  {
420  if (pEnumerator)
421  {
422  pEnumerator->Release();
423  pEnumerator = nullptr;
424  }
425  }
426 
427  // Move assignment
429  {
430  if (pEnumerator)
431  {
432  pEnumerator->Release();
433  }
434  pEnumerator = other.pEnumerator;
435  other.pEnumerator = nullptr;
436  return *this;
437  }
438 
439  // Copy assignment is not allowed
440  DeviceEnumerator& operator=(const DeviceEnumerator& other) = delete;
441 
442  bool IsValid() { return pEnumerator != nullptr; }
443 
444  Device GetDefaultDevice(ERole in_eRole)
445  {
446  Device pDevice;
447  pEnumerator->GetDefaultAudioEndpoint(eRender, in_eRole, (IMMDevice**)&pDevice.pDevice); //Transfer the ref
448  if (pDevice.pDevice)
449  pDevice.ComputeId();
450  return pDevice;
451  }
452 
453  interface IMMDeviceEnumerator* pEnumerator;
454  };
455 
456  /// Interface to access the IMMDevice cache. This avoids driver accesses.
458  {
459  public:
460  virtual AkUInt32 Count() = 0; ///Returns the number of devices. This function can block.
461  virtual Device Item(AkUInt32 in_idx) = 0; ///Gets item in_idx from the cache. Must be smaller than Count(). This function can block.
462  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.
463  virtual void Unlock() = 0; /// For thread safety. See \ref Lock()
464  virtual Device FindDevice(AkUInt32 in_id) = 0; ///Find a device that has this unique ID. The Id is one returned by AK::GetDeviceID.
465  };
466  }
467 };
AkUInt32 idDevice
Definition: AkMMDevice.h:249
AkUInt32 GetDeviceID() const
Definition: AkMMDevice.h:211
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:323
DeviceProperties(const DeviceProperties &other)=delete
DeviceEnumerator & operator=(const DeviceEnumerator &other)=delete
Iterator(IMMDeviceCollection *in_pDevices, UINT in_i)
Definition: AkMMDevice.h:257
void SetDevice(IMMDevice *in_pNew)
Definition: AkMMDevice.h:240
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:191
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:216
UINT Count() const
Definition: AkMMDevice.h:374
interface IMMDevice * pDevice
Definition: AkMMDevice.h:248
bool IsValid() const
Definition: AkMMDevice.h:372
#define NULL
Definition: AkTypes.h:47
Device(const Device &other)
Definition: AkMMDevice.h:164
DeviceCollection & operator=(DeviceCollection &&other)
Definition: AkMMDevice.h:356
DeviceCollection(DeviceCollection &&other)
Definition: AkMMDevice.h:334
void ComputeId()
Definition: AkMMDevice.h:221
DeviceProperties & operator=(const DeviceProperties &other)=delete
Interface to access the IMMDevice cache. This avoids driver accesses.
Definition: AkMMDevice.h:458
DeviceProperty(const DeviceProperty &other)=delete
Iterator operator+(AkUInt32 inc) const
Definition: AkMMDevice.h:264
DeviceEnumerator(DeviceEnumerator &&other)
Definition: AkMMDevice.h:408
interface IMMDeviceCollection * pDevices
Definition: AkMMDevice.h:311
interface IMMDeviceEnumerator * pEnumerator
Definition: AkMMDevice.h:453
Device & operator=(Device &&other)
Definition: AkMMDevice.h:181
virtual AkUInt32 Count()=0
interface IMMDeviceCollection * pDevices
Definition: AkMMDevice.h:390
bool IsValid() const
Definition: AkMMDevice.h:209
bool operator!=(const Iterator &in_rOp) const
!= operator</div>
Definition: AkMMDevice.h:297
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:271
DeviceEnumerator(const DeviceEnumerator &other)=delete
Iterator & operator++()
++ operator</div>
Definition: AkMMDevice.h:277
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:291
DeviceProperty(DeviceProperty &&other)
Definition: AkMMDevice.h:57
DeviceCollection(IMMDeviceEnumerator *pEnumerator)
Definition: AkMMDevice.h:315
uint32_t AkUInt32
Unsigned 32-bit integer.
Definition: AkTypes.h:57
virtual Device FindDevice(AkUInt32 in_id)=0
For thread safety. See Lock()
Device & operator=(IMMDevice *pOther)
Definition: AkMMDevice.h:202
DeviceEnumerator & operator=(DeviceEnumerator &&other)
Definition: AkMMDevice.h:428
Device GetDefaultDevice(ERole in_eRole)
Definition: AkMMDevice.h:444
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:284
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