mirror of
https://github.com/cookiengineer/audacity
synced 2025-04-30 15:49:41 +02:00
List of commands that were executed in the `src directory`: * sed -i 's/Audacity: A Digital Audio Editor/Tenacity/g' *.h * sed -i 's/Audacity: A Digital Audio Editor/Tenacity/g' *.cpp Signed-off-by: Panagiotis Vasilopoulos <hello@alwayslivid.com>
406 lines
9.2 KiB
C++
406 lines
9.2 KiB
C++
/**********************************************************************
|
|
|
|
Tenacity
|
|
|
|
DeviceChange.cpp
|
|
|
|
Leland Lucius
|
|
|
|
*******************************************************************//*!
|
|
|
|
\file DeviceChange.cpp
|
|
\brief
|
|
|
|
*//*******************************************************************/
|
|
|
|
#include "DeviceChange.h"
|
|
|
|
|
|
|
|
#if defined(EXPERIMENTAL_DEVICE_CHANGE_HANDLER)
|
|
|
|
#if defined(HAVE_DEVICE_CHANGE)
|
|
|
|
#include <wx/module.h>
|
|
#include <wx/timer.h>
|
|
#include <wx/thread.h>
|
|
|
|
DECLARE_LOCAL_EVENT_TYPE(EVT_DEVICE_CHANGE, -1);
|
|
DEFINE_EVENT_TYPE(EVT_DEVICE_CHANGE);
|
|
|
|
#if defined(__WXMSW__)
|
|
|
|
#include <Windows.h>
|
|
#include <mmsystem.h>
|
|
#include <mmdeviceapi.h>
|
|
#include <audioclient.h>
|
|
|
|
class DeviceChangeListener final : public IMMNotificationClient,
|
|
public DeviceChangeInterface
|
|
{
|
|
public:
|
|
DeviceChangeListener()
|
|
{
|
|
mRefCnt = 1;
|
|
mEnumerator = NULL;
|
|
mEnabled = false;
|
|
mHandler = NULL;
|
|
}
|
|
|
|
virtual ~DeviceChangeListener()
|
|
{
|
|
if (mEnumerator)
|
|
{
|
|
mEnumerator->UnregisterEndpointNotificationCallback(this);
|
|
mEnumerator = NULL;
|
|
}
|
|
|
|
if (mHandler)
|
|
{
|
|
CoInitialize(NULL);
|
|
}
|
|
}
|
|
|
|
// IUnknown implementation
|
|
|
|
ULONG STDMETHODCALLTYPE AddRef()
|
|
{
|
|
return InterlockedIncrement(&mRefCnt);
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE Release()
|
|
{
|
|
ULONG cnt = InterlockedDecrement(&mRefCnt);
|
|
if (cnt == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface)
|
|
{
|
|
if (riid == IID_IUnknown)
|
|
{
|
|
AddRef();
|
|
*ppvInterface = (IUnknown *) this;
|
|
}
|
|
else if (riid == __uuidof(IMMNotificationClient))
|
|
{
|
|
AddRef();
|
|
*ppvInterface = (IMMNotificationClient *) this;
|
|
}
|
|
else
|
|
{
|
|
*ppvInterface = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// IMMDeviceChangeListener implementation
|
|
|
|
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged( EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState)
|
|
{
|
|
if (mEnabled)
|
|
{
|
|
mEnabled = false;
|
|
wxMutexGuiEnter();
|
|
wxCommandEvent e(EVT_DEVICE_CHANGE);
|
|
mHandler->AddPendingEvent(e);
|
|
wxMutexGuiLeave();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
bool SetHandler(wxEvtHandler *handler)
|
|
{
|
|
mHandler = handler;
|
|
|
|
CoInitialize(NULL);
|
|
|
|
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
__uuidof(IMMDeviceEnumerator),
|
|
(void**)&mEnumerator);
|
|
if (hr == S_OK && mEnumerator)
|
|
{
|
|
mEnumerator->RegisterEndpointNotificationCallback(this);
|
|
}
|
|
|
|
return hr == S_OK && mEnumerator;
|
|
}
|
|
|
|
void Enable(bool enable)
|
|
{
|
|
mEnabled = enable;
|
|
}
|
|
|
|
private:
|
|
wxEvtHandler *mHandler;
|
|
bool mEnabled;
|
|
ULONG mRefCnt;
|
|
IMMDeviceEnumerator *mEnumerator;
|
|
};
|
|
|
|
#elif defined(__WXGTK__)
|
|
|
|
#include <libudev.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <locale.h>
|
|
#include <unistd.h>
|
|
|
|
class DeviceChangeListener final : public DeviceChangeInterface
|
|
{
|
|
public:
|
|
DeviceChangeListener()
|
|
{
|
|
mEnabled = false;
|
|
mHandler = NULL;
|
|
mThread = 0;
|
|
}
|
|
|
|
virtual ~DeviceChangeListener()
|
|
{
|
|
if (mThread)
|
|
{
|
|
pthread_cancel(mThread);
|
|
mThread = 0;
|
|
}
|
|
}
|
|
|
|
// IUnknown implementation
|
|
bool SetHandler(wxEvtHandler *handler)
|
|
{
|
|
mHandler = handler;
|
|
|
|
return pthread_create(&mThread, NULL, DeviceChangeListener::Listener, this) == 0;
|
|
}
|
|
|
|
void Enable(bool enable)
|
|
{
|
|
mEnabled = enable;
|
|
}
|
|
|
|
static void *Listener(void *parm)
|
|
{
|
|
DeviceChangeListener *This = (DeviceChangeListener *) parm;
|
|
|
|
// Instantiate the udev object
|
|
struct udev *udev = udev_new();
|
|
if (!udev)
|
|
{
|
|
pthread_exit(NULL);
|
|
}
|
|
|
|
// Instantiate the monitor object
|
|
struct udev_monitor *mon = udev_monitor_new_from_netlink(udev, "udev");
|
|
|
|
// Start receiving notifications
|
|
udev_monitor_enable_receiving(mon);
|
|
|
|
// Get the file descriptor we'll wait on
|
|
int fd = udev_monitor_get_fd(mon);
|
|
|
|
while (true)
|
|
{
|
|
fd_set set;
|
|
|
|
FD_ZERO(&set);
|
|
FD_SET(fd, &set);
|
|
|
|
if (select(fd + 1, &set, NULL, NULL, NULL) < 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (FD_ISSET(fd, &set))
|
|
{
|
|
struct udev_device *dev = udev_monitor_receive_device(mon);
|
|
if (dev)
|
|
{
|
|
#if 0
|
|
wxPrintf("Got Device\n");
|
|
wxPrintf(" Node: %s\n", udev_device_get_devnode(dev));
|
|
wxPrintf(" Subsystem: %s\n", udev_device_get_subsystem(dev));
|
|
wxPrintf(" Devtype: %s\n", udev_device_get_devtype(dev));
|
|
wxPrintf(" Action: %s\n", udev_device_get_action(dev));
|
|
#endif
|
|
if (This->mEnabled)
|
|
{
|
|
This->mEnabled = false;
|
|
wxMutexGuiEnter();
|
|
wxCommandEvent e(EVT_DEVICE_CHANGE);
|
|
This->mHandler->AddPendingEvent(e);
|
|
wxMutexGuiLeave();
|
|
}
|
|
|
|
udev_device_unref(dev);
|
|
}
|
|
}
|
|
}
|
|
|
|
udev_unref(udev);
|
|
|
|
pthread_exit(NULL);
|
|
}
|
|
|
|
private:
|
|
wxEvtHandler *mHandler;
|
|
bool mEnabled;
|
|
pthread_t mThread;
|
|
};
|
|
|
|
#elif defined(__WXMAC__)
|
|
|
|
#include <CoreAudio/CoreAudio.h>
|
|
|
|
class DeviceChangeListener final : public DeviceChangeInterface
|
|
{
|
|
public:
|
|
DeviceChangeListener()
|
|
{
|
|
mEnabled = false;
|
|
mHandler = NULL;
|
|
mListening = false;
|
|
}
|
|
|
|
virtual ~DeviceChangeListener()
|
|
{
|
|
if (mListening)
|
|
{
|
|
AudioObjectPropertyAddress property_address;
|
|
|
|
property_address.mSelector = kAudioHardwarePropertyDevices;
|
|
property_address.mScope = kAudioObjectPropertyScopeGlobal;
|
|
property_address.mElement = kAudioObjectPropertyElementMaster;
|
|
|
|
AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
|
|
&property_address,
|
|
DeviceChangeListener::Listener,
|
|
this);
|
|
mListening = false;
|
|
}
|
|
}
|
|
|
|
// IUnknown implementation
|
|
bool SetHandler(wxEvtHandler *handler)
|
|
{
|
|
mHandler = handler;
|
|
|
|
AudioObjectPropertyAddress property_address;
|
|
|
|
property_address.mSelector = kAudioHardwarePropertyDevices;
|
|
property_address.mScope = kAudioObjectPropertyScopeGlobal;
|
|
property_address.mElement = kAudioObjectPropertyElementMaster;
|
|
|
|
mListening = AudioObjectAddPropertyListener(kAudioObjectSystemObject,
|
|
&property_address,
|
|
DeviceChangeListener::Listener,
|
|
this) == 0;
|
|
}
|
|
|
|
void Enable(bool enable)
|
|
{
|
|
mEnabled = enable;
|
|
}
|
|
|
|
static OSStatus Listener(AudioObjectID objectID,
|
|
UInt32 numberAddresses,
|
|
const AudioObjectPropertyAddress inAddresses[],
|
|
void *clientData)
|
|
{
|
|
DeviceChangeListener *This = (DeviceChangeListener *) clientData;
|
|
|
|
for (int i = 0; i < numberAddresses; i++)
|
|
{
|
|
#if 0
|
|
wxPrintf("address %d\n", i);
|
|
wxPrintf("selector %08x\n", inAddresses[i].mSelector);
|
|
wxPrintf("scope %08x\n", inAddresses[i].mScope);
|
|
wxPrintf("element %08x\n", inAddresses[i].mElement);
|
|
#endif
|
|
if (This->mEnabled)
|
|
{
|
|
This->mEnabled = false;
|
|
wxMutexGuiEnter();
|
|
wxCommandEvent e(EVT_DEVICE_CHANGE);
|
|
This->mHandler->AddPendingEvent(e);
|
|
wxMutexGuiLeave();
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
wxEvtHandler *mHandler;
|
|
bool mEnabled;
|
|
bool mListening;
|
|
};
|
|
#endif
|
|
|
|
BEGIN_EVENT_TABLE(DeviceChangeHandler, wxEvtHandler)
|
|
EVT_COMMAND(wxID_ANY, EVT_DEVICE_CHANGE, DeviceChangeHandler::OnChange)
|
|
EVT_TIMER(wxID_ANY, DeviceChangeHandler::OnTimer)
|
|
END_EVENT_TABLE()
|
|
|
|
DeviceChangeHandler::DeviceChangeHandler()
|
|
: wxEvtHandler()
|
|
{
|
|
mTimer.SetOwner(this);
|
|
mListener = std::make_unique<DeviceChangeListener>();
|
|
mListener->SetHandler(this);
|
|
mListener->Enable(true);
|
|
}
|
|
|
|
DeviceChangeHandler::~DeviceChangeHandler()
|
|
{
|
|
if (mListener)
|
|
mListener->Enable(false);
|
|
}
|
|
|
|
void DeviceChangeHandler::Enable(bool enable)
|
|
{
|
|
mListener->Enable(enable);
|
|
}
|
|
|
|
void DeviceChangeHandler::OnChange(wxCommandEvent & evt)
|
|
{
|
|
mTimer.Start(500, true);
|
|
}
|
|
|
|
void DeviceChangeHandler::OnTimer(wxTimerEvent & evt)
|
|
{
|
|
DeviceChangeNotification();
|
|
mListener->Enable(true);
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|