1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

WASAPI: Only send change broadcast when devices are updated

This commit is contained in:
reuk 2023-01-16 14:03:04 +00:00
parent 238fbfca94
commit 49a954d473
No known key found for this signature in database
GPG key ID: 9ADCD339CFC98A11
4 changed files with 71 additions and 78 deletions

View file

@ -1035,8 +1035,14 @@ public:
};
//==============================================================================
struct DSoundDeviceList
class DSoundDeviceList
{
auto tie() const
{
return std::tie (outputDeviceNames, inputDeviceNames, outputGuids, inputGuids);
}
public:
StringArray outputDeviceNames, inputDeviceNames;
Array<GUID> outputGuids, inputGuids;
@ -1054,13 +1060,8 @@ struct DSoundDeviceList
}
}
bool operator!= (const DSoundDeviceList& other) const noexcept
{
return outputDeviceNames != other.outputDeviceNames
|| inputDeviceNames != other.inputDeviceNames
|| outputGuids != other.outputGuids
|| inputGuids != other.inputGuids;
}
bool operator== (const DSoundDeviceList& other) const noexcept { return tie() == other.tie(); }
bool operator!= (const DSoundDeviceList& other) const noexcept { return tie() != other.tie(); }
private:
static BOOL enumProc (LPGUID lpGUID, String desc, StringArray& names, Array<GUID>& guids)
@ -1213,13 +1214,11 @@ String DSoundAudioIODevice::openDevice (const BigInteger& inputChannels,
}
//==============================================================================
class DSoundAudioIODeviceType : public AudioIODeviceType,
private DeviceChangeDetector
class DSoundAudioIODeviceType : public AudioIODeviceType
{
public:
DSoundAudioIODeviceType()
: AudioIODeviceType ("DirectSound"),
DeviceChangeDetector (L"DirectSound")
: AudioIODeviceType ("DirectSound")
{
initialiseDSoundFunctions();
}
@ -1274,19 +1273,17 @@ public:
}
private:
DeviceChangeDetector detector { L"DirectSound", [this] { systemDeviceChanged(); } };
DSoundDeviceList deviceList;
bool hasScanned = false;
void systemDeviceChanged() override
void systemDeviceChanged()
{
DSoundDeviceList newList;
newList.scan();
if (newList != deviceList)
{
deviceList = newList;
if (std::exchange (deviceList, newList) != newList)
callDeviceChangeListeners();
}
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DSoundAudioIODeviceType)

View file

@ -1694,13 +1694,11 @@ private:
//==============================================================================
class WASAPIAudioIODeviceType : public AudioIODeviceType,
private DeviceChangeDetector
class WASAPIAudioIODeviceType : public AudioIODeviceType
{
public:
WASAPIAudioIODeviceType (WASAPIDeviceMode mode)
explicit WASAPIAudioIODeviceType (WASAPIDeviceMode mode)
: AudioIODeviceType (getDeviceTypename (mode)),
DeviceChangeDetector (L"Windows Audio"),
deviceMode (mode)
{
}
@ -1715,22 +1713,15 @@ public:
void scanForDevices() override
{
hasScanned = true;
outputDeviceNames.clear();
inputDeviceNames.clear();
outputDeviceIds.clear();
inputDeviceIds.clear();
scan (outputDeviceNames, inputDeviceNames,
outputDeviceIds, inputDeviceIds);
devices = scan();
}
StringArray getDeviceNames (bool wantInputNames) const override
{
jassert (hasScanned); // need to call scanForDevices() before doing this
return wantInputNames ? inputDeviceNames
: outputDeviceNames;
return wantInputNames ? devices.inputDeviceNames
: devices.outputDeviceNames;
}
int getDefaultDeviceIndex (bool /*forInput*/) const override
@ -1744,8 +1735,8 @@ public:
jassert (hasScanned); // need to call scanForDevices() before doing this
if (auto d = dynamic_cast<WASAPIAudioIODevice*> (device))
return asInput ? inputDeviceIds.indexOf (d->inputDeviceId)
: outputDeviceIds.indexOf (d->outputDeviceId);
return asInput ? devices.inputDeviceIds .indexOf (d->inputDeviceId)
: devices.outputDeviceIds.indexOf (d->outputDeviceId);
return -1;
}
@ -1759,16 +1750,16 @@ public:
std::unique_ptr<WASAPIAudioIODevice> device;
auto outputIndex = outputDeviceNames.indexOf (outputDeviceName);
auto inputIndex = inputDeviceNames.indexOf (inputDeviceName);
auto outputIndex = devices.outputDeviceNames.indexOf (outputDeviceName);
auto inputIndex = devices.inputDeviceNames .indexOf (inputDeviceName);
if (outputIndex >= 0 || inputIndex >= 0)
{
device.reset (new WASAPIAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
: inputDeviceName,
getTypeName(),
outputDeviceIds [outputIndex],
inputDeviceIds [inputIndex],
devices.outputDeviceIds[outputIndex],
devices.inputDeviceIds [inputIndex],
deviceMode));
if (! device->initialise())
@ -1779,10 +1770,24 @@ public:
}
//==============================================================================
StringArray outputDeviceNames, outputDeviceIds;
StringArray inputDeviceNames, inputDeviceIds;
struct Devices
{
StringArray outputDeviceNames, outputDeviceIds;
StringArray inputDeviceNames, inputDeviceIds;
auto tie() const
{
return std::tie (outputDeviceNames, outputDeviceIds, inputDeviceNames, inputDeviceIds);
}
bool operator== (const Devices& other) const { return tie() == other.tie(); }
bool operator!= (const Devices& other) const { return tie() != other.tie(); }
};
Devices devices;
private:
DeviceChangeDetector deviceChangeDetector { L"Windows Audio", [this] { systemDeviceChanged(); } };
WASAPIDeviceMode deviceMode;
bool hasScanned = false;
ComSmartPtr<IMMDeviceEnumerator> enumerator;
@ -1791,7 +1796,7 @@ private:
class ChangeNotificationClient : public ComBaseClassHelper<IMMNotificationClient>
{
public:
ChangeNotificationClient (WASAPIAudioIODeviceType* d)
explicit ChangeNotificationClient (WASAPIAudioIODeviceType* d)
: ComBaseClassHelper (0), device (d) {}
JUCE_COMRESULT OnDeviceAdded (LPCWSTR) { return notify(); }
@ -1806,7 +1811,7 @@ private:
HRESULT notify()
{
if (device != nullptr)
device->triggerAsyncDeviceChangeCallback();
device->deviceChangeDetector.triggerAsyncDeviceChangeCallback();
return S_OK;
}
@ -1840,15 +1845,12 @@ private:
}
//==============================================================================
void scan (StringArray& outDeviceNames,
StringArray& inDeviceNames,
StringArray& outDeviceIds,
StringArray& inDeviceIds)
Devices scan()
{
if (enumerator == nullptr)
{
if (! check (enumerator.CoCreateInstance (__uuidof (MMDeviceEnumerator))))
return;
return {};
notifyClient = new ChangeNotificationClient (this);
enumerator->RegisterEndpointNotificationCallback (notifyClient);
@ -1862,7 +1864,9 @@ private:
if (! (check (enumerator->EnumAudioEndpoints (eAll, DEVICE_STATE_ACTIVE, deviceCollection.resetAndGetPointerAddress()))
&& check (deviceCollection->GetCount (&numDevices))))
return;
return {};
Devices result;
for (UINT32 i = 0; i < numDevices; ++i)
{
@ -1902,40 +1906,33 @@ private:
if (flow == eRender)
{
const int index = (deviceId == defaultRenderer) ? 0 : -1;
outDeviceIds.insert (index, deviceId);
outDeviceNames.insert (index, name);
result.outputDeviceIds.insert (index, deviceId);
result.outputDeviceNames.insert (index, name);
}
else if (flow == eCapture)
{
const int index = (deviceId == defaultCapture) ? 0 : -1;
inDeviceIds.insert (index, deviceId);
inDeviceNames.insert (index, name);
result.inputDeviceIds.insert (index, deviceId);
result.inputDeviceNames.insert (index, name);
}
}
inDeviceNames.appendNumbersToDuplicates (false, false);
outDeviceNames.appendNumbersToDuplicates (false, false);
result.inputDeviceNames .appendNumbersToDuplicates (false, false);
result.outputDeviceNames.appendNumbersToDuplicates (false, false);
return result;
}
//==============================================================================
void systemDeviceChanged() override
void systemDeviceChanged()
{
StringArray newOutNames, newInNames, newOutIds, newInIds;
scan (newOutNames, newInNames, newOutIds, newInIds);
const auto newDevices = scan();
if (newOutNames != outputDeviceNames
|| newInNames != inputDeviceNames
|| newOutIds != outputDeviceIds
|| newInIds != inputDeviceIds)
if (std::exchange (devices, newDevices) != newDevices)
{
hasScanned = true;
outputDeviceNames = newOutNames;
inputDeviceNames = newInNames;
outputDeviceIds = newOutIds;
inputDeviceIds = newInIds;
callDeviceChangeListeners();
}
callDeviceChangeListeners();
}
//==============================================================================

View file

@ -91,14 +91,13 @@ private:
class DeviceChangeDetector : private Timer
{
public:
DeviceChangeDetector (const wchar_t* const name)
: messageWindow (name, (WNDPROC) deviceChangeEventCallback)
DeviceChangeDetector (const wchar_t* const name, std::function<void()> onChangeIn)
: messageWindow (name, (WNDPROC) deviceChangeEventCallback),
onChange (std::move (onChangeIn))
{
SetWindowLongPtr (messageWindow.getHWND(), GWLP_USERDATA, (LONG_PTR) this);
}
virtual void systemDeviceChanged() = 0;
void triggerAsyncDeviceChangeCallback()
{
// We'll pause before sending a message, because on device removal, the OS hasn't always updated
@ -108,6 +107,7 @@ public:
private:
HiddenMessageWindow messageWindow;
std::function<void()> onChange;
static LRESULT CALLBACK deviceChangeEventCallback (HWND h, const UINT message,
const WPARAM wParam, const LPARAM lParam)
@ -127,7 +127,7 @@ private:
void timerCallback() override
{
stopTimer();
systemDeviceChanged();
NullCheckedInvocation::invoke (onChange);
}
};

View file

@ -299,25 +299,24 @@ void MessageManager::doPlatformSpecificShutdown()
}
//==============================================================================
struct MountedVolumeListChangeDetector::Pimpl : private DeviceChangeDetector
struct MountedVolumeListChangeDetector::Pimpl
{
Pimpl (MountedVolumeListChangeDetector& d) : DeviceChangeDetector (L"MountedVolumeList"), owner (d)
explicit Pimpl (MountedVolumeListChangeDetector& d)
: owner (d)
{
File::findFileSystemRoots (lastVolumeList);
}
void systemDeviceChanged() override
void systemDeviceChanged()
{
Array<File> newList;
File::findFileSystemRoots (newList);
if (lastVolumeList != newList)
{
lastVolumeList = newList;
if (std::exchange (lastVolumeList, newList) != newList)
owner.mountedVolumeListChanged();
}
}
DeviceChangeDetector detector { L"MountedVolumeList", [this] { systemDeviceChanged(); } };
MountedVolumeListChangeDetector& owner;
Array<File> lastVolumeList;
};