diff options
author | Henri Herscher <henri@oreka.org> | 2006-12-18 20:54:10 +0000 |
---|---|---|
committer | Henri Herscher <henri@oreka.org> | 2006-12-18 20:54:10 +0000 |
commit | 179e05d310e852573838d417c38744ed77c8dc30 (patch) | |
tree | ac392034ad653a670059698a2e622150a7539e44 /orkaudio | |
parent | 0b1f069bf332eb6c21357d17b7b8a5795f165efc (diff) |
RTP mixer is now flushed at the end of streams so we don't miss a small chunk of audio at the end of the transcoded file. Also, introduced VoIP QOS logging in the RTP mixer.
git-svn-id: https://oreka.svn.sourceforge.net/svnroot/oreka/trunk@372 09dcff7a-b715-0410-9601-b79a96267cd0
Diffstat (limited to 'orkaudio')
-rw-r--r-- | orkaudio/BatchProcessing.cpp | 14 | ||||
-rw-r--r-- | orkaudio/filters/rtpmixer/RtpMixer.cpp | 86 |
2 files changed, 97 insertions, 3 deletions
diff --git a/orkaudio/BatchProcessing.cpp b/orkaudio/BatchProcessing.cpp index 808fea0..14b5d11 100644 --- a/orkaudio/BatchProcessing.cpp +++ b/orkaudio/BatchProcessing.cpp @@ -240,6 +240,20 @@ void BatchProcessing::ThreadHandler(void *args) } } + if(voIpSession) + { + // Flush the RTP mixer + AudioChunkRef stopChunk(new AudioChunk()); + stopChunk->GetDetails()->m_marker = MEDIA_CHUNK_EOS_MARKER; + filter->AudioChunkIn(stopChunk); + filter->AudioChunkOut(tmpChunkRef); + outFileRef->WriteChunk(tmpChunkRef); + if(tmpChunkRef.get()) + { + numSamplesOut += tmpChunkRef->GetNumSamples(); + } + } + fileRef->Close(); outFileRef->Close(); logMsg.Format("[%s] Th%s stop: num samples: s1:%u s2:%u out:%u", trackingId, threadIdString, numSamplesS1, numSamplesS2, numSamplesOut); diff --git a/orkaudio/filters/rtpmixer/RtpMixer.cpp b/orkaudio/filters/rtpmixer/RtpMixer.cpp index f651673..f087dd1 100644 --- a/orkaudio/filters/rtpmixer/RtpMixer.cpp +++ b/orkaudio/filters/rtpmixer/RtpMixer.cpp @@ -56,6 +56,9 @@ private: short* CircularPointerAddOffset(short *ptr, size_t offset); short* CicularPointerSubtractOffset(short *ptr, size_t offset); bool CheckChunkDetails(AudioChunkDetails&); + void DoStats( AudioChunkDetails* details, AudioChunkDetails* lastDetails, + int& seqNumMisses, int& seqMaxGap, int& seqNumOutOfOrder, + int& seqNumDiscontinuities); short* m_writePtr; // pointer after newest RTP data we've received short* m_readPtr; // where to read from next @@ -69,6 +72,18 @@ private: bool m_invalidChannelReported; size_t m_numProcessedSamples; bool m_error; + + // Statistics related variables + AudioChunkRef m_lastChunkS1; + AudioChunkRef m_lastChunkS2; + int m_seqNumMissesS1; + int m_seqNumMissesS2; + int m_seqMaxGapS1; + int m_seqMaxGapS2; + int m_seqNumOutOfOrderS1; + int m_seqNumOutOfOrderS2; + int m_seqNumDiscontinuitiesS1; + int m_seqNumDiscontinuitiesS2; }; RtpMixer::RtpMixer() @@ -84,6 +99,14 @@ RtpMixer::RtpMixer() m_invalidChannelReported = false; m_numProcessedSamples = 0; m_error = false; + m_seqNumMissesS1 = 0; + m_seqNumMissesS2 = 0; + m_seqMaxGapS1 = 0; + m_seqMaxGapS2 = 0; + m_seqNumOutOfOrderS1 = 0; + m_seqNumOutOfOrderS2 = 0; + m_seqNumDiscontinuitiesS1 = 0; + m_seqNumDiscontinuitiesS2 = 0; } FilterRef RtpMixer::Instanciate() @@ -92,6 +115,40 @@ FilterRef RtpMixer::Instanciate() return Filter; } +void RtpMixer::DoStats( AudioChunkDetails* details, AudioChunkDetails* lastDetails, + int& seqNumMisses, int& seqMaxGap, int& seqNumOutOfOrder, + int& seqNumDiscontinuities) +{ + double seqNumDelta = (double)details->m_sequenceNumber - (double)lastDetails->m_sequenceNumber; + double timestampDelta = (double)details->m_timestamp - (double)lastDetails->m_timestamp; + if( abs(seqNumDelta) > 1000.0 && + abs(timestampDelta) > 160000.0) + { + seqNumDiscontinuities++; + CStdString logMsg; + logMsg.Format("RTP discontinuity s%d: before: seq:%u ts:%u after: seq:%u ts:%u", + details->m_channel, lastDetails->m_sequenceNumber, lastDetails->m_timestamp, + details->m_sequenceNumber, details->m_timestamp); + LOG4CXX_DEBUG(m_log, logMsg); + } + else + { + if(seqNumDelta > (double)seqMaxGap) + { + seqMaxGap = (unsigned int)seqNumDelta; + } + if(seqNumDelta < 0.0) + { + seqNumOutOfOrder++; + } + if(seqNumDelta != 1.0 && details->m_sequenceNumber != 1) + { + seqNumMisses++; + } + } +} + + void RtpMixer::AudioChunkIn(AudioChunkRef& chunk) { CStdString logMsg; @@ -105,6 +162,19 @@ void RtpMixer::AudioChunkIn(AudioChunkRef& chunk) LOG4CXX_DEBUG(m_log, "Null input chunk"); return; } + + AudioChunkDetails* details = chunk->GetDetails(); + + if(details->m_marker == MEDIA_CHUNK_EOS_MARKER) + { + logMsg.Format("EOS s1: misses:%d maxgap:%d oo:%d disc:%d s2: misses:%d maxgap:%d oo:%d disc:%d", + m_seqNumMissesS1, m_seqMaxGapS1, m_seqNumOutOfOrderS1, m_seqNumDiscontinuitiesS1, + m_seqNumMissesS2, m_seqMaxGapS2, m_seqNumOutOfOrderS2, m_seqNumDiscontinuitiesS2); + LOG4CXX_INFO(m_log, logMsg); + + CreateShipment(); // flush the buffer + return; + } else if(chunk->GetNumSamples() == 0) { LOG4CXX_DEBUG(m_log, "Empty input chunk"); @@ -116,17 +186,21 @@ void RtpMixer::AudioChunkIn(AudioChunkRef& chunk) LOG4CXX_ERROR(m_log, "RtpMixer: input chunk too big"); return; } - - AudioChunkDetails* details = chunk->GetDetails(); if(details->m_encoding != PcmAudio) { throw (CStdString("RtpMixer input audio must be PCM !")); - } + } unsigned int correctedTimestamp = 0; if(details->m_channel == 1) { + if(m_lastChunkS1.get()) + { + DoStats(details, m_lastChunkS1->GetDetails(), m_seqNumMissesS1, m_seqMaxGapS1, + m_seqNumOutOfOrderS1, m_seqNumDiscontinuitiesS1); + } + m_lastChunkS1 = chunk; correctedTimestamp = details->m_timestamp; m_numProcessedSamples += chunk->GetNumSamples(); if(m_numProcessedSamples > 115200000) // arbitrary high number (= 4 hours worth of 8KHz samples) @@ -138,6 +212,12 @@ void RtpMixer::AudioChunkIn(AudioChunkRef& chunk) } else if(details->m_channel == 2) { + if(m_lastChunkS2.get()) + { + DoStats(details, m_lastChunkS2->GetDetails(), m_seqNumMissesS2, m_seqMaxGapS2, + m_seqNumOutOfOrderS2, m_seqNumDiscontinuitiesS2); + } + m_lastChunkS2 = chunk; // Corrective delta always only applied to side 2. double tmp = (double)details->m_timestamp - m_timestampCorrectiveDelta; if(tmp < 0.0) |