From e07f34274b8912f773993ed96624242115440a3b Mon Sep 17 00:00:00 2001 From: Henri Herscher Date: Fri, 20 Jan 2006 22:38:18 +0000 Subject: VoIP mixing and decoding does now happen in the batch processing thread instead of immediately. Additionally, the system now supports filter plugins such as codecs. git-svn-id: https://oreka.svn.sourceforge.net/svnroot/oreka/trunk@120 09dcff7a-b715-0410-9601-b79a96267cd0 --- orkaudio/AudioTape.cpp | 55 ++-- orkaudio/AudioTape.h | 2 + orkaudio/BatchProcessing.cpp | 58 +++- orkaudio/CapturePort.cpp | 2 +- orkaudio/ImmediateProcessing.cpp | 3 +- orkaudio/OrkAudio.cpp | 32 ++ orkaudio/OrkAudio.dsp | 8 + orkaudio/OrkAudio.dsw | 12 + .../audiocaptureplugins/generator/Generator.cpp | 4 +- .../sounddevice/SoundDevice.cpp | 18 +- orkaudio/audiocaptureplugins/voip/Rtp.cpp | 13 +- orkaudio/audiocaptureplugins/voip/RtpSession.cpp | 18 +- orkaudio/audiofile/LibSndFileFile.cpp | 18 +- orkaudio/audiofile/MediaChunkFile.cpp | 154 +++++++++ orkaudio/audiofile/MediaChunkFile.h | 40 +++ orkaudio/audiofile/PcmFile.cpp | 13 +- orkaudio/filters/VoIpMixer/VoIpMixer.cpp | 353 +++++++++++++++++++++ orkaudio/filters/VoIpMixer/VoIpMixer.dsp | 162 ++++++++++ 18 files changed, 925 insertions(+), 40 deletions(-) create mode 100644 orkaudio/audiofile/MediaChunkFile.cpp create mode 100644 orkaudio/audiofile/MediaChunkFile.h create mode 100644 orkaudio/filters/VoIpMixer/VoIpMixer.cpp create mode 100644 orkaudio/filters/VoIpMixer/VoIpMixer.dsp (limited to 'orkaudio') diff --git a/orkaudio/AudioTape.cpp b/orkaudio/AudioTape.cpp index fd01b2c..c7ea945 100644 --- a/orkaudio/AudioTape.cpp +++ b/orkaudio/AudioTape.cpp @@ -16,9 +16,10 @@ #include "ace/OS_NS_time.h" #include "Utils.h" #include "ThreadSafeQueue.h" -#include "audiofile/PcmFile.h" #include "LogManager.h" +#include "audiofile/PcmFile.h" #include "audiofile/LibSndFileFile.h" +#include "audiofile/MediaChunkFile.h" #include "messages/TapeMsg.h" AudioTapeDescription::AudioTapeDescription() @@ -69,6 +70,7 @@ AudioTape::AudioTape(CStdString &portId) m_duration = 0; m_direction = CaptureEvent::DirUnkn; m_shouldStop = false; + m_readyForBatchProcessing = false; GenerateFilePathAndIdentifier(); } @@ -77,6 +79,7 @@ AudioTape::AudioTape(CStdString &portId) void AudioTape::AddAudioChunk(AudioChunkRef chunkRef, bool remote) { // Add the chunk to the local queue + if(m_state == StateCreated || m_state == StateActive) { MutexSentinel sentinel(m_mutex); if(remote) @@ -119,26 +122,30 @@ void AudioTape::Write() { m_state = StateActive; - switch(chunkRef->m_encoding) + switch(chunkRef->GetEncoding()) { - case AudioChunk::PcmAudio: - m_audioFileRef.reset(new PcmFile); - break; - case AudioChunk::UlawAudio: - m_audioFileRef.reset(new LibSndFileFile(SF_FORMAT_ULAW | SF_FORMAT_WAV)); - break; - case AudioChunk::AlawAudio: - m_audioFileRef.reset(new LibSndFileFile(SF_FORMAT_ALAW | SF_FORMAT_WAV)); - break; + case PcmAudio: + //m_audioFileRef.reset(new PcmFile); + //break; + case UlawAudio: + //m_audioFileRef.reset(new LibSndFileFile(SF_FORMAT_ULAW | SF_FORMAT_WAV)); + //break; + case AlawAudio: + //m_audioFileRef.reset(new LibSndFileFile(SF_FORMAT_ALAW | SF_FORMAT_WAV)); + //break; default: - LOG4CXX_ERROR(LOG.portLog, "#" + m_portId + ": received unsupported audio encoding from capture plugin:" + FileFormatToString(chunkRef->m_encoding)); - m_state = StateError; + //LOG4CXX_ERROR(LOG.portLog, "#" + m_portId + ": received unsupported audio encoding from capture plugin:" + FileFormatToString(chunkRef->GetEncoding())); + //m_state = StateError; + + // ########### + // All other encodings: output as a media chunk file + m_audioFileRef.reset(new MediaChunkFile()); } if (m_state == StateActive) { // A file format was successfully added to the tape, open it CStdString file = CONFIG.m_audioOutputPath + "/" + m_filePath + m_fileIdentifier; - m_audioFileRef->Open(file, AudioFile::WRITE, false, chunkRef->m_sampleRate); + m_audioFileRef->Open(file, AudioFile::WRITE, false, chunkRef->GetSampleRate()); // determine what final extension the file will have after optional compression if(CONFIG.m_storageAudioFormat == FfNative) @@ -172,18 +179,17 @@ void AudioTape::Write() } } - if (m_shouldStop) + if ( (m_shouldStop && m_state != StateStopped) || m_state == StateError) { m_state = StateStopped; - } - - if (m_state == StateStopped || m_state == StateError) - { if(m_audioFileRef.get()) { m_audioFileRef->Close(); + m_readyForBatchProcessing = true; } } + + } void AudioTape::SetShouldStop() @@ -317,6 +323,17 @@ AudioFileRef AudioTape::GetAudioFileRef() return m_audioFileRef; } +bool AudioTape::IsReadyForBatchProcessing() +{ + if(m_readyForBatchProcessing) + { + m_readyForBatchProcessing = false; // toggle to ensure not processed twice + return true; + } + return false; +} + + //======================================== // File format related methods diff --git a/orkaudio/AudioTape.h b/orkaudio/AudioTape.h index 7d40564..9870c46 100644 --- a/orkaudio/AudioTape.h +++ b/orkaudio/AudioTape.h @@ -90,6 +90,7 @@ public: CStdString GetIdentifier(); CStdString GetPath(); AudioFileRef GetAudioFileRef(); + bool IsReadyForBatchProcessing(); CStdString m_portId; CStdString m_localParty; @@ -116,6 +117,7 @@ private: ACE_Thread_Mutex m_mutex; StateEnum m_state; bool m_shouldStop; + bool m_readyForBatchProcessing; }; typedef boost::shared_ptr AudioTapeRef; diff --git a/orkaudio/BatchProcessing.cpp b/orkaudio/BatchProcessing.cpp index 1a01ac5..90f2b7b 100644 --- a/orkaudio/BatchProcessing.cpp +++ b/orkaudio/BatchProcessing.cpp @@ -17,6 +17,7 @@ #include "ace/OS_NS_unistd.h" #include "audiofile/LibSndFileFile.h" #include "Daemon.h" +#include "Filter.h" BatchProcessing BatchProcessing::m_batchProcessingSingleton; @@ -42,6 +43,8 @@ void BatchProcessing::AddAudioTape(AudioTapeRef audioTapeRef) void BatchProcessing::ThreadHandler(void *args) { + CStdString debug; + BatchProcessing* pBatchProcessing = BatchProcessing::GetInstance(); int threadId = 0; { @@ -55,6 +58,9 @@ void BatchProcessing::ThreadHandler(void *args) for(;stop == false;) { + AudioFileRef fileRef; + AudioFileRef outFileRef; + try { AudioTapeRef audioTapeRef = pBatchProcessing->m_audioTapeQueue.pop(); @@ -70,12 +76,11 @@ void BatchProcessing::ThreadHandler(void *args) CStdString threadIdString = IntToString(threadId); LOG4CXX_INFO(LOG.batchProcessingLog, CStdString("Th") + threadIdString + " processing: " + audioTapeRef->GetIdentifier()); - AudioFileRef fileRef = audioTapeRef->GetAudioFileRef(); + fileRef = audioTapeRef->GetAudioFileRef(); fileRef->MoveOrig(); fileRef->Open(AudioFile::READ); AudioChunkRef chunkRef; - AudioFileRef outFileRef; switch(CONFIG.m_storageAudioFormat) { @@ -95,14 +100,54 @@ void BatchProcessing::ThreadHandler(void *args) CStdString file = CONFIG.m_audioOutputPath + "/" + audioTapeRef->GetPath() + audioTapeRef->GetIdentifier(); outFileRef->Open(file, AudioFile::WRITE, false, fileRef->GetSampleRate()); + FilterRef filter; + FilterRef decoder1; + FilterRef decoder2; + + bool firstChunk = true; + bool voIpSession = false; + while(fileRef->ReadChunkMono(chunkRef)) { + AudioChunkDetails details = *chunkRef->GetDetails(); + if(firstChunk && details.m_rtpPayloadType != -1) + { + firstChunk = false; + CStdString filterName("VoIpMixer"); + filter = FilterRegistry::instance()->GetNewFilter(filterName); + decoder1 = FilterRegistry::instance()->GetNewFilter(details.m_rtpPayloadType); + decoder2 = FilterRegistry::instance()->GetNewFilter(details.m_rtpPayloadType); + if(decoder1.get() == NULL || decoder2.get() == NULL) + { + debug.Format("BatchProcessing - Could not find decoder for RTP payload type:%u", chunkRef->GetDetails()->m_rtpPayloadType); + throw(debug); + } + voIpSession = true; + } + if(voIpSession) + { + if(details.m_channel == 2) + { + decoder2->AudioChunkIn(chunkRef); + decoder2->AudioChunkOut(chunkRef); + } + else + { + decoder1->AudioChunkIn(chunkRef); + decoder1->AudioChunkOut(chunkRef); + } + + filter->AudioChunkIn(chunkRef); + filter->AudioChunkOut(chunkRef); + } outFileRef->WriteChunk(chunkRef); } + fileRef->Close(); + outFileRef->Close(); + if(CONFIG.m_deleteNativeFile) { - fileRef->Close(); fileRef->Delete(); CStdString threadIdString = IntToString(threadId); LOG4CXX_INFO(LOG.batchProcessingLog, CStdString("Th") + threadIdString + " deleting native: " + audioTapeRef->GetIdentifier()); @@ -113,9 +158,10 @@ void BatchProcessing::ThreadHandler(void *args) { LOG4CXX_ERROR(LOG.batchProcessingLog, CStdString("BatchProcessing: ") + e); } - catch(...) - { - } + //catch(...) + //{ + // LOG4CXX_ERROR(LOG.batchProcessingLog, CStdString("BatchProcessing: unknown exception")); + //} } LOG4CXX_INFO(LOG.batchProcessingLog, CStdString("Exiting thread #" + threadIdString)); } diff --git a/orkaudio/CapturePort.cpp b/orkaudio/CapturePort.cpp index 52ca35c..fa5a4e1 100644 --- a/orkaudio/CapturePort.cpp +++ b/orkaudio/CapturePort.cpp @@ -74,7 +74,7 @@ void CapturePort::AddAudioChunk(AudioChunkRef chunkRef, bool remote) } else if (CONFIG.m_vad) { - if(chunkRef->m_encoding == AudioChunk::PcmAudio) + if(chunkRef->GetEncoding() == PcmAudio) { if(m_vadUp) { diff --git a/orkaudio/ImmediateProcessing.cpp b/orkaudio/ImmediateProcessing.cpp index 26f564e..1298117 100644 --- a/orkaudio/ImmediateProcessing.cpp +++ b/orkaudio/ImmediateProcessing.cpp @@ -10,6 +10,7 @@ * Please refer to http://www.gnu.org/copyleft/gpl.html * */ +#pragma warning( disable: 4786 ) #include "ImmediateProcessing.h" #include "LogManager.h" @@ -58,7 +59,7 @@ void ImmediateProcessing::ThreadHandler(void *args) audioTapeRef->Write(); - if (audioTapeRef->IsStoppedAndValid()) + if (audioTapeRef->IsReadyForBatchProcessing()) { // Forward to batch processing thread BatchProcessing::GetInstance()->AddAudioTape(audioTapeRef); diff --git a/orkaudio/OrkAudio.cpp b/orkaudio/OrkAudio.cpp index 05ac4c1..daea814 100644 --- a/orkaudio/OrkAudio.cpp +++ b/orkaudio/OrkAudio.cpp @@ -16,6 +16,7 @@ #include "MultiThreadedServer.h" #include "ace/Thread_Manager.h" +#include "ace/DLL.h" #include "OrkAudio.h" #include "Utils.h" #include "messages/TapeMsg.h" @@ -33,6 +34,8 @@ #include "ObjectFactory.h" #include "CapturePluginProxy.h" #include "ace/OS_NS_arpa_inet.h" +#include "AudioCapturePlugin.h" +#include "Filter.h" static volatile bool serviceStop = false; @@ -73,6 +76,35 @@ void MainThread() ConfigManagerSingleton::instance()->Initialize(); + // Register in-built filters + FilterRef filter(new AlawToPcmFilter()); + FilterRegistry::instance()->RegisterFilter(filter); + + // Load filter plugins ##################### + //CStdString pluginPath = "./filters/VoIpMixer/Debug/VoIpMixer.dll"; + CStdString pluginPath = "./filters/VoIpMixer.dll"; + ACE_DLL dll; + dll.open((PCSTR)pluginPath); + ACE_TCHAR* error = dll.error(); + if(error) + { + LOG4CXX_ERROR(LOG.rootLog, CStdString("Failed to load the following plugin: ") + pluginPath); + } + else + { + // Ok, the dll has been successfully loaded + LOG4CXX_INFO(LOG.rootLog, CStdString("Loaded plugin: ") + pluginPath); + + //void (*initfunction)(void); + InitializeFunction initfunction; + initfunction = (InitializeFunction)dll.symbol("Initialize"); + + if (initfunction) + { + initfunction(); + } + } + if (!ACE_Thread_Manager::instance()->spawn(ACE_THR_FUNC(ImmediateProcessing::ThreadHandler))) { LOG4CXX_INFO(LOG.rootLog, CStdString("Failed to create immediate processing thread")); diff --git a/orkaudio/OrkAudio.dsp b/orkaudio/OrkAudio.dsp index d32442d..8e21d3f 100644 --- a/orkaudio/OrkAudio.dsp +++ b/orkaudio/OrkAudio.dsp @@ -150,6 +150,14 @@ SOURCE=.\AudioFile\LibSndFileFile.h # End Source File # Begin Source File +SOURCE=.\audiofile\MediaChunkFile.cpp +# End Source File +# Begin Source File + +SOURCE=.\audiofile\MediaChunkFile.h +# End Source File +# Begin Source File + SOURCE=.\AudioFile\PcmFile.cpp # End Source File # Begin Source File diff --git a/orkaudio/OrkAudio.dsw b/orkaudio/OrkAudio.dsw index aa80c9f..625b1df 100644 --- a/orkaudio/OrkAudio.dsw +++ b/orkaudio/OrkAudio.dsw @@ -63,6 +63,18 @@ Package=<4> ############################################################################### +Project: "VoIpMixer"=.\filters\VoIpMixer\VoIpMixer.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + Global: Package=<5> diff --git a/orkaudio/audiocaptureplugins/generator/Generator.cpp b/orkaudio/audiocaptureplugins/generator/Generator.cpp index 8deb07a..d97d0e4 100644 --- a/orkaudio/audiocaptureplugins/generator/Generator.cpp +++ b/orkaudio/audiocaptureplugins/generator/Generator.cpp @@ -126,7 +126,9 @@ void Run() // send audio buffer AudioChunkRef chunkRef(new AudioChunk); int sampleOffset = (elapsed % numChunks)*NUM_SAMPLES_PER_CHUNK; - chunkRef->SetBuffer(audioBuffer+sampleOffset, sizeof(short)*NUM_SAMPLES_PER_CHUNK, AudioChunk::PcmAudio); + AudioChunkDetails details; + details.m_encoding = PcmAudio; + chunkRef->SetBuffer(audioBuffer+sampleOffset, sizeof(short)*NUM_SAMPLES_PER_CHUNK, details); g_audioChunkCallBack(chunkRef, portName); } diff --git a/orkaudio/audiocaptureplugins/sounddevice/SoundDevice.cpp b/orkaudio/audiocaptureplugins/sounddevice/SoundDevice.cpp index 5326152..db791ad 100644 --- a/orkaudio/audiocaptureplugins/sounddevice/SoundDevice.cpp +++ b/orkaudio/audiocaptureplugins/sounddevice/SoundDevice.cpp @@ -65,12 +65,20 @@ int portAudioCallBack(void *inputBuffer, void *outputBuffer, unsigned long frame leftBuffer[sampleId] = inputSamples[2*sampleId+1]; } AudioChunkRef chunkRef(new AudioChunk); - chunkRef->SetBuffer(rightBuffer, sizeof(short)*framesPerBuffer, AudioChunk::PcmAudio, 0, 0, DLLCONFIG.m_sampleRate); + AudioChunkDetails rightDetails; + rightDetails.m_encoding = PcmAudio; + rightDetails.m_sampleRate = DLLCONFIG.m_sampleRate; + rightDetails.m_channel = 1; + chunkRef->SetBuffer(rightBuffer, sizeof(short)*framesPerBuffer, rightDetails); portName.Format("port%d-%d", device->deviceID, 1); g_audioChunkCallBack(chunkRef, portName); chunkRef.reset(new AudioChunk); - chunkRef->SetBuffer(leftBuffer, sizeof(short)*framesPerBuffer, AudioChunk::PcmAudio, 0, 0, DLLCONFIG.m_sampleRate); + AudioChunkDetails leftDetails; + leftDetails.m_encoding = PcmAudio; + leftDetails.m_sampleRate = DLLCONFIG.m_sampleRate; + leftDetails.m_channel = 1; + chunkRef->SetBuffer(leftBuffer, sizeof(short)*framesPerBuffer, leftDetails); portName.Format("port%d-%d", device->deviceID, 2); g_audioChunkCallBack(chunkRef, portName); @@ -81,7 +89,11 @@ int portAudioCallBack(void *inputBuffer, void *outputBuffer, unsigned long frame { // mono AudioChunkRef chunkRef(new AudioChunk); - chunkRef->SetBuffer(inputSamples, sizeof(short)*framesPerBuffer, AudioChunk::PcmAudio, 0, 0, DLLCONFIG.m_sampleRate); + AudioChunkDetails details; + details.m_encoding = PcmAudio; + details.m_sampleRate = DLLCONFIG.m_sampleRate; + details.m_channel = 1; + chunkRef->SetBuffer(inputSamples, sizeof(short)*framesPerBuffer, details); portName.Format("port%d", device->deviceID); g_audioChunkCallBack(chunkRef, portName); } diff --git a/orkaudio/audiocaptureplugins/voip/Rtp.cpp b/orkaudio/audiocaptureplugins/voip/Rtp.cpp index 23c236e..49d0815 100644 --- a/orkaudio/audiocaptureplugins/voip/Rtp.cpp +++ b/orkaudio/audiocaptureplugins/voip/Rtp.cpp @@ -36,6 +36,7 @@ void RtpPacketInfo::ToString(CStdString& string) string.Format("%s,%d %s,%d seq:%u ts:%u len:%d type:%x", sourceIp, m_sourcePort, destIp, m_destPort, m_seqNum, m_timestamp, m_payloadSize, m_payloadType); } +//============================================================================== RtpRingBuffer::RtpRingBuffer() { @@ -199,7 +200,9 @@ void RtpRingBuffer::CreateShipment(size_t silenceSize) size_t shortSize = stopPtr-m_readPtr; size_t byteSize = shortSize*2; AudioChunkRef chunk(new AudioChunk()); - chunk->SetBuffer((void*)m_readPtr, byteSize, AudioChunk::PcmAudio); + AudioChunkDetails details; + details.m_encoding = PcmAudio; + chunk->SetBuffer((void*)m_readPtr, byteSize, details); g_audioChunkCallBack(chunk, m_capturePort); m_shippedSamples += shortSize; m_readPtr = CircularPointerAddOffset(m_readPtr ,shortSize); @@ -216,7 +219,9 @@ void RtpRingBuffer::CreateShipment(size_t silenceSize) shortSize = wrappedStopPtr - m_buffer; byteSize = shortSize*2; chunk.reset(new AudioChunk()); - chunk->SetBuffer((void*)m_buffer, byteSize, AudioChunk::PcmAudio); + AudioChunkDetails details; + details.m_encoding = PcmAudio; + chunk->SetBuffer((void*)m_buffer, byteSize, details); g_audioChunkCallBack(chunk, m_capturePort); m_shippedSamples += shortSize; m_readPtr = CircularPointerAddOffset(m_readPtr ,shortSize); @@ -233,7 +238,9 @@ void RtpRingBuffer::CreateShipment(size_t silenceSize) if (silenceBuffer) { AudioChunkRef chunk(new AudioChunk()); - chunk->SetBuffer((void*)silenceBuffer, byteSize, AudioChunk::PcmAudio); + AudioChunkDetails details; + details.m_encoding = PcmAudio; + chunk->SetBuffer((void*)silenceBuffer, byteSize, details); g_audioChunkCallBack(chunk, m_capturePort); m_shippedSamples += silenceSize; m_readPtr = CircularPointerAddOffset(m_readPtr ,silenceSize); diff --git a/orkaudio/audiocaptureplugins/voip/RtpSession.cpp b/orkaudio/audiocaptureplugins/voip/RtpSession.cpp index 9065eb4..2cac30c 100644 --- a/orkaudio/audiocaptureplugins/voip/RtpSession.cpp +++ b/orkaudio/audiocaptureplugins/voip/RtpSession.cpp @@ -237,6 +237,7 @@ void RtpSession::ReportMetadata() void RtpSession::AddRtpPacket(RtpPacketInfoRef& rtpPacket) { CStdString logMsg; + unsigned char channel = 0; if(m_lastRtpPacket.get() == NULL) { @@ -262,6 +263,7 @@ void RtpSession::AddRtpPacket(RtpPacketInfoRef& rtpPacket) { // First RTP packet for side 1 m_lastRtpPacketSide1 = rtpPacket; + channel = 1; if(m_log->isInfoEnabled()) { rtpPacket->ToString(logMsg); @@ -274,6 +276,7 @@ void RtpSession::AddRtpPacket(RtpPacketInfoRef& rtpPacket) if(rtpPacket->m_sourceIp.s_addr == m_lastRtpPacketSide1->m_sourceIp.s_addr) { m_lastRtpPacketSide1 = rtpPacket; + channel = 1; } else { @@ -288,6 +291,7 @@ void RtpSession::AddRtpPacket(RtpPacketInfoRef& rtpPacket) } } m_lastRtpPacketSide2 = rtpPacket; + channel = 2; } } @@ -333,7 +337,19 @@ void RtpSession::AddRtpPacket(RtpPacketInfoRef& rtpPacket) if(m_started) { - m_rtpRingBuffer.AddRtpPacket(rtpPacket); + AudioChunkDetails details; + details.m_arrivalTimestamp = rtpPacket->m_arrivalTimestamp; + details.m_numBytes = rtpPacket->m_payloadSize; + details.m_timestamp = rtpPacket->m_timestamp; + details.m_rtpPayloadType = rtpPacket->m_payloadType; + details.m_sequenceNumber = rtpPacket->m_seqNum; + details.m_channel = channel; + details.m_encoding = AlawAudio; + AudioChunkRef chunk(new AudioChunk()); + chunk->SetBuffer(rtpPacket->m_payload, rtpPacket->m_payloadSize, details); + g_audioChunkCallBack(chunk, m_capturePort); // ##### after + //m_rtpRingBuffer.AddRtpPacket(rtpPacket); // ##### before + m_lastUpdated = rtpPacket->m_arrivalTimestamp; } } diff --git a/orkaudio/audiofile/LibSndFileFile.cpp b/orkaudio/audiofile/LibSndFileFile.cpp index fbbf3cb..0589466 100644 --- a/orkaudio/audiofile/LibSndFileFile.cpp +++ b/orkaudio/audiofile/LibSndFileFile.cpp @@ -68,10 +68,18 @@ void LibSndFileFile::Open(CStdString& filename, fileOpenModeEnum mode, bool ster void LibSndFileFile::WriteChunk(AudioChunkRef chunkRef) { - if (m_pFile) + if(chunkRef.get() == NULL) + { + return; + } + if(chunkRef->GetDetails()->m_numBytes == 0) { + return; + } - if( chunkRef->m_encoding == AudioChunk::AlawAudio || chunkRef->m_encoding == AudioChunk::UlawAudio) + if (m_pFile) + { + if( chunkRef->GetEncoding() == AlawAudio || chunkRef->GetEncoding() == UlawAudio) { if(sf_write_raw(m_pFile, chunkRef->m_pBuffer, chunkRef->GetNumSamples()) != chunkRef->GetNumSamples()) { @@ -79,7 +87,7 @@ void LibSndFileFile::WriteChunk(AudioChunkRef chunkRef) throw(CStdString("sf_write_raw failed, audio file " + m_filename + " could not be written after " + numChunksWrittenString + " chunks written")); } } - else if (chunkRef->m_encoding == AudioChunk::PcmAudio) + else if (chunkRef->GetEncoding() == PcmAudio) { if(sf_write_short(m_pFile, (short*)chunkRef->m_pBuffer, chunkRef->GetNumSamples()) != chunkRef->GetNumSamples()) { @@ -103,7 +111,9 @@ int LibSndFileFile::ReadChunkMono(AudioChunkRef& chunk) chunk.reset(new AudioChunk()); short temp[8000]; numRead = sf_read_short(m_pFile, temp, 8000); - chunk->SetBuffer(temp, sizeof(short)*numRead, AudioChunk::PcmAudio, 0, 0, m_sampleRate); + AudioChunkDetails details; + details.m_encoding = PcmAudio; + chunk->SetBuffer(temp, sizeof(short)*numRead, details); } else { diff --git a/orkaudio/audiofile/MediaChunkFile.cpp b/orkaudio/audiofile/MediaChunkFile.cpp new file mode 100644 index 0000000..47b2e8b --- /dev/null +++ b/orkaudio/audiofile/MediaChunkFile.cpp @@ -0,0 +1,154 @@ +/* + * 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 + * + */ + +#include "MediaChunkFile.h" + +#define MAX_CHUNK_SIZE 100000 + + +MediaChunkFile::MediaChunkFile() +{ + m_stream = NULL; + m_mode = READ; + m_numChunksWritten = 0; + m_sampleRate = 0; +} + +MediaChunkFile::~MediaChunkFile() +{ + Close(); +} + + +void MediaChunkFile::Close() +{ + if(m_stream) + { + ACE_OS::fclose(m_stream); + m_stream = NULL; + } +} + +void MediaChunkFile::WriteChunk(AudioChunkRef chunkRef) +{ + if(chunkRef.get() == NULL) + { + return; + } + if(chunkRef->GetDetails()->m_numBytes == 0) + { + return; + } + + unsigned int numWritten = 0; + bool writeError = false; + if (m_stream) + { + int tmp = sizeof(AudioChunkDetails); + numWritten = ACE_OS::fwrite(chunkRef->GetDetails(), sizeof(AudioChunkDetails), 1, m_stream); + if(numWritten != 1) + { + writeError = true; + } + numWritten = ACE_OS::fwrite(chunkRef->m_pBuffer, sizeof(char), chunkRef->GetNumBytes(), m_stream); + if(numWritten != chunkRef->GetNumBytes()) + { + writeError = true; + } + } + else + { + throw(CStdString("Write attempt on unopened file:")+ m_filename); + } + + if (writeError) + { + throw(CStdString("Could not write to file:")+ m_filename); + } +} + +int MediaChunkFile::ReadChunkMono(AudioChunkRef& chunkRef) +{ + unsigned int numRead = 0; + bool readError = false; + + if (m_stream) + { + chunkRef.reset(new AudioChunk()); + short temp[MAX_CHUNK_SIZE]; + numRead = ACE_OS::fread(temp, sizeof(AudioChunkDetails), 1, m_stream); + if(numRead == 1) + { + AudioChunkDetails details; + memcpy(&details, temp, sizeof(AudioChunkDetails)); + + if(details.m_marker != MEDIA_CHUNK_MARKER) + { + throw(CStdString("Invalid marker in file:")+ m_filename); + } + if(details.m_numBytes >= MAX_CHUNK_SIZE) + { + throw(CStdString("Chunk too big in file:")+ m_filename); + } + else + { + numRead = ACE_OS::fread(temp, sizeof(char), details.m_numBytes, m_stream); + if(numRead != details.m_numBytes) + { + throw(CStdString("Incomplete chunk in file:")+ m_filename); + } + chunkRef->SetBuffer(temp, details.m_numBytes, details); + } + } + } + else + { + throw(CStdString("Read attempt on unopened file:")+ m_filename); + } + + return numRead; +} + + +void MediaChunkFile::Open(CStdString& filename, fileOpenModeEnum mode, bool stereo, int sampleRate) +{ + if(m_sampleRate == 0) + { + m_sampleRate = sampleRate; + } + + if(!m_filename.Equals(filename)) + { + m_filename = filename + GetExtension(); + } + m_stream = NULL; + m_mode = mode; + if (mode == READ) + { + m_stream = ACE_OS::fopen((PCSTR)m_filename, "rb"); + } + else + { + RecursiveMkdir(m_filename); + m_stream = ACE_OS::fopen((PCSTR)m_filename, "wb"); + } + if(!m_stream) + { + throw(CStdString("Could not open file: ") + m_filename); + } +} + +CStdString MediaChunkFile::GetExtension() +{ + return ".mcf"; +} diff --git a/orkaudio/audiofile/MediaChunkFile.h b/orkaudio/audiofile/MediaChunkFile.h new file mode 100644 index 0000000..b8e69ed --- /dev/null +++ b/orkaudio/audiofile/MediaChunkFile.h @@ -0,0 +1,40 @@ +/* + * 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 __MEDIACHUNKFILE_H__ +#define __MEDIACHUNKFILE_H__ + +#include "audiofile/AudioFile.h" + + +/** File class for saving audio chunks as-is */ +class MediaChunkFile : public AudioFile +{ +public: + MediaChunkFile(); + ~MediaChunkFile(); + + void Open(CStdString& filename, fileOpenModeEnum mode, bool stereo = false, int sampleRate = 8000); + void Close(); + + void WriteChunk(AudioChunkRef chunkRef); + int ReadChunkMono(AudioChunkRef& chunkRef); + + CStdString GetExtension(); +protected: + + FILE* m_stream; +}; + +#endif + diff --git a/orkaudio/audiofile/PcmFile.cpp b/orkaudio/audiofile/PcmFile.cpp index 0acfb3f..9d1a6d0 100644 --- a/orkaudio/audiofile/PcmFile.cpp +++ b/orkaudio/audiofile/PcmFile.cpp @@ -38,6 +38,15 @@ void PcmFile::Close() void PcmFile::WriteChunk(AudioChunkRef chunkRef) { + if(chunkRef.get() == NULL) + { + return; + } + if(chunkRef->GetDetails()->m_numBytes == 0) + { + return; + } + unsigned int numWritten = 0; if (m_stream) { @@ -62,7 +71,9 @@ int PcmFile::ReadChunkMono(AudioChunkRef& chunkRef) chunkRef.reset(new AudioChunk()); short temp[PCM_FILE_DEFAULT_CHUNK_NUM_SAMPLES]; numRead = ACE_OS::fread(temp, sizeof(short), PCM_FILE_DEFAULT_CHUNK_NUM_SAMPLES, m_stream); - chunkRef->SetBuffer(temp, sizeof(short)*numRead, AudioChunk::PcmAudio, 0, 0, m_sampleRate); + AudioChunkDetails details; + details.m_encoding = PcmAudio; + chunkRef->SetBuffer(temp, sizeof(short)*numRead, details); } else { diff --git a/orkaudio/filters/VoIpMixer/VoIpMixer.cpp b/orkaudio/filters/VoIpMixer/VoIpMixer.cpp new file mode 100644 index 0000000..b2a7925 --- /dev/null +++ b/orkaudio/filters/VoIpMixer/VoIpMixer.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 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 new file mode 100644 index 0000000..2d43dd8 --- /dev/null +++ b/orkaudio/filters/VoIpMixer/VoIpMixer.dsp @@ -0,0 +1,162 @@ +# 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 -- cgit v1.2.3