summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenri Herscher <henri@oreka.org>2006-01-20 22:38:18 +0000
committerHenri Herscher <henri@oreka.org>2006-01-20 22:38:18 +0000
commite07f34274b8912f773993ed96624242115440a3b (patch)
tree6b2f35398ceb7ff5c6a5afc9991f9a3670cb3a27
parent4ab4f3d3b2f0c3c51922eaeea49df162a9c892cd (diff)
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
-rw-r--r--orkaudio/AudioTape.cpp55
-rw-r--r--orkaudio/AudioTape.h2
-rw-r--r--orkaudio/BatchProcessing.cpp58
-rw-r--r--orkaudio/CapturePort.cpp2
-rw-r--r--orkaudio/ImmediateProcessing.cpp3
-rw-r--r--orkaudio/OrkAudio.cpp32
-rw-r--r--orkaudio/OrkAudio.dsp8
-rw-r--r--orkaudio/OrkAudio.dsw12
-rw-r--r--orkaudio/audiocaptureplugins/generator/Generator.cpp4
-rw-r--r--orkaudio/audiocaptureplugins/sounddevice/SoundDevice.cpp18
-rw-r--r--orkaudio/audiocaptureplugins/voip/Rtp.cpp13
-rw-r--r--orkaudio/audiocaptureplugins/voip/RtpSession.cpp18
-rw-r--r--orkaudio/audiofile/LibSndFileFile.cpp18
-rw-r--r--orkaudio/audiofile/MediaChunkFile.cpp154
-rw-r--r--orkaudio/audiofile/MediaChunkFile.h40
-rw-r--r--orkaudio/audiofile/PcmFile.cpp13
-rw-r--r--orkaudio/filters/VoIpMixer/VoIpMixer.cpp353
-rw-r--r--orkaudio/filters/VoIpMixer/VoIpMixer.dsp162
18 files changed, 925 insertions, 40 deletions
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<AudioTape> 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 <queue>
+#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<AudioChunkRef> 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; i<audioChunk->GetNumSamples() ; 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