mirror of
				https://github.com/cookiengineer/audacity
				synced 2025-10-31 14:13:50 +01: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:
		
							
								
								
									
										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 | ||||
		Reference in New Issue
	
	Block a user