|
|
@@ -91,85 +91,210 @@ bool check (HRESULT hr) |
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
namespace
|
|
|
|
}
|
|
|
|
|
|
|
|
#if JUCE_MINGW
|
|
|
|
#define JUCE_COMCLASS(name, guid) \
|
|
|
|
struct name; \
|
|
|
|
template<> struct UUIDGetter<name> { static CLSID get() { return uuidFromString (guid); } }; \
|
|
|
|
struct name
|
|
|
|
|
|
|
|
#define KSDATAFORMAT_SUBTYPE_PCM uuidFromString ("00000001-0000-0010-8000-00aa00389b71")
|
|
|
|
#define KSDATAFORMAT_SUBTYPE_IEEE_FLOAT uuidFromString ("00000003-0000-0010-8000-00aa00389b71")
|
|
|
|
|
|
|
|
struct PROPERTYKEY
|
|
|
|
{
|
|
|
|
GUID fmtid;
|
|
|
|
DWORD pid;
|
|
|
|
};
|
|
|
|
|
|
|
|
WINOLEAPI PropVariantClear (PROPVARIANT*);
|
|
|
|
#else
|
|
|
|
#define JUCE_COMCLASS(name, guid) struct __declspec (uuid (guid)) name
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define JUCE_IUNKNOWNCLASS(name, guid) JUCE_COMCLASS(name, guid) : public IUnknown
|
|
|
|
#define JUCE_COMCALL virtual HRESULT STDMETHODCALLTYPE
|
|
|
|
|
|
|
|
enum EDataFlow
|
|
|
|
{
|
|
|
|
enum EDataFlow
|
|
|
|
{
|
|
|
|
eRender = 0,
|
|
|
|
eCapture = (eRender + 1),
|
|
|
|
eAll = (eCapture + 1)
|
|
|
|
};
|
|
|
|
eRender = 0,
|
|
|
|
eCapture = (eRender + 1),
|
|
|
|
eAll = (eCapture + 1)
|
|
|
|
};
|
|
|
|
|
|
|
|
enum { DEVICE_STATE_ACTIVE = 1 };
|
|
|
|
enum { DEVICE_STATE_ACTIVE = 1 };
|
|
|
|
|
|
|
|
struct __declspec (uuid ("D666063F-1587-4E43-81F1-B948E807363F")) IMMDevice : public IUnknown
|
|
|
|
{
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE Activate(REFIID, DWORD, PROPVARIANT*, void**) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE OpenPropertyStore(DWORD, IPropertyStore**) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetId(LPWSTR*) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetState(DWORD*) = 0;
|
|
|
|
};
|
|
|
|
JUCE_IUNKNOWNCLASS (IPropertyStore, "886d8eeb-8cf2-4446-8d02-cdba1dbdcf99")
|
|
|
|
{
|
|
|
|
JUCE_COMCALL GetCount (DWORD*) = 0;
|
|
|
|
JUCE_COMCALL GetAt (DWORD, PROPERTYKEY*) = 0;
|
|
|
|
JUCE_COMCALL GetValue (const PROPERTYKEY&, PROPVARIANT*) = 0;
|
|
|
|
JUCE_COMCALL SetValue (const PROPERTYKEY&, const PROPVARIANT&) = 0;
|
|
|
|
JUCE_COMCALL Commit() = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct __declspec (uuid ("1BE09788-6894-4089-8586-9A2A6C265AC5")) IMMEndpoint : public IUnknown
|
|
|
|
{
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetDataFlow(EDataFlow*) = 0;
|
|
|
|
};
|
|
|
|
JUCE_IUNKNOWNCLASS (IMMDevice, "D666063F-1587-4E43-81F1-B948E807363F")
|
|
|
|
{
|
|
|
|
JUCE_COMCALL Activate (REFIID, DWORD, PROPVARIANT*, void**) = 0;
|
|
|
|
JUCE_COMCALL OpenPropertyStore (DWORD, IPropertyStore**) = 0;
|
|
|
|
JUCE_COMCALL GetId (LPWSTR*) = 0;
|
|
|
|
JUCE_COMCALL GetState (DWORD*) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct IMMDeviceCollection : public IUnknown
|
|
|
|
{
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetCount(UINT*) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE Item(UINT, IMMDevice**) = 0;
|
|
|
|
};
|
|
|
|
JUCE_IUNKNOWNCLASS (IMMEndpoint, "1BE09788-6894-4089-8586-9A2A6C265AC5")
|
|
|
|
{
|
|
|
|
JUCE_COMCALL GetDataFlow (EDataFlow*) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum ERole
|
|
|
|
{
|
|
|
|
eConsole = 0,
|
|
|
|
eMultimedia = (eConsole + 1),
|
|
|
|
eCommunications = (eMultimedia + 1)
|
|
|
|
};
|
|
|
|
struct IMMDeviceCollection : public IUnknown
|
|
|
|
{
|
|
|
|
JUCE_COMCALL GetCount (UINT*) = 0;
|
|
|
|
JUCE_COMCALL Item (UINT, IMMDevice**) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct __declspec (uuid ("7991EEC9-7E89-4D85-8390-6C703CEC60C0")) IMMNotificationClient : public IUnknown
|
|
|
|
{
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR, DWORD) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow, ERole, LPCWSTR) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY) = 0;
|
|
|
|
};
|
|
|
|
enum ERole
|
|
|
|
{
|
|
|
|
eConsole = 0,
|
|
|
|
eMultimedia = (eConsole + 1),
|
|
|
|
eCommunications = (eMultimedia + 1)
|
|
|
|
};
|
|
|
|
|
|
|
|
struct __declspec (uuid ("A95664D2-9614-4F35-A746-DE8DB63617E6")) IMMDeviceEnumerator : public IUnknown
|
|
|
|
{
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE EnumAudioEndpoints(EDataFlow, DWORD, IMMDeviceCollection**) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetDefaultAudioEndpoint(EDataFlow, ERole, IMMDevice**) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetDevice(LPCWSTR, IMMDevice**) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE RegisterEndpointNotificationCallback(IMMNotificationClient*) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE UnregisterEndpointNotificationCallback(IMMNotificationClient*) = 0;
|
|
|
|
};
|
|
|
|
JUCE_IUNKNOWNCLASS (IMMNotificationClient, "7991EEC9-7E89-4D85-8390-6C703CEC60C0")
|
|
|
|
{
|
|
|
|
JUCE_COMCALL OnDeviceStateChanged (LPCWSTR, DWORD) = 0;
|
|
|
|
JUCE_COMCALL OnDeviceAdded (LPCWSTR) = 0;
|
|
|
|
JUCE_COMCALL OnDeviceRemoved (LPCWSTR) = 0;
|
|
|
|
JUCE_COMCALL OnDefaultDeviceChanged (EDataFlow, ERole, LPCWSTR) = 0;
|
|
|
|
JUCE_COMCALL OnPropertyValueChanged (LPCWSTR, const PROPERTYKEY) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct __declspec (uuid ("BCDE0395-E52F-467C-8E3D-C4579291692E")) MMDeviceEnumerator;
|
|
|
|
JUCE_IUNKNOWNCLASS (IMMDeviceEnumerator, "A95664D2-9614-4F35-A746-DE8DB63617E6")
|
|
|
|
{
|
|
|
|
JUCE_COMCALL EnumAudioEndpoints (EDataFlow, DWORD, IMMDeviceCollection**) = 0;
|
|
|
|
JUCE_COMCALL GetDefaultAudioEndpoint (EDataFlow, ERole, IMMDevice**) = 0;
|
|
|
|
JUCE_COMCALL GetDevice (LPCWSTR, IMMDevice**) = 0;
|
|
|
|
JUCE_COMCALL RegisterEndpointNotificationCallback (IMMNotificationClient*) = 0;
|
|
|
|
JUCE_COMCALL UnregisterEndpointNotificationCallback (IMMNotificationClient*) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct __declspec (uuid ("5CDF2C82-841E-4546-9722-0CF74078229A")) IAudioEndpointVolume : public IUnknown
|
|
|
|
{
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE RegisterControlChangeNotify (void*) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE UnregisterControlChangeNotify (void*) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetChannelCount (UINT*) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE SetMasterVolumeLevel (float, LPCGUID) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE SetMasterVolumeLevelScalar (float, LPCGUID) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetMasterVolumeLevel (float*) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetMasterVolumeLevelScalar (float*) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE SetChannelVolumeLevel (UINT, float, LPCGUID) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE SetChannelVolumeLevelScalar (UINT, float, LPCGUID) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetChannelVolumeLevel (UINT, float*) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetChannelVolumeLevelScalar (UINT, float*) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE SetMute (BOOL, LPCGUID) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetMute (BOOL*) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetVolumeStepInfo (UINT*, UINT*) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE VolumeStepUp (LPCGUID) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE VolumeStepDown (LPCGUID) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE QueryHardwareSupport (DWORD*) = 0;
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE GetVolumeRange (float*, float*, float*) = 0;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
JUCE_COMCLASS (MMDeviceEnumerator, "BCDE0395-E52F-467C-8E3D-C4579291692E");
|
|
|
|
|
|
|
|
typedef LONGLONG REFERENCE_TIME;
|
|
|
|
|
|
|
|
enum AVRT_PRIORITY
|
|
|
|
{
|
|
|
|
AVRT_PRIORITY_LOW = -1,
|
|
|
|
AVRT_PRIORITY_NORMAL,
|
|
|
|
AVRT_PRIORITY_HIGH,
|
|
|
|
AVRT_PRIORITY_CRITICAL
|
|
|
|
};
|
|
|
|
|
|
|
|
enum AUDCLNT_SHAREMODE
|
|
|
|
{
|
|
|
|
AUDCLNT_SHAREMODE_SHARED,
|
|
|
|
AUDCLNT_SHAREMODE_EXCLUSIVE
|
|
|
|
};
|
|
|
|
|
|
|
|
JUCE_IUNKNOWNCLASS (IAudioClient, "1CB9AD4C-DBFA-4c32-B178-C2F568A703B2")
|
|
|
|
{
|
|
|
|
JUCE_COMCALL Initialize (AUDCLNT_SHAREMODE, DWORD, REFERENCE_TIME, REFERENCE_TIME, const WAVEFORMATEX*, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL GetBufferSize (UINT32*) = 0;
|
|
|
|
JUCE_COMCALL GetStreamLatency (REFERENCE_TIME*) = 0;
|
|
|
|
JUCE_COMCALL GetCurrentPadding (UINT32*) = 0;
|
|
|
|
JUCE_COMCALL IsFormatSupported (AUDCLNT_SHAREMODE, const WAVEFORMATEX*, WAVEFORMATEX**) = 0;
|
|
|
|
JUCE_COMCALL GetMixFormat (WAVEFORMATEX**) = 0;
|
|
|
|
JUCE_COMCALL GetDevicePeriod (REFERENCE_TIME*, REFERENCE_TIME*) = 0;
|
|
|
|
JUCE_COMCALL Start() = 0;
|
|
|
|
JUCE_COMCALL Stop() = 0;
|
|
|
|
JUCE_COMCALL Reset() = 0;
|
|
|
|
JUCE_COMCALL SetEventHandle (HANDLE) = 0;
|
|
|
|
JUCE_COMCALL GetService (REFIID, void**) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
JUCE_IUNKNOWNCLASS (IAudioCaptureClient, "C8ADBD64-E71E-48a0-A4DE-185C395CD317")
|
|
|
|
{
|
|
|
|
JUCE_COMCALL GetBuffer (BYTE**, UINT32*, DWORD*, UINT64*, UINT64*) = 0;
|
|
|
|
JUCE_COMCALL ReleaseBuffer (UINT32) = 0;
|
|
|
|
JUCE_COMCALL GetNextPacketSize (UINT32*) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
JUCE_IUNKNOWNCLASS (IAudioRenderClient, "F294ACFC-3146-4483-A7BF-ADDCA7C260E2")
|
|
|
|
{
|
|
|
|
JUCE_COMCALL GetBuffer (UINT32, BYTE**) = 0;
|
|
|
|
JUCE_COMCALL ReleaseBuffer (UINT32, DWORD) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
JUCE_IUNKNOWNCLASS (IAudioEndpointVolume, "5CDF2C82-841E-4546-9722-0CF74078229A")
|
|
|
|
{
|
|
|
|
JUCE_COMCALL RegisterControlChangeNotify (void*) = 0;
|
|
|
|
JUCE_COMCALL UnregisterControlChangeNotify (void*) = 0;
|
|
|
|
JUCE_COMCALL GetChannelCount (UINT*) = 0;
|
|
|
|
JUCE_COMCALL SetMasterVolumeLevel (float, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL SetMasterVolumeLevelScalar (float, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL GetMasterVolumeLevel (float*) = 0;
|
|
|
|
JUCE_COMCALL GetMasterVolumeLevelScalar (float*) = 0;
|
|
|
|
JUCE_COMCALL SetChannelVolumeLevel (UINT, float, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL SetChannelVolumeLevelScalar (UINT, float, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL GetChannelVolumeLevel (UINT, float*) = 0;
|
|
|
|
JUCE_COMCALL GetChannelVolumeLevelScalar (UINT, float*) = 0;
|
|
|
|
JUCE_COMCALL SetMute (BOOL, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL GetMute (BOOL*) = 0;
|
|
|
|
JUCE_COMCALL GetVolumeStepInfo (UINT*, UINT*) = 0;
|
|
|
|
JUCE_COMCALL VolumeStepUp (LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL VolumeStepDown (LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL QueryHardwareSupport (DWORD*) = 0;
|
|
|
|
JUCE_COMCALL GetVolumeRange (float*, float*, float*) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum AudioSessionDisconnectReason
|
|
|
|
{
|
|
|
|
DisconnectReasonDeviceRemoval = 0,
|
|
|
|
DisconnectReasonServerShutdown = 1,
|
|
|
|
DisconnectReasonFormatChanged = 2,
|
|
|
|
DisconnectReasonSessionLogoff = 3,
|
|
|
|
DisconnectReasonSessionDisconnected = 4,
|
|
|
|
DisconnectReasonExclusiveModeOverride = 5
|
|
|
|
};
|
|
|
|
|
|
|
|
enum AudioSessionState
|
|
|
|
{
|
|
|
|
AudioSessionStateInactive = 0,
|
|
|
|
AudioSessionStateActive = 1,
|
|
|
|
AudioSessionStateExpired = 2
|
|
|
|
};
|
|
|
|
|
|
|
|
JUCE_IUNKNOWNCLASS (IAudioSessionEvents, "24918ACC-64B3-37C1-8CA9-74A66E9957A8")
|
|
|
|
{
|
|
|
|
JUCE_COMCALL OnDisplayNameChanged (LPCWSTR, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL OnIconPathChanged (LPCWSTR, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL OnSimpleVolumeChanged (float, BOOL, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL OnChannelVolumeChanged (DWORD, float*, DWORD, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL OnGroupingParamChanged (LPCGUID, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL OnStateChanged (AudioSessionState) = 0;
|
|
|
|
JUCE_COMCALL OnSessionDisconnected (AudioSessionDisconnectReason) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
JUCE_IUNKNOWNCLASS (IAudioSessionControl, "F4B1A599-7266-4319-A8CA-E70ACB11E8CD")
|
|
|
|
{
|
|
|
|
JUCE_COMCALL GetState (AudioSessionState*) = 0;
|
|
|
|
JUCE_COMCALL GetDisplayName (LPWSTR*) = 0;
|
|
|
|
JUCE_COMCALL SetDisplayName (LPCWSTR, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL GetIconPath (LPWSTR*) = 0;
|
|
|
|
JUCE_COMCALL SetIconPath (LPCWSTR, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL GetGroupingParam (GUID*) = 0;
|
|
|
|
JUCE_COMCALL SetGroupingParam (LPCGUID, LPCGUID) = 0;
|
|
|
|
JUCE_COMCALL RegisterAudioSessionNotification (IAudioSessionEvents*) = 0;
|
|
|
|
JUCE_COMCALL UnregisterAudioSessionNotification (IAudioSessionEvents*) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
#undef JUCE_COMCALL
|
|
|
|
#undef JUCE_COMCLASS
|
|
|
|
#undef JUCE_IUNKNOWNCLASS
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
namespace WasapiClasses
|
|
|
|
{
|
|
|
|
|
|
|
|
String getDeviceID (IMMDevice* const device)
|
|
|
|
{
|
|
|
@@ -263,7 +388,7 @@ public: |
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~WASAPIDeviceBase()
|
|
|
|
virtual ~WASAPIDeviceBase()
|
|
|
|
{
|
|
|
|
device = nullptr;
|
|
|
|
CloseHandle (clientEvent);
|
|
|
@@ -345,7 +470,7 @@ private: |
|
|
|
class SessionEventCallback : public ComBaseClassHelper <IAudioSessionEvents>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SessionEventCallback (WASAPIDeviceBase& owner_) : owner (owner_) {}
|
|
|
|
SessionEventCallback (WASAPIDeviceBase& d) : owner (d) {}
|
|
|
|
|
|
|
|
JUCE_COMRESULT OnDisplayNameChanged (LPCWSTR, LPCGUID) { return S_OK; }
|
|
|
|
JUCE_COMRESULT OnIconPathChanged (LPCWSTR, LPCGUID) { return S_OK; }
|
|
|
@@ -411,7 +536,8 @@ private: |
|
|
|
|
|
|
|
bool tryInitialisingWithFormat (const bool useFloat, const int bytesPerSampleToTry)
|
|
|
|
{
|
|
|
|
WAVEFORMATEXTENSIBLE format = { 0 };
|
|
|
|
WAVEFORMATEXTENSIBLE format;
|
|
|
|
zerostruct (format);
|
|
|
|
|
|
|
|
if (numChannels <= 2 && bytesPerSampleToTry <= 2)
|
|
|
|
{
|
|
|
@@ -462,7 +588,7 @@ private: |
|
|
|
GUID session;
|
|
|
|
if (hr == S_OK
|
|
|
|
&& check (client->Initialize (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
|
|
|
|
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
|
|
|
|
0x40000 /*AUDCLNT_STREAMFLAGS_EVENTCALLBACK*/,
|
|
|
|
defaultPeriod, defaultPeriod, (WAVEFORMATEX*) &format, &session)))
|
|
|
|
{
|
|
|
|
actualNumChannels = format.Format.nChannels;
|
|
|
@@ -1264,7 +1390,11 @@ private: |
|
|
|
continue;
|
|
|
|
|
|
|
|
PROPVARIANT value;
|
|
|
|
PropVariantInit (&value);
|
|
|
|
zerostruct (value);
|
|
|
|
|
|
|
|
const PROPERTYKEY PKEY_Device_FriendlyName
|
|
|
|
= { { 0xa45c254e, 0xdf1c, 0x4efd, { 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0 } }, 14 };
|
|
|
|
|
|
|
|
if (check (properties->GetValue (PKEY_Device_FriendlyName, &value)))
|
|
|
|
name = value.pwszVal;
|
|
|
|
|
|
|
|