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:
parent
238fbfca94
commit
49a954d473
4 changed files with 71 additions and 78 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue