123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- /*******************************************************************************
- The content of this file includes portions of the AUDIOKINETIC Wwise Technology
- released in source code form as part of the SDK installer package.
- Commercial License Usage
- Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
- may use this file in accordance with the end user license agreement provided
- with the software or, alternatively, in accordance with the terms contained in a
- written agreement between you and Audiokinetic Inc.
- Apache License Usage
- Alternatively, this file may be used under the Apache License, Version 2.0 (the
- "Apache License"); you may not use this file except in compliance with the
- Apache License. You may obtain a copy of the Apache License at
- http://www.apache.org/licenses/LICENSE-2.0.
- Unless required by applicable law or agreed to in writing, software distributed
- under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
- OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
- the specific language governing permissions and limitations under the License.
- Copyright (c) 2023 Audiokinetic Inc.
- *******************************************************************************/
- // AkMMDevice.h -- C++ RIAA object wrappers for Win32 MMDevice enumeration APIs
- #pragma once
- #include <AK/SoundEngine/Common/AkSoundEngine.h>
- #include <AK/Tools/Common/AkPlatformFuncs.h>
- // Fix for Windows SDK 10.0.17763.0
- #if !defined(_DEBUG)
- namespace Microsoft {
- namespace WRL {
- namespace Details {
- template <typename T>
- inline void CheckForDuplicateEntries() {}
- }
- }
- }
- #endif
- #include <mmdeviceapi.h>
- namespace AK
- {
- namespace Win32
- {
- class DeviceProperty
- {
- public:
- // Default constructor
- DeviceProperty()
- {
- PropVariantInit(&variant);
- }
- // Construct a property from an existing property store
- DeviceProperty(const PROPERTYKEY &key, IPropertyStore* in_pProps)
- {
- PropVariantInit(&variant);
- if (in_pProps) in_pProps->GetValue(key, &variant);
- }
- // Move constructor
- DeviceProperty(DeviceProperty&& other)
- {
- variant = other.variant;
- PropVariantInit(&other.variant);
- }
- // Copy construction is not allowed
- DeviceProperty(const DeviceProperty& other) = delete;
- // Destructor
- ~DeviceProperty()
- {
- PropVariantClear(&variant);
- }
- // Move assignment
- DeviceProperty& operator=(DeviceProperty&& other)
- {
- PropVariantClear(&variant);
- variant = other.variant;
- PropVariantInit(&other.variant);
- return *this;
- }
- // Copy assignment is not allowed
- DeviceProperty& operator=(const DeviceProperty& other) = delete;
- bool IsEmpty() const { return variant.vt == VT_EMPTY; }
- PROPVARIANT variant;
- };
- class DeviceProperties
- {
- public:
- // Default constructor
- DeviceProperties()
- : pProps(nullptr)
- {
- }
- // Construct properties from an IMMDevice
- DeviceProperties(IMMDevice* in_pDevice)
- {
- in_pDevice->OpenPropertyStore(STGM_READ, &pProps);
- }
- // Move constructor
- DeviceProperties(DeviceProperties&& other)
- {
- pProps = other.pProps;
- other.pProps = nullptr;
- }
- // Copy construction is not allowed
- DeviceProperties(const DeviceProperties& other) = delete;
- // Destructor
- ~DeviceProperties()
- {
- if (pProps)
- {
- pProps->Release();
- pProps = nullptr;
- }
- }
- // Move assignment
- DeviceProperties& operator=(DeviceProperties&& other)
- {
- if (pProps)
- pProps->Release();
- pProps = other.pProps;
- other.pProps = nullptr;
- return *this;
- }
- // Copy assignment is not allowed
- DeviceProperties& operator=(const DeviceProperties& other) = delete;
- bool IsValid() { return pProps != nullptr; }
- DeviceProperty GetProperty(const PROPERTYKEY& key)
- {
- return DeviceProperty(key, pProps);
- }
- IPropertyStore* pProps;
- };
- class Device
- {
- public:
- // Default constructor
- Device()
- : pDevice(nullptr)
- , idDevice(AK_INVALID_DEVICE_ID)
- {
- }
- // Move constructor
- Device(Device&& other)
- : pDevice(nullptr)
- {
- SetDevice(other.pDevice);
- other.pDevice = nullptr;
- }
-
- Device(const Device& other)
- : pDevice(nullptr)
- {
- *this = other;
- }
- // Destructor
- ~Device()
- {
- if (pDevice)
- {
- pDevice->Release();
- pDevice = nullptr;
- }
- }
- // Move assignment
- Device& operator=(Device&& other)
- {
- if (pDevice)
- {
- pDevice->Release();
- pDevice = nullptr; // Do not remove, protects against this == &other
- }
- pDevice = other.pDevice;
- idDevice = other.idDevice;
- other.pDevice = nullptr;
- return *this;
- }
-
- Device& operator=(const Device& other)
- {
- if (pDevice)
- {
- pDevice->Release();
- pDevice = nullptr; // Do not remove, protects against this == &other
- }
- pDevice = other.pDevice;
- if (pDevice)
- pDevice->AddRef();
- idDevice = other.idDevice;
- return *this;
- }
- Device& operator=(IMMDevice* pOther)
- {
- SetDevice(pOther);
- if (pDevice)
- pDevice->AddRef();
- return *this;
- }
- bool IsValid() const { return pDevice != nullptr; }
- AkUInt32 GetDeviceID() const
- {
- return pDevice ? idDevice : AK_INVALID_DEVICE_ID;
- }
- DeviceProperties GetProperties() const
- {
- return DeviceProperties(pDevice);
- }
- void ComputeId()
- {
- idDevice = AK_INVALID_DEVICE_ID;
- if (pDevice)
- {
- //Inlined version of GetDeviceID.
- LPWSTR pwszID = NULL;
- if (pDevice->GetId(&pwszID) == S_OK)
- {
- char szString[260];
- AKPLATFORM::AkWideCharToChar(pwszID, 260 - 1, szString);
- szString[260 - 1] = 0;
- idDevice = FNVHash32::ComputeLowerCase((const char*)szString);
- CoTaskMemFree(pwszID);
- }
- }
- }
- void SetDevice(IMMDevice* in_pNew)
- {
- if (pDevice)
- pDevice->Release();
- pDevice = in_pNew;
- ComputeId();
- }
- interface IMMDevice* pDevice;
- AkUInt32 idDevice;
- };
- class DeviceCollection
- {
- public:
- class Iterator
- {
- public:
- Iterator(IMMDeviceCollection* in_pDevices, UINT in_i)
- : pDevices(in_pDevices)
- , i(in_i)
- {
- }
- /// + operator
- Iterator operator+(AkUInt32 inc) const
- {
- Iterator returnedIt(pDevices, i + inc);
- return returnedIt;
- }
- /// - operator
- AkUInt32 operator-(Iterator const& rhs) const
- {
- return (AkUInt32)(i - rhs.i);
- }
- /// ++ operator
- Iterator& operator++()
- {
- ++i;
- return *this;
- }
- /// -- operator
- Iterator& operator--()
- {
- --i;
- return *this;
- }
- /// == operator
- bool operator ==(const Iterator& in_rOp) const
- {
- return (pDevices == in_rOp.pDevices && i == in_rOp.i);
- }
- /// != operator
- bool operator !=(const Iterator& in_rOp) const
- {
- return (pDevices != in_rOp.pDevices || i != in_rOp.i);
- }
-
- Device GetDevice()
- {
- Device pDevice;
- pDevices->Item(i, (IMMDevice**)&pDevice.pDevice); //Transfer the ref
- if (pDevice.pDevice)
- pDevice.ComputeId();
- return pDevice;
- }
- interface IMMDeviceCollection* pDevices; //Keep first.
- UINT i;
- };
- DeviceCollection(IMMDeviceEnumerator* pEnumerator)
- : pDevices(nullptr)
- , uCount(0)
- {
- pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATEMASK_ALL, &pDevices);
- if (pDevices)
- pDevices->GetCount(&uCount);
- }
- DeviceCollection(IMMDeviceEnumerator* pEnumerator, EDataFlow eFlow, DWORD dwStateMask)
- : pDevices(nullptr)
- , uCount(0)
- {
- pEnumerator->EnumAudioEndpoints(eFlow, dwStateMask, &pDevices);
- if (pDevices)
- pDevices->GetCount(&uCount);
- }
- // Move constructor
- DeviceCollection(DeviceCollection&& other)
- {
- pDevices = other.pDevices;
- uCount = other.uCount;
- other.pDevices = nullptr;
- other.uCount = 0;
- }
- // Copy construction is not allowed
- DeviceCollection(const DeviceCollection& other) = delete;
- // Destructor
- ~DeviceCollection()
- {
- if (pDevices)
- {
- pDevices->Release();
- pDevices = nullptr;
- }
- }
- // Move assignment
- DeviceCollection& operator=(DeviceCollection&& other)
- {
- if (pDevices)
- {
- pDevices->Release();
- }
- pDevices = other.pDevices;
- uCount = other.uCount;
- other.pDevices = nullptr;
- other.uCount = 0;
- return *this;
- }
- // Copy assignment is not allowed
- DeviceCollection& operator=(const DeviceCollection& other) = delete;
- bool IsValid() const { return pDevices != nullptr; }
- UINT Count() const
- {
- return uCount;
- }
- Iterator Begin()
- {
- Iterator it(pDevices, 0);
- return it;
- }
- Iterator End()
- {
- Iterator it(pDevices, uCount);
- return it;
- }
- interface IMMDeviceCollection* pDevices;
- UINT uCount;
- };
- class DeviceEnumerator
- {
- public:
- DeviceEnumerator()
- : pEnumerator(nullptr)
- {
- CoCreateInstance(
- __uuidof(MMDeviceEnumerator), NULL,
- CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
- (void**)&pEnumerator);
- }
- // Move constructor
- DeviceEnumerator(DeviceEnumerator&& other)
- {
- pEnumerator = other.pEnumerator;
- other.pEnumerator = nullptr;
- }
- // Copy construction is not allowed
- DeviceEnumerator(const DeviceEnumerator& other) = delete;
- // Destructor
- ~DeviceEnumerator()
- {
- if (pEnumerator)
- {
- pEnumerator->Release();
- pEnumerator = nullptr;
- }
- }
- // Move assignment
- DeviceEnumerator& operator=(DeviceEnumerator&& other)
- {
- if (pEnumerator)
- {
- pEnumerator->Release();
- }
- pEnumerator = other.pEnumerator;
- other.pEnumerator = nullptr;
- return *this;
- }
- // Copy assignment is not allowed
- DeviceEnumerator& operator=(const DeviceEnumerator& other) = delete;
- bool IsValid() { return pEnumerator != nullptr; }
- Device GetDefaultDevice(ERole in_eRole)
- {
- Device pDevice;
- pEnumerator->GetDefaultAudioEndpoint(eRender, in_eRole, (IMMDevice**)&pDevice.pDevice); //Transfer the ref
- if (pDevice.pDevice)
- pDevice.ComputeId();
- return pDevice;
- }
- interface IMMDeviceEnumerator* pEnumerator;
- };
- /// Interface to access the IMMDevice cache. This avoids driver accesses.
- class IAkDeviceEnumerator
- {
- public:
- virtual AkUInt32 Count() = 0; ///Returns the number of devices. This function can block.
- virtual Device Item(AkUInt32 in_idx) = 0; ///Gets item in_idx from the cache. Must be smaller than Count(). This function can block.
- 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.
- virtual void Unlock() = 0; /// For thread safety. See \ref Lock()
- virtual Device FindDevice(AkUInt32 in_id) = 0; ///Find a device that has this unique ID. The Id is one returned by AK::GetDeviceID.
- };
- }
- };
|