mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-16 08:09:32 +02:00
Add new files...should have been part of r13697
I REALLY need to come up with a better process for moving between plats as I (apparently) can't remember to do a simple "svn add" on the final move...grrrr!!!!
This commit is contained in:
parent
512cf7faca
commit
d438755ae5
406
src/DeviceChange.cpp
Normal file
406
src/DeviceChange.cpp
Normal file
@ -0,0 +1,406 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
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 : 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 : 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
|
||||
printf("Got Device\n");
|
||||
printf(" Node: %s\n", udev_device_get_devnode(dev));
|
||||
printf(" Subsystem: %s\n", udev_device_get_subsystem(dev));
|
||||
printf(" Devtype: %s\n", udev_device_get_devtype(dev));
|
||||
printf(" 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 : 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
|
||||
printf("address %d\n", i);
|
||||
printf("selector %08x\n", inAddresses[i].mSelector);
|
||||
printf("scope %08x\n", inAddresses[i].mScope);
|
||||
printf("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 = new DeviceChangeListener();
|
||||
mListener->SetHandler(this);
|
||||
mListener->Enable(true);
|
||||
}
|
||||
|
||||
DeviceChangeHandler::~DeviceChangeHandler()
|
||||
{
|
||||
if (mListener)
|
||||
{
|
||||
mListener->Enable(false);
|
||||
delete mListener;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
61
src/DeviceChange.h
Normal file
61
src/DeviceChange.h
Normal file
@ -0,0 +1,61 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
DeviceChange.h
|
||||
|
||||
Leland Lucius
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __AUDACITY_DEVICECHANGE_H__
|
||||
#define __AUDACITY_DEVICECHANGE_H__
|
||||
|
||||
#include "Audacity.h"
|
||||
#include "Experimental.h"
|
||||
|
||||
#if defined(EXPERIMENTAL_DEVICE_CHANGE_HANDLER)
|
||||
|
||||
#if defined(__WXMSW__) || defined(__WXMAC__) || defined(HAVE_LIBUDEV_H)
|
||||
#define HAVE_DEVICE_CHANGE
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DEVICE_CHANGE)
|
||||
|
||||
#include <wx/event.h>
|
||||
#include <wx/timer.h>
|
||||
|
||||
class DeviceChangeInterface
|
||||
{
|
||||
public:
|
||||
virtual ~DeviceChangeInterface() {};
|
||||
|
||||
virtual bool SetHandler(wxEvtHandler *handler) = 0;
|
||||
virtual void Enable(bool enable = true) = 0;
|
||||
};
|
||||
|
||||
class DeviceChangeHandler : public wxEvtHandler
|
||||
{
|
||||
public:
|
||||
DeviceChangeHandler();
|
||||
virtual ~DeviceChangeHandler();
|
||||
|
||||
void Enable(bool enable = true);
|
||||
|
||||
virtual void DeviceChangeNotification() = 0;
|
||||
|
||||
private:
|
||||
void OnChange(wxCommandEvent & evt);
|
||||
void OnTimer(wxTimerEvent & evt);
|
||||
|
||||
DeviceChangeInterface *mListener;
|
||||
wxTimer mTimer;
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user