summaryrefslogtreecommitdiff
path: root/orkaudio
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 /orkaudio
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
Diffstat (limited to 'orkaudio')
-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