From d0f20811afae74d94f757f73bcfe84600e3b6040 Mon Sep 17 00:00:00 2001 From: Henri Herscher Date: Sat, 21 Jan 2006 01:41:51 +0000 Subject: *** empty log message *** git-svn-id: https://oreka.svn.sourceforge.net/svnroot/oreka/trunk@123 09dcff7a-b715-0410-9601-b79a96267cd0 --- orkaudio/OrkAudio.dsw | 6 +- orkaudio/filters/VoIpMixer/VoIpMixer.cpp | 353 ------------------------------- orkaudio/filters/VoIpMixer/VoIpMixer.dsp | 162 -------------- orkaudio/filters/rtpmixer/RtpMixer.cpp | 353 +++++++++++++++++++++++++++++++ orkaudio/filters/rtpmixer/RtpMixer.dsp | 106 ++++++++++ 5 files changed, 462 insertions(+), 518 deletions(-) delete mode 100644 orkaudio/filters/VoIpMixer/VoIpMixer.cpp delete mode 100644 orkaudio/filters/VoIpMixer/VoIpMixer.dsp create mode 100644 orkaudio/filters/rtpmixer/RtpMixer.cpp create mode 100644 orkaudio/filters/rtpmixer/RtpMixer.dsp (limited to 'orkaudio') diff --git a/orkaudio/OrkAudio.dsw b/orkaudio/OrkAudio.dsw index 625b1df..9c693eb 100644 --- a/orkaudio/OrkAudio.dsw +++ b/orkaudio/OrkAudio.dsw @@ -39,7 +39,7 @@ Package=<4> ############################################################################### -Project: "SoundDevice"=.\AudioCapturePlugins\SoundDevice\SoundDevice.dsp - Package Owner=<4> +Project: "RtpMixer"=.\filters\rtpmixer\RtpMixer.dsp - Package Owner=<4> Package=<5> {{{ @@ -51,7 +51,7 @@ Package=<4> ############################################################################### -Project: "VoIp"=.\audiocaptureplugins\voip\VoIp.dsp - Package Owner=<4> +Project: "SoundDevice"=.\AudioCapturePlugins\SoundDevice\SoundDevice.dsp - Package Owner=<4> Package=<5> {{{ @@ -63,7 +63,7 @@ Package=<4> ############################################################################### -Project: "VoIpMixer"=.\filters\VoIpMixer\VoIpMixer.dsp - Package Owner=<4> +Project: "VoIp"=.\audiocaptureplugins\voip\VoIp.dsp - Package Owner=<4> Package=<5> {{{ diff --git a/orkaudio/filters/VoIpMixer/VoIpMixer.cpp b/orkaudio/filters/VoIpMixer/VoIpMixer.cpp deleted file mode 100644 index b2a7925..0000000 --- a/orkaudio/filters/VoIpMixer/VoIpMixer.cpp +++ /dev/null @@ -1,353 +0,0 @@ -/* - * 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 - * - */ -#pragma warning( disable: 4786 ) - -#ifdef WIN32 -#define __CDECL__ __cdecl -#else -#define __CDECL__ -#endif -#ifdef WIN32 - #define DLL_EXPORT __declspec( dllexport ) -#else - #define DLL_EXPORT -#endif - -#include -#include "Filter.h" -#include "AudioCapture.h" -extern "C" -{ -#include "g711.h" -} - -#define NUM_SAMPLES_CIRCULAR_BUFFER 8000 -#define NUM_SAMPLES_TRIGGER 4000 // when we have this number of available samples make a shipment -#define NUM_SAMPLES_SHIPMENT_HOLDOFF 2000 // when shipping, ship everything but this number of samples - - -class VoIpMixer : public Filter -{ -public: - VoIpMixer(); - - FilterRef __CDECL__ Instanciate(); - void __CDECL__ AudioChunkIn(AudioChunkRef& chunk); - void __CDECL__ AudioChunkOut(AudioChunkRef& chunk); - AudioEncodingEnum __CDECL__ GetInputAudioEncoding(); - AudioEncodingEnum __CDECL__ GetOutputAudioEncoding(); - CStdString __CDECL__ GetName(); - int __CDECL__ GetInputRtpPayloadType(); - -private: - //AudioChunkRef m_outputAudioChunk; - std::queue m_outputQueue; - - void StoreRtpPacket(AudioChunkRef& chunk); - void CreateShipment(size_t silenceSize); - unsigned int FreeSpace(); - unsigned int UsedSpace(); - short* GetHoldOffPtr(); - short* CircularPointerAddOffset(short *ptr, size_t offset); - short* CicularPointerSubtractOffset(short *ptr, size_t offset); - - short* m_writePtr; // pointer after newest RTP data we've received - short* m_readPtr; // where to read from next - unsigned int m_readTimestamp; // timestamp that the next shipment will have - unsigned int m_writeTimestamp; // timestamp that the next RTP buffer should have - short* m_bufferEnd; - short m_buffer[NUM_SAMPLES_CIRCULAR_BUFFER]; - unsigned int m_shippedSamples; - -}; - -VoIpMixer::VoIpMixer() -{ - m_writePtr = m_buffer; - m_readPtr = m_buffer; - m_bufferEnd = m_buffer + NUM_SAMPLES_CIRCULAR_BUFFER; - m_writeTimestamp = 0; - m_readTimestamp = 0; - //m_log = Logger::getLogger("rtpringbuffer"); - m_shippedSamples = 0; -} - -FilterRef VoIpMixer::Instanciate() -{ - FilterRef Filter(new VoIpMixer()); - return Filter; -} - -void VoIpMixer::AudioChunkIn(AudioChunkRef& chunk) -{ - AudioChunkDetails* details = chunk->GetDetails(); - if(details->m_encoding != PcmAudio) - { - throw (CStdString("VoIpMixer input audio must be PCM !")); - } - - unsigned int rtpEndTimestamp = details->m_timestamp + chunk->GetNumSamples(); // GetNumSamples() ############################# - - if(m_writeTimestamp == 0) - { - // First RTP packet of the session - //LOG4CXX_DEBUG(m_log, m_capturePort + " first packet"); - m_writeTimestamp = details->m_timestamp; - m_readTimestamp = m_writeTimestamp; - StoreRtpPacket(chunk); - } - else if (details->m_timestamp >= m_readTimestamp) // drop packets that are older than last shipment - { - if( (int)(rtpEndTimestamp - m_writeTimestamp) <= (int)FreeSpace()) - { - // RTP packet fits into current buffer - StoreRtpPacket(chunk); - - if(UsedSpace() > NUM_SAMPLES_TRIGGER) - { - // We have enough stuff, make a shipment - CreateShipment(0); - } - } - else - { - // RTP packet does not fit into current buffer - // work out how much silence we need to add to the current buffer when shipping - size_t silenceSize = details->m_timestamp - m_writeTimestamp; - CreateShipment(silenceSize); - - // reset buffer - m_writePtr = m_buffer; - m_readPtr = m_buffer; - m_writeTimestamp = details->m_timestamp; - m_readTimestamp = m_writeTimestamp; - - // Store new packet - StoreRtpPacket(chunk); - } - } - else - { - //LOG4CXX_DEBUG(m_log, m_capturePort + " packet too old, dropped"); - } - CStdString debug; - debug.Format("free:%u used:%u wr:%x rd:%x wrts:%u rdts:%d", FreeSpace(), UsedSpace(), m_writePtr, m_readPtr, m_writeTimestamp, m_readTimestamp); - //LOG4CXX_DEBUG(m_log, debug); -} - -void VoIpMixer::AudioChunkOut(AudioChunkRef& chunk) -{ - if(m_outputQueue.size() > 0) - { - chunk = m_outputQueue.front(); - m_outputQueue.pop(); - } - else - { - chunk.reset(); - } -} - -AudioEncodingEnum VoIpMixer::GetInputAudioEncoding() -{ - return PcmAudio; -} - -AudioEncodingEnum VoIpMixer::GetOutputAudioEncoding() -{ - return PcmAudio; -} - -CStdString VoIpMixer::GetName() -{ - return "VoIpMixer"; -} - - -int VoIpMixer::GetInputRtpPayloadType(void) // does not link if not defined here ? -{ - return -1; -} - -// Writes to the internal buffer without any size verification -void VoIpMixer::StoreRtpPacket(AudioChunkRef& audioChunk) -{ - CStdString debug; - AudioChunkDetails* details = audioChunk->GetDetails(); - - // 1. Silence from write pointer until end of RTP packet - unsigned int endRtpTimestamp = details->m_timestamp + audioChunk->GetNumSamples(); // GetNumSamples() ############################# - if (endRtpTimestamp > m_writeTimestamp) - { - for(int i=0; i<(endRtpTimestamp - m_writeTimestamp); i++) - { - *m_writePtr = 0; - m_writePtr++; - if(m_writePtr >= m_bufferEnd) - { - m_writePtr = m_buffer; - } - } - int silenceSize = endRtpTimestamp - m_writeTimestamp; - m_writeTimestamp = endRtpTimestamp; - debug.Format("Zeroed %d samples, wr:%x wrts:%u", silenceSize, m_writePtr, m_writeTimestamp); - //LOG4CXX_DEBUG(m_log, debug); - } - - // 2. Mix in the latest samples from this RTP packet - unsigned int timestampDelta = m_writeTimestamp - details->m_timestamp; - ASSERT(timestampDelta>=0); - short* tempWritePtr = CicularPointerSubtractOffset(m_writePtr, timestampDelta); - short* payload = (short *)audioChunk->m_pBuffer; // payload should be short* ################################################# - - for(int i=0; iGetNumSamples() ; i++) //################################################# - { - *tempWritePtr += payload[i]; - tempWritePtr++; - if(tempWritePtr >= m_bufferEnd) - { - tempWritePtr = m_buffer; - } - } - debug.Format("Copied %d samples, tmpwr:%x", audioChunk->GetNumSamples(), tempWritePtr); //################################################# - //LOG4CXX_DEBUG(m_log, debug); -} - -short* VoIpMixer::CircularPointerAddOffset(short *ptr, size_t offset) -{ - if((ptr + offset) >= m_bufferEnd) - { - return m_buffer + offset - (m_bufferEnd-ptr); - } - else - { - return ptr + offset; - } -} - -short* VoIpMixer::CicularPointerSubtractOffset(short *ptr, size_t offset) -{ - if((ptr-offset) < m_buffer) - { - return m_bufferEnd - offset + (ptr-m_buffer); - } - else - { - return ptr - offset; - } -} - -void VoIpMixer::CreateShipment(size_t silenceSize) -{ - // 1. ship from readPtr until stop pointer or until end of buffer if wrapped - bool bufferWrapped = false; - short* stopPtr = NULL; - short* wrappedStopPtr = NULL; - if (silenceSize) - { - // There is additional silence to ship, do not take holdoff into account - stopPtr = m_writePtr; - } - else - { - stopPtr = CicularPointerSubtractOffset(m_writePtr, NUM_SAMPLES_SHIPMENT_HOLDOFF); - } - - if (stopPtr < m_readPtr) - { - wrappedStopPtr = stopPtr; - stopPtr = m_bufferEnd; - bufferWrapped = true; - } - size_t shortSize = stopPtr-m_readPtr; - size_t byteSize = shortSize*2; - AudioChunkRef chunk(new AudioChunk()); - AudioChunkDetails details; - details.m_encoding = PcmAudio; - chunk->SetBuffer((void*)m_readPtr, byteSize, details); - m_outputQueue.push(chunk); - m_shippedSamples += shortSize; - m_readPtr = CircularPointerAddOffset(m_readPtr ,shortSize); - m_readTimestamp += shortSize; - - CStdString debug; - debug.Format("Ship %d samples, rd:%x rdts:%u", shortSize, m_readPtr, m_readTimestamp); - //LOG4CXX_DEBUG(m_log, debug); - - - // 2. ship from beginning of buffer until stop ptr - if(bufferWrapped) - { - shortSize = wrappedStopPtr - m_buffer; - byteSize = shortSize*2; - chunk.reset(new AudioChunk()); - AudioChunkDetails details; - details.m_encoding = PcmAudio; - chunk->SetBuffer((void*)m_buffer, byteSize, details); - m_outputQueue.push(chunk); - m_shippedSamples += shortSize; - m_readPtr = CircularPointerAddOffset(m_readPtr ,shortSize); - m_readTimestamp += shortSize; - debug.Format("Ship wrapped %d samples, rd:%x rdts:%u", shortSize, m_readPtr, m_readTimestamp); - //LOG4CXX_DEBUG(m_log, debug); - } - - // 3. ship silence - if (silenceSize) - { - byteSize = silenceSize*2; - char* silenceBuffer = (char*)calloc(byteSize, 1); - if (silenceBuffer) - { - AudioChunkRef chunk(new AudioChunk()); - AudioChunkDetails details; - details.m_encoding = PcmAudio; - chunk->SetBuffer((void*)silenceBuffer, byteSize, details); - m_outputQueue.push(chunk); - m_shippedSamples += silenceSize; - m_readPtr = CircularPointerAddOffset(m_readPtr ,silenceSize); - m_readTimestamp += silenceSize; - } - debug.Format("Ship %d silence samples, rd:%x rdts:%u", silenceSize, m_readPtr, m_readTimestamp); - //LOG4CXX_DEBUG(m_log, debug); - } -} - - -unsigned int VoIpMixer::UsedSpace() -{ - if(m_writePtr >= m_readPtr) - { - return m_writePtr - m_readPtr; - } - return NUM_SAMPLES_CIRCULAR_BUFFER + m_writePtr - m_readPtr; -} - - -unsigned int VoIpMixer::FreeSpace() -{ - return NUM_SAMPLES_CIRCULAR_BUFFER - UsedSpace(); -} - - -//===================================================================== - - -extern "C" -{ - DLL_EXPORT void __CDECL__ Initialize() - { - FilterRef filter(new VoIpMixer()); - FilterRegistry::instance()->RegisterFilter(filter); - } -} \ No newline at end of file diff --git a/orkaudio/filters/VoIpMixer/VoIpMixer.dsp b/orkaudio/filters/VoIpMixer/VoIpMixer.dsp deleted file mode 100644 index 2d43dd8..0000000 --- a/orkaudio/filters/VoIpMixer/VoIpMixer.dsp +++ /dev/null @@ -1,162 +0,0 @@ -# Microsoft Developer Studio Project File - Name="VoIpMixer" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=VoIpMixer - 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 "VoIpMixer.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 "VoIpMixer.mak" CFG="VoIpMixer - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "VoIpMixer - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "VoIpMixer - 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)" == "VoIpMixer - 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 "VoIpMixer_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MT /W3 /GX /O2 /I "C:\devExt\winpcap\WpdPack\Include" /I "../.." /I "../../../OrkBaseCxx" /I "C:\devExt\boost\boost_1_32_0" /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 "VoIpMixer_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 packet.lib wpcap.lib wininet.lib OrkBase.lib ace.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:"C:\devExt\winpcap\WpdPack\Lib" /libpath:"../../../OrkBaseCxx/Release" /libpath:"C:\devExt\log4cxx\log4cxx-0.9.7\msvc\Lib\Release" /libpath:"C:\devExt\ACE_wrappers\lib" - -!ELSEIF "$(CFG)" == "VoIpMixer - 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 "VoIpMixer_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "C:\devExt\winpcap\WpdPack\Include" /I "../.." /I "../../../OrkBaseCxx" /I "C:\devExt\boost\boost_1_32_0" /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 "VoIpMixer_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 packet.lib wpcap.lib wininet.lib OrkBaseD.lib aced.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:"C:\devExt\winpcap\WpdPack\Lib" /libpath:"../../../OrkBaseCxx/Debug" /libpath:"C:\devExt\log4cxx\log4cxx-0.9.7\msvc\Lib\Debug" /libpath:"C:\devExt\ACE_wrappers\lib" - -!ENDIF - -# Begin Target - -# Name "VoIpMixer - Win32 Release" -# Name "VoIpMixer - 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=.\g711.c -# End Source File -# Begin Source File - -SOURCE=.\g711.h -# End Source File -# Begin Source File - -SOURCE=.\PacketHeaderDefs.cpp -# End Source File -# Begin Source File - -SOURCE=.\PacketHeaderDefs.h -# End Source File -# Begin Source File - -SOURCE=.\Rtp.cpp -# End Source File -# Begin Source File - -SOURCE=.\Rtp.h -# End Source File -# Begin Source File - -SOURCE=.\RtpSession.cpp -# End Source File -# Begin Source File - -SOURCE=.\RtpSession.h -# End Source File -# Begin Source File - -SOURCE=.\VoIpMixer.cpp -# End Source File -# Begin Source File - -SOURCE=.\VoIpMixerConfig.cpp -# End Source File -# Begin Source File - -SOURCE=.\VoIpMixerConfig.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/filters/rtpmixer/RtpMixer.cpp b/orkaudio/filters/rtpmixer/RtpMixer.cpp new file mode 100644 index 0000000..bbba476 --- /dev/null +++ b/orkaudio/filters/rtpmixer/RtpMixer.cpp @@ -0,0 +1,353 @@ +/* + * 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 + * + */ +#pragma warning( disable: 4786 ) + +#ifdef WIN32 +#define __CDECL__ __cdecl +#else +#define __CDECL__ +#endif +#ifdef WIN32 + #define DLL_EXPORT __declspec( dllexport ) +#else + #define DLL_EXPORT +#endif + +#include +#include "Filter.h" +#include "AudioCapture.h" +extern "C" +{ +#include "g711.h" +} + +#define NUM_SAMPLES_CIRCULAR_BUFFER 8000 +#define NUM_SAMPLES_TRIGGER 4000 // when we have this number of available samples make a shipment +#define NUM_SAMPLES_SHIPMENT_HOLDOFF 2000 // when shipping, ship everything but this number of samples + + +class RtpMixer : public Filter +{ +public: + RtpMixer(); + + FilterRef __CDECL__ Instanciate(); + void __CDECL__ AudioChunkIn(AudioChunkRef& chunk); + void __CDECL__ AudioChunkOut(AudioChunkRef& chunk); + AudioEncodingEnum __CDECL__ GetInputAudioEncoding(); + AudioEncodingEnum __CDECL__ GetOutputAudioEncoding(); + CStdString __CDECL__ GetName(); + int __CDECL__ GetInputRtpPayloadType(); + +private: + //AudioChunkRef m_outputAudioChunk; + std::queue m_outputQueue; + + void StoreRtpPacket(AudioChunkRef& chunk); + void CreateShipment(size_t silenceSize); + unsigned int FreeSpace(); + unsigned int UsedSpace(); + short* GetHoldOffPtr(); + short* CircularPointerAddOffset(short *ptr, size_t offset); + short* CicularPointerSubtractOffset(short *ptr, size_t offset); + + short* m_writePtr; // pointer after newest RTP data we've received + short* m_readPtr; // where to read from next + unsigned int m_readTimestamp; // timestamp that the next shipment will have + unsigned int m_writeTimestamp; // timestamp that the next RTP buffer should have + short* m_bufferEnd; + short m_buffer[NUM_SAMPLES_CIRCULAR_BUFFER]; + unsigned int m_shippedSamples; + +}; + +RtpMixer::RtpMixer() +{ + m_writePtr = m_buffer; + m_readPtr = m_buffer; + m_bufferEnd = m_buffer + NUM_SAMPLES_CIRCULAR_BUFFER; + m_writeTimestamp = 0; + m_readTimestamp = 0; + //m_log = Logger::getLogger("rtpringbuffer"); + m_shippedSamples = 0; +} + +FilterRef RtpMixer::Instanciate() +{ + FilterRef Filter(new RtpMixer()); + return Filter; +} + +void RtpMixer::AudioChunkIn(AudioChunkRef& chunk) +{ + AudioChunkDetails* details = chunk->GetDetails(); + if(details->m_encoding != PcmAudio) + { + throw (CStdString("RtpMixer input audio must be PCM !")); + } + + unsigned int rtpEndTimestamp = details->m_timestamp + chunk->GetNumSamples(); // GetNumSamples() ############################# + + if(m_writeTimestamp == 0) + { + // First RTP packet of the session + //LOG4CXX_DEBUG(m_log, m_capturePort + " first packet"); + m_writeTimestamp = details->m_timestamp; + m_readTimestamp = m_writeTimestamp; + StoreRtpPacket(chunk); + } + else if (details->m_timestamp >= m_readTimestamp) // drop packets that are older than last shipment + { + if( (int)(rtpEndTimestamp - m_writeTimestamp) <= (int)FreeSpace()) + { + // RTP packet fits into current buffer + StoreRtpPacket(chunk); + + if(UsedSpace() > NUM_SAMPLES_TRIGGER) + { + // We have enough stuff, make a shipment + CreateShipment(0); + } + } + else + { + // RTP packet does not fit into current buffer + // work out how much silence we need to add to the current buffer when shipping + size_t silenceSize = details->m_timestamp - m_writeTimestamp; + CreateShipment(silenceSize); + + // reset buffer + m_writePtr = m_buffer; + m_readPtr = m_buffer; + m_writeTimestamp = details->m_timestamp; + m_readTimestamp = m_writeTimestamp; + + // Store new packet + StoreRtpPacket(chunk); + } + } + else + { + //LOG4CXX_DEBUG(m_log, m_capturePort + " packet too old, dropped"); + } + CStdString debug; + debug.Format("free:%u used:%u wr:%x rd:%x wrts:%u rdts:%d", FreeSpace(), UsedSpace(), m_writePtr, m_readPtr, m_writeTimestamp, m_readTimestamp); + //LOG4CXX_DEBUG(m_log, debug); +} + +void RtpMixer::AudioChunkOut(AudioChunkRef& chunk) +{ + if(m_outputQueue.size() > 0) + { + chunk = m_outputQueue.front(); + m_outputQueue.pop(); + } + else + { + chunk.reset(); + } +} + +AudioEncodingEnum RtpMixer::GetInputAudioEncoding() +{ + return PcmAudio; +} + +AudioEncodingEnum RtpMixer::GetOutputAudioEncoding() +{ + return PcmAudio; +} + +CStdString RtpMixer::GetName() +{ + return "RtpMixer"; +} + + +int RtpMixer::GetInputRtpPayloadType(void) // does not link if not defined here ? +{ + return -1; +} + +// Writes to the internal buffer without any size verification +void RtpMixer::StoreRtpPacket(AudioChunkRef& audioChunk) +{ + CStdString debug; + AudioChunkDetails* details = audioChunk->GetDetails(); + + // 1. Silence from write pointer until end of RTP packet + unsigned int endRtpTimestamp = details->m_timestamp + audioChunk->GetNumSamples(); // GetNumSamples() ############################# + if (endRtpTimestamp > m_writeTimestamp) + { + for(int i=0; i<(endRtpTimestamp - m_writeTimestamp); i++) + { + *m_writePtr = 0; + m_writePtr++; + if(m_writePtr >= m_bufferEnd) + { + m_writePtr = m_buffer; + } + } + int silenceSize = endRtpTimestamp - m_writeTimestamp; + m_writeTimestamp = endRtpTimestamp; + debug.Format("Zeroed %d samples, wr:%x wrts:%u", silenceSize, m_writePtr, m_writeTimestamp); + //LOG4CXX_DEBUG(m_log, debug); + } + + // 2. Mix in the latest samples from this RTP packet + unsigned int timestampDelta = m_writeTimestamp - details->m_timestamp; + ASSERT(timestampDelta>=0); + short* tempWritePtr = CicularPointerSubtractOffset(m_writePtr, timestampDelta); + short* payload = (short *)audioChunk->m_pBuffer; // payload should be short* ################################################# + + for(int i=0; iGetNumSamples() ; i++) //################################################# + { + *tempWritePtr += payload[i]; + tempWritePtr++; + if(tempWritePtr >= m_bufferEnd) + { + tempWritePtr = m_buffer; + } + } + debug.Format("Copied %d samples, tmpwr:%x", audioChunk->GetNumSamples(), tempWritePtr); //################################################# + //LOG4CXX_DEBUG(m_log, debug); +} + +short* RtpMixer::CircularPointerAddOffset(short *ptr, size_t offset) +{ + if((ptr + offset) >= m_bufferEnd) + { + return m_buffer + offset - (m_bufferEnd-ptr); + } + else + { + return ptr + offset; + } +} + +short* RtpMixer::CicularPointerSubtractOffset(short *ptr, size_t offset) +{ + if((ptr-offset) < m_buffer) + { + return m_bufferEnd - offset + (ptr-m_buffer); + } + else + { + return ptr - offset; + } +} + +void RtpMixer::CreateShipment(size_t silenceSize) +{ + // 1. ship from readPtr until stop pointer or until end of buffer if wrapped + bool bufferWrapped = false; + short* stopPtr = NULL; + short* wrappedStopPtr = NULL; + if (silenceSize) + { + // There is additional silence to ship, do not take holdoff into account + stopPtr = m_writePtr; + } + else + { + stopPtr = CicularPointerSubtractOffset(m_writePtr, NUM_SAMPLES_SHIPMENT_HOLDOFF); + } + + if (stopPtr < m_readPtr) + { + wrappedStopPtr = stopPtr; + stopPtr = m_bufferEnd; + bufferWrapped = true; + } + size_t shortSize = stopPtr-m_readPtr; + size_t byteSize = shortSize*2; + AudioChunkRef chunk(new AudioChunk()); + AudioChunkDetails details; + details.m_encoding = PcmAudio; + chunk->SetBuffer((void*)m_readPtr, byteSize, details); + m_outputQueue.push(chunk); + m_shippedSamples += shortSize; + m_readPtr = CircularPointerAddOffset(m_readPtr ,shortSize); + m_readTimestamp += shortSize; + + CStdString debug; + debug.Format("Ship %d samples, rd:%x rdts:%u", shortSize, m_readPtr, m_readTimestamp); + //LOG4CXX_DEBUG(m_log, debug); + + + // 2. ship from beginning of buffer until stop ptr + if(bufferWrapped) + { + shortSize = wrappedStopPtr - m_buffer; + byteSize = shortSize*2; + chunk.reset(new AudioChunk()); + AudioChunkDetails details; + details.m_encoding = PcmAudio; + chunk->SetBuffer((void*)m_buffer, byteSize, details); + m_outputQueue.push(chunk); + m_shippedSamples += shortSize; + m_readPtr = CircularPointerAddOffset(m_readPtr ,shortSize); + m_readTimestamp += shortSize; + debug.Format("Ship wrapped %d samples, rd:%x rdts:%u", shortSize, m_readPtr, m_readTimestamp); + //LOG4CXX_DEBUG(m_log, debug); + } + + // 3. ship silence + if (silenceSize) + { + byteSize = silenceSize*2; + char* silenceBuffer = (char*)calloc(byteSize, 1); + if (silenceBuffer) + { + AudioChunkRef chunk(new AudioChunk()); + AudioChunkDetails details; + details.m_encoding = PcmAudio; + chunk->SetBuffer((void*)silenceBuffer, byteSize, details); + m_outputQueue.push(chunk); + m_shippedSamples += silenceSize; + m_readPtr = CircularPointerAddOffset(m_readPtr ,silenceSize); + m_readTimestamp += silenceSize; + } + debug.Format("Ship %d silence samples, rd:%x rdts:%u", silenceSize, m_readPtr, m_readTimestamp); + //LOG4CXX_DEBUG(m_log, debug); + } +} + + +unsigned int RtpMixer::UsedSpace() +{ + if(m_writePtr >= m_readPtr) + { + return m_writePtr - m_readPtr; + } + return NUM_SAMPLES_CIRCULAR_BUFFER + m_writePtr - m_readPtr; +} + + +unsigned int RtpMixer::FreeSpace() +{ + return NUM_SAMPLES_CIRCULAR_BUFFER - UsedSpace(); +} + + +//===================================================================== + + +extern "C" +{ + DLL_EXPORT void __CDECL__ Initialize() + { + FilterRef filter(new RtpMixer()); + FilterRegistry::instance()->RegisterFilter(filter); + } +} \ No newline at end of file diff --git a/orkaudio/filters/rtpmixer/RtpMixer.dsp b/orkaudio/filters/rtpmixer/RtpMixer.dsp new file mode 100644 index 0000000..3784a41 --- /dev/null +++ b/orkaudio/filters/rtpmixer/RtpMixer.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="RtpMixer" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=RtpMixer - 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 "RtpMixer.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 "RtpMixer.mak" CFG="RtpMixer - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "RtpMixer - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "RtpMixer - 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)" == "RtpMixer - 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 "RtpMixer_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "C:\devExt\winpcap\WpdPack\Include" /I "../.." /I "../../../OrkBaseCxx" /I "C:\devExt\boost\boost_1_32_0" /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 "RtpMixer_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 packet.lib wpcap.lib wininet.lib OrkBase.lib ace.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:"C:\devExt\winpcap\WpdPack\Lib" /libpath:"../../../OrkBaseCxx/Release" /libpath:"C:\devExt\log4cxx\log4cxx-0.9.7\msvc\Lib\Release" /libpath:"C:\devExt\ACE_wrappers\lib" + +!ELSEIF "$(CFG)" == "RtpMixer - 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 "RtpMixer_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "C:\devExt\winpcap\WpdPack\Include" /I "../.." /I "../../../OrkBaseCxx" /I "C:\devExt\boost\boost_1_32_0" /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 "RtpMixer_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 packet.lib wpcap.lib wininet.lib OrkBaseD.lib aced.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:"C:\devExt\winpcap\WpdPack\Lib" /libpath:"../../../OrkBaseCxx/Debug" /libpath:"C:\devExt\log4cxx\log4cxx-0.9.7\msvc\Lib\Debug" /libpath:"C:\devExt\ACE_wrappers\lib" + +!ENDIF + +# Begin Target + +# Name "RtpMixer - Win32 Release" +# Name "RtpMixer - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\RtpMixer.cpp +# 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 -- cgit v1.2.3