From 7e1d63dd9fd149e4934bf77095c8610fac786b04 Mon Sep 17 00:00:00 2001 From: Henri Herscher Date: Thu, 20 Oct 2005 13:40:58 +0000 Subject: First checkin git-svn-id: https://oreka.svn.sourceforge.net/svnroot/oreka/trunk@2 09dcff7a-b715-0410-9601-b79a96267cd0 --- .../sounddevice/SoundDevice.cpp | 252 +++++++++++++++++++++ .../sounddevice/SoundDevice.dsp | 130 +++++++++++ .../sounddevice/SoundDeviceConfig.cpp | 70 ++++++ .../sounddevice/SoundDeviceConfig.h | 60 +++++ 4 files changed, 512 insertions(+) create mode 100644 orkaudio/audiocaptureplugins/sounddevice/SoundDevice.cpp create mode 100644 orkaudio/audiocaptureplugins/sounddevice/SoundDevice.dsp create mode 100644 orkaudio/audiocaptureplugins/sounddevice/SoundDeviceConfig.cpp create mode 100644 orkaudio/audiocaptureplugins/sounddevice/SoundDeviceConfig.h (limited to 'orkaudio/audiocaptureplugins/sounddevice') diff --git a/orkaudio/audiocaptureplugins/sounddevice/SoundDevice.cpp b/orkaudio/audiocaptureplugins/sounddevice/SoundDevice.cpp new file mode 100644 index 0000000..2a6bef4 --- /dev/null +++ b/orkaudio/audiocaptureplugins/sounddevice/SoundDevice.cpp @@ -0,0 +1,252 @@ +/* + * Oreka -- A media capture and retrieval platform + * + * Copyright (C) 2005, orecx LLC + * + * http://www.orecx.com + * + * This program is free software, distributed under the terms of + * the GNU General Public License. + * Please refer to http://www.gnu.org/copyleft/gpl.html + * + */ + +#define _WINSOCKAPI_ // prevents the inclusion of winsock.h + +#include "ace/OS_NS_unistd.h" +#include "ace/Singleton.h" +#include "ace/Min_Max.h" +#include "AudioCapturePlugin.h" +#include "AudioCapturePluginCommon.h" +#include "portaudio.h" +#include "Utils.h" +#include "SoundDeviceConfig.h" + +extern AudioChunkCallBackFunction g_audioChunkCallBack; +extern CaptureEventCallBackFunction g_captureEventCallBack; +extern LogManager* g_logManager; + +SoundDeviceConfigTopObjectRef g_soundDeviceConfigTopObjectRef; +#define DLLCONFIG g_soundDeviceConfigTopObjectRef.get()->m_config + + +typedef struct +{ + PaDeviceID deviceID; + int channelCount; + PortAudioStream* stream; +} DeviceUserData; + +int portAudioCallBack(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData) +{ + DeviceUserData *device = (DeviceUserData *)userData; + short * inputSamples = (short *)inputBuffer; + CStdString portName; + + if (device->channelCount == 2) + { + // stereo -> split into two different chunks + short* rightBuffer = new short[DLLCONFIG.m_audioChunkSize]; + short* leftBuffer = new short[DLLCONFIG.m_audioChunkSize]; + + for (int sampleId=0; sampleIdSetBuffer(rightBuffer, sizeof(short)*framesPerBuffer, AudioChunk::PcmAudio); + portName.Format("port%d-%d", device->deviceID, 1); + g_audioChunkCallBack(chunkRef, portName); + + chunkRef.reset(new AudioChunk); + chunkRef->SetBuffer(leftBuffer, sizeof(short)*framesPerBuffer, AudioChunk::PcmAudio); + portName.Format("port%d-%d", device->deviceID, 2); + g_audioChunkCallBack(chunkRef, portName); + + delete rightBuffer; + delete leftBuffer; + } + else + { + // mono + AudioChunkRef chunkRef(new AudioChunk); + chunkRef->SetBuffer(inputSamples, sizeof(short)*framesPerBuffer, AudioChunk::PcmAudio); + portName.Format("port%d", device->deviceID); + g_audioChunkCallBack(chunkRef, portName); + } + + return 0; +} + + +class SoundDevice +{ +public: + SoundDevice(); + void Initialize(); + void Run(); + void StartCapture(CStdString& port); + void StopCapture(CStdString& port); +private: + DeviceUserData** m_devices; + int m_deviceCount; + PaStream* m_stream; +}; + +typedef ACE_Singleton SoundDeviceSingleton; + +SoundDevice::SoundDevice() +{ + m_deviceCount = 0; + m_devices = NULL; +} + +void Configure(DOMNode* node) +{ + if (node) + { + SoundDeviceConfigTopObjectRef soundDeviceConfigTopObjectRef(new SoundDeviceConfigTopObject); + try + { + soundDeviceConfigTopObjectRef.get()->DeSerializeDom(node); + g_soundDeviceConfigTopObjectRef = soundDeviceConfigTopObjectRef; + } + catch (CStdString& e) + { + LOG4CXX_WARN(g_logManager->rootLog, "SoundDevice.dll: " + e + " - using defaults"); + } + } + else + { + LOG4CXX_WARN(g_logManager->rootLog, "SoundDevice.dll: got empty DOM tree"); + } +} + + +void SoundDevice::Initialize() +{ + LOG4CXX_INFO(g_logManager->rootLog, "Initializing Sound Device plugin"); + + // create a default config object in case it was not properly initialized by Configure + if(!g_soundDeviceConfigTopObjectRef.get()) + { + g_soundDeviceConfigTopObjectRef.reset(new SoundDeviceConfigTopObject); + } + + + PaError result = Pa_Initialize(); + if (result) + { + LOG4CXX_ERROR(g_logManager->rootLog, "Could not initialize Sound Device plugin"); + } + + m_deviceCount = Pa_CountDevices(); + m_devices = new DeviceUserData*[m_deviceCount]; + + for( PaDeviceID deviceID=0; deviceIDdeviceID = deviceID; + m_devices[deviceID]->channelCount = ace_max(deviceInfo->maxInputChannels,2); + m_devices[deviceID]->stream = NULL; + CStdString deviceName(deviceInfo->name); + + if (deviceInfo->maxInputChannels > 0 && deviceName.Find("Primary") == -1) // Primary audio device is a duplicate of one of the devices + { + CStdString capturePorts; + if (deviceInfo->maxInputChannels > 1) + { + capturePorts.Format("port%d-1, port%d-2", deviceID, deviceID); // stereo + } + else + { + capturePorts.Format("port%d-1", deviceID); // mono + } + + CStdString maxInputChannelsString = IntToString(deviceInfo->maxInputChannels); + LOG4CXX_INFO(g_logManager->rootLog, "Ports:" + capturePorts + " Name:" + deviceName + " Channels:" + maxInputChannelsString); + + result = Pa_OpenStream( &m_devices[deviceID]->stream, + deviceID, + m_devices[deviceID]->channelCount, + paInt16, + NULL, + paNoDevice , + 0, + paInt16, + NULL, + 8000.0, + DLLCONFIG.m_audioChunkSize, + 0, + 0, + portAudioCallBack, + (void*)m_devices[deviceID] ); + + if (result) + { + CStdString deviceIdString = IntToString(deviceID); + LOG4CXX_ERROR(g_logManager->rootLog, "Device:" + deviceIdString + CStdString(" Pa_OpenStream error:") + Pa_GetErrorText(result)); + } + } + } +} + +void SoundDevice::Run() +{ + for( PaDeviceID deviceID=0; deviceIDchannelCount > 0 && m_devices[deviceID]->stream) + { + PaError result = Pa_StartStream(m_devices[deviceID]->stream); + if (result) + { + CStdString deviceIdString = IntToString(deviceID); + LOG4CXX_ERROR(g_logManager->rootLog, "Device:" + deviceIdString + CStdString(" Pa_StartStream error:") + Pa_GetErrorText(result)); + } + } + } +} + +void SoundDevice::StartCapture(CStdString& port) +{ + CaptureEventRef startEvent(new CaptureEvent); + startEvent->m_type = CaptureEvent::EtStart; + startEvent->m_timestamp = time(NULL); + g_captureEventCallBack(startEvent, port); +} + +void SoundDevice::StopCapture(CStdString& port) +{ + CaptureEventRef stopEvent(new CaptureEvent); + stopEvent->m_type = CaptureEvent::EtStop; + stopEvent->m_timestamp = time(NULL); + g_captureEventCallBack(stopEvent, port); +} + +void __CDECL__ Initialize() +{ + SoundDeviceSingleton::instance()->Initialize(); +} + +void __CDECL__ Run() +{ + SoundDeviceSingleton::instance()->Run(); + for(;;) + { + // if this idle thread is missing, it will crash winmm + ACE_OS::sleep(5); + } +} + +void __CDECL__ StartCapture(CStdString& capturePort) +{ + SoundDeviceSingleton::instance()->StartCapture(capturePort); +} + +void __CDECL__ StopCapture(CStdString& capturePort) +{ + SoundDeviceSingleton::instance()->StopCapture(capturePort); +} \ No newline at end of file diff --git a/orkaudio/audiocaptureplugins/sounddevice/SoundDevice.dsp b/orkaudio/audiocaptureplugins/sounddevice/SoundDevice.dsp new file mode 100644 index 0000000..844f5a6 --- /dev/null +++ b/orkaudio/audiocaptureplugins/sounddevice/SoundDevice.dsp @@ -0,0 +1,130 @@ +# Microsoft Developer Studio Project File - Name="SoundDevice" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=SoundDevice - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SoundDevice.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SoundDevice.mak" CFG="SoundDevice - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SoundDevice - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "SoundDevice - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SoundDevice - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOUNDDEVICE_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../.." /I "../../../OrkBaseCxx" /I "C:\devExt\boost\boost_1_32_0" /I "C:\devExt\portaudio_v18\pa_common" /I "C:\devExt\ACE_wrappers" /I "C:\devExt\xerces++\xerces-c_2_6_0-windows_nt-msvc_60\include" /I "../Common" /I "C:\devExt\log4cxx\log4cxx-0.9.7\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOUNDDEVICE_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 OrkBase.lib winmm.lib dsound.lib ace.lib PAStaticDS.lib log4cxx.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /libpath:"../../../OrkBaseCxx/Release" /libpath:"C:\devExt\log4cxx\log4cxx-0.9.7\msvc\Lib\Release" /libpath:"C:\devExt\portaudio_v18\winproj\Lib" /libpath:"C:\devExt\ACE_wrappers\lib" + +!ELSEIF "$(CFG)" == "SoundDevice - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOUNDDEVICE_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../.." /I "../../../OrkBaseCxx" /I "C:\devExt\boost\boost_1_32_0" /I "C:\devExt\portaudio_v18\pa_common" /I "C:\devExt\ACE_wrappers" /I "C:\devExt\xerces++\xerces-c_2_6_0-windows_nt-msvc_60\include" /I "../Common" /I "C:\devExt\log4cxx\log4cxx-0.9.7\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SOUNDDEVICE_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 OrkBaseD.lib winmm.lib dsound.lib aced.lib PAStaticDSD.lib log4cxx.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../OrkBaseCxx/Debug" /libpath:"C:\devExt\log4cxx\log4cxx-0.9.7\msvc\Lib\Debug" /libpath:"C:\devExt\portaudio_v18\winproj\Lib" /libpath:"C:\devExt\ACE_wrappers\lib" + +!ENDIF + +# Begin Target + +# Name "SoundDevice - Win32 Release" +# Name "SoundDevice - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\AudioCapturePlugin.h +# End Source File +# Begin Source File + +SOURCE=..\Common\AudioCapturePluginCommon.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\AudioCapturePluginCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\ConfigManager.h +# End Source File +# Begin Source File + +SOURCE=.\SoundDevice.cpp +# End Source File +# Begin Source File + +SOURCE=.\SoundDeviceConfig.cpp +# End Source File +# Begin Source File + +SOURCE=.\SoundDeviceConfig.h +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/orkaudio/audiocaptureplugins/sounddevice/SoundDeviceConfig.cpp b/orkaudio/audiocaptureplugins/sounddevice/SoundDeviceConfig.cpp new file mode 100644 index 0000000..998eb72 --- /dev/null +++ b/orkaudio/audiocaptureplugins/sounddevice/SoundDeviceConfig.cpp @@ -0,0 +1,70 @@ +/* + * Oreka -- A media capture and retrieval platform + * + * Copyright (C) 2005, orecx LLC + * + * http://www.orecx.com + * + * This program is free software, distributed under the terms of + * the GNU General Public License. + * Please refer to http://www.gnu.org/copyleft/gpl.html + * + */ + +#define _WINSOCKAPI_ // prevents the inclusion of winsock.h + +#include "Utils.h" +#include "Serializers/Serializer.h" +#include "SoundDeviceConfig.h" + +SoundDeviceConfig::SoundDeviceConfig() +{ + m_audioChunkSize = AUDIO_CHUNK_SIZE_DEFAULT; +} + +void SoundDeviceConfig::Define(Serializer* s) +{ + s->IntValue(AUDIO_CHUNK_SIZE_PARAM, m_audioChunkSize); +} + +void SoundDeviceConfig::Validate() +{ + if(m_audioChunkSize > 80000 || m_audioChunkSize<100) + { + CStdString audioChunkSizeString = IntToString(m_audioChunkSize); + throw(CStdString("SoundDeviceConfig: ") + AUDIO_CHUNK_SIZE_PARAM + "=" + audioChunkSizeString + " this is out of range"); + } +} + +CStdString SoundDeviceConfig::GetClassName() +{ + return CStdString("SoundDeviceConfig"); +} + +ObjectRef SoundDeviceConfig::NewInstance() +{ + return ObjectRef(new SoundDeviceConfig); +} + +//==================================== + + +void SoundDeviceConfigTopObject::Define(Serializer* s) +{ + s->ObjectValue(SOUND_DEVICE_CONFIG_PARAM, m_config, true); +} + +void SoundDeviceConfigTopObject::Validate() +{ + ; +} + +CStdString SoundDeviceConfigTopObject::GetClassName() +{ + return CStdString("SoundDeviceConfigTopObject"); +} + +ObjectRef SoundDeviceConfigTopObject::NewInstance() +{ + return ObjectRef(new SoundDeviceConfigTopObject); +} \ No newline at end of file diff --git a/orkaudio/audiocaptureplugins/sounddevice/SoundDeviceConfig.h b/orkaudio/audiocaptureplugins/sounddevice/SoundDeviceConfig.h new file mode 100644 index 0000000..6453523 --- /dev/null +++ b/orkaudio/audiocaptureplugins/sounddevice/SoundDeviceConfig.h @@ -0,0 +1,60 @@ +/* + * Oreka -- A media capture and retrieval platform + * + * Copyright (C) 2005, orecx LLC + * + * http://www.orecx.com + * + * This program is free software, distributed under the terms of + * the GNU General Public License. + * Please refer to http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifndef __SOUNDDEVICECONFIG_H__ +#define __SOUNDDEVICECONFIG_H__ + +#include "StdString.h" +#include "Object.h" +#include "boost/shared_ptr.hpp" + +#define AUDIO_CHUNK_SIZE_PARAM "AudioChunkSize" +#define AUDIO_CHUNK_SIZE_DEFAULT 8000 + +/** This class defines various configuration parameters for the generator. */ +class SoundDeviceConfig : public Object +{ +public: + SoundDeviceConfig(); + void Define(Serializer* s); + void Validate(); + + CStdString GetClassName(); + ObjectRef NewInstance(); + inline ObjectRef Process() {return ObjectRef();}; + + int m_audioChunkSize; +}; + +//======================================== + +#define SOUND_DEVICE_CONFIG_PARAM "SoundDevicePlugin" + +/** This class represents the top of the configuration hierarchy for the generator. */ +class SoundDeviceConfigTopObject : public Object +{ +public: + void Define(Serializer* s); + void Validate(); + + CStdString GetClassName(); + ObjectRef NewInstance(); + inline ObjectRef Process() {return ObjectRef();}; + + SoundDeviceConfig m_config; +}; + +typedef boost::shared_ptr SoundDeviceConfigTopObjectRef; + + +#endif \ No newline at end of file -- cgit v1.2.3