From bc1b43b297b6b229df5c0de95f7ef888bf3c6c10 Mon Sep 17 00:00:00 2001 From: "tina.legrand@webrtc.org" Date: Thu, 26 Apr 2012 08:53:45 +0000 Subject: [PATCH] Refactoring of audio_coding_module_impl First patch set: pure formatting. Review URL: https://webrtc-codereview.appspot.com/522001 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2125 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../main/source/audio_coding_module_impl.cc | 4251 ++++++++--------- .../main/source/audio_coding_module_impl.h | 580 +-- 2 files changed, 2177 insertions(+), 2654 deletions(-) diff --git a/src/modules/audio_coding/main/source/audio_coding_module_impl.cc b/src/modules/audio_coding/main/source/audio_coding_module_impl.cc index 3e573d26f7..a8c30af5fc 100644 --- a/src/modules/audio_coding/main/source/audio_coding_module_impl.cc +++ b/src/modules/audio_coding/main/source/audio_coding_module_impl.cc @@ -8,1357 +8,1156 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include "audio_coding_module_impl.h" + +#include +#include +#ifdef ACM_QA_TEST +# include +#endif + #include "acm_codec_database.h" #include "acm_common_defs.h" #include "acm_dtmf_detection.h" #include "acm_generic_codec.h" #include "acm_resampler.h" -#include "audio_coding_module_impl.h" #include "critical_section_wrapper.h" #include "engine_configurations.h" #include "rw_lock_wrapper.h" #include "trace.h" -#include -#include - -#ifdef ACM_QA_TEST -# include -#endif - -#ifdef TIMED_LOGGING - char message[500]; - #include "../test/timedtrace.h" - #include - #define LOGWITHTIME(logString) \ - sprintf(message, logString, _id); \ - _trace.TimedLogg(message); -#else - #define LOGWITHTIME(logString) -#endif - -namespace webrtc -{ +namespace webrtc { enum { - kACMToneEnd = 999 + kACMToneEnd = 999 }; -// Maximum number of bytes in one packet (PCM16B, 20 ms packets, stereo) +// Maximum number of bytes in one packet (PCM16B, 20 ms packets, stereo). enum { - kMaxPacketSize = 2560 + kMaxPacketSize = 2560 }; -AudioCodingModuleImpl::AudioCodingModuleImpl( - const WebRtc_Word32 id): - _packetizationCallback(NULL), - _id(id), - _lastTimestamp(0), - _lastInTimestamp(0), - _cng_nb_pltype(255), - _cng_wb_pltype(255), - _cng_swb_pltype(255), - _red_pltype(255), - _vadEnabled(false), - _dtxEnabled(false), - _vadMode(VADNormal), - _stereoReceiveRegistered(false), - _stereoSend(false), - _prev_received_channel(0), - _expected_channels(1), - _currentSendCodecIdx(-1), // invalid value - _current_receive_codec_idx(-1), // invalid value - _sendCodecRegistered(false), - _acmCritSect(CriticalSectionWrapper::CreateCriticalSection()), - _vadCallback(NULL), - _lastRecvAudioCodecPlType(255), - _isFirstRED(true), - _fecEnabled(false), - _fragmentation(NULL), - _lastFECTimestamp(0), - _receiveREDPayloadType(255), // invalid value - _previousPayloadType(255), - _dummyRTPHeader(NULL), - _recvPlFrameSizeSmpls(0), - _receiverInitialized(false), - _dtmfDetector(NULL), - _dtmfCallback(NULL), - _lastDetectedTone(kACMToneEnd), - _callbackCritSect(CriticalSectionWrapper::CreateCriticalSection()) -{ - _lastTimestamp = 0xD87F3F9F; - _lastInTimestamp = 0xD87F3F9F; +AudioCodingModuleImpl::AudioCodingModuleImpl(const WebRtc_Word32 id) + : _packetizationCallback(NULL), + _id(id), + _lastTimestamp(0), + _lastInTimestamp(0), + _cng_nb_pltype(255), + _cng_wb_pltype(255), + _cng_swb_pltype(255), + _red_pltype(255), + _vadEnabled(false), + _dtxEnabled(false), + _vadMode(VADNormal), + _stereoReceiveRegistered(false), + _stereoSend(false), + _prev_received_channel(0), + _expected_channels(1), + _currentSendCodecIdx(-1), + _current_receive_codec_idx(-1), + _sendCodecRegistered(false), + _acmCritSect(CriticalSectionWrapper::CreateCriticalSection()), + _vadCallback(NULL), + _lastRecvAudioCodecPlType(255), + _isFirstRED(true), + _fecEnabled(false), + _fragmentation(NULL), + _lastFECTimestamp(0), + _receiveREDPayloadType(255), + _previousPayloadType(255), + _dummyRTPHeader(NULL), + _recvPlFrameSizeSmpls(0), + _receiverInitialized(false), + _dtmfDetector(NULL), + _dtmfCallback(NULL), + _lastDetectedTone(kACMToneEnd), + _callbackCritSect(CriticalSectionWrapper::CreateCriticalSection()) { + _lastTimestamp = 0xD87F3F9F; + _lastInTimestamp = 0xD87F3F9F; - // Nullify send codec memory, set payload type and set codec name to - // invalid values. - memset(&_sendCodecInst, 0, sizeof(CodecInst)); - strncpy(_sendCodecInst.plname, "noCodecRegistered", 31); - _sendCodecInst.pltype = -1; + // Nullify send codec memory, set payload type and set codec name to + // invalid values. + memset(&_sendCodecInst, 0, sizeof(CodecInst)); + strncpy(_sendCodecInst.plname, "noCodecRegistered", 31); + _sendCodecInst.pltype = -1; - for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) - { - _codecs[i] = NULL; - _registeredPlTypes[i] = -1; - _stereoReceive[i] = false; - _slaveCodecs[i] = NULL; - _mirrorCodecIdx[i] = -1; + for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) { + _codecs[i] = NULL; + _registeredPlTypes[i] = -1; + _stereoReceive[i] = false; + _slaveCodecs[i] = NULL; + _mirrorCodecIdx[i] = -1; + } + + _netEq.SetUniqueId(_id); + + // Allocate memory for RED. + _redBuffer = new WebRtc_UWord8[MAX_PAYLOAD_SIZE_BYTE]; + _fragmentation = new RTPFragmentationHeader; + _fragmentation->fragmentationVectorSize = 2; + _fragmentation->fragmentationOffset = new WebRtc_UWord32[2]; + _fragmentation->fragmentationLength = new WebRtc_UWord32[2]; + _fragmentation->fragmentationTimeDiff = new WebRtc_UWord16[2]; + _fragmentation->fragmentationPlType = new WebRtc_UWord8[2]; + + // Register the default payload type for RED and for CNG for the three + // frequencies 8, 16 and 32 kHz. + for (int i = (ACMCodecDB::kNumCodecs - 1); i >= 0; i--) { + if (IsCodecRED(i)) { + _red_pltype = static_cast(ACMCodecDB::database_[i].pltype); + } else if (IsCodecCN(i)) { + if (ACMCodecDB::database_[i].plfreq == 8000) { + _cng_nb_pltype = static_cast(ACMCodecDB::database_[i].pltype); + } else if (ACMCodecDB::database_[i].plfreq == 16000) { + _cng_wb_pltype = static_cast(ACMCodecDB::database_[i].pltype); + } else if (ACMCodecDB::database_[i].plfreq == 32000) { + _cng_swb_pltype = static_cast(ACMCodecDB::database_[i].pltype); + } } + } - _netEq.SetUniqueId(_id); - - // Allocate memory for RED - _redBuffer = new WebRtc_UWord8[MAX_PAYLOAD_SIZE_BYTE]; - _fragmentation = new RTPFragmentationHeader; - _fragmentation->fragmentationVectorSize = 2; - _fragmentation->fragmentationOffset = new WebRtc_UWord32[2]; - _fragmentation->fragmentationLength = new WebRtc_UWord32[2]; - _fragmentation->fragmentationTimeDiff = new WebRtc_UWord16[2]; - _fragmentation->fragmentationPlType = new WebRtc_UWord8[2]; - - // Register the default payload type for RED and for - // CNG for the three frequencies 8, 16 and 32 kHz - for (int i = (ACMCodecDB::kNumCodecs - 1); i>=0; i--) - { - if (IsCodecRED(i)) - { - _red_pltype = static_cast(ACMCodecDB::database_[i].pltype); - } - else if (IsCodecCN(i)) - { - if (ACMCodecDB::database_[i].plfreq == 8000) - { - _cng_nb_pltype = - static_cast(ACMCodecDB::database_[i].pltype); - } - else if (ACMCodecDB::database_[i].plfreq == 16000) - { - _cng_wb_pltype = - static_cast(ACMCodecDB::database_[i].pltype); - } else if (ACMCodecDB::database_[i].plfreq == 32000) - { - _cng_swb_pltype = - static_cast(ACMCodecDB::database_[i].pltype); - } - } - } - - if(InitializeReceiverSafe() < 0 ) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot initialize reciever"); - } -#ifdef TIMED_LOGGING - _trace.SetUp("TimedLogg.txt"); + if (InitializeReceiverSafe() < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot initialize reciever"); + } +#ifdef ACM_QA_TEST + char file_name[500]; + sprintf(file_name, "ACM_QA_incomingPL_%03d_%d%d%d%d%d%d.dat", _id, + rand() % 10, rand() % 10, rand() % 10, rand() % 10, rand() % 10, + rand() % 10); + _incomingPL = fopen(file_name, "wb"); + sprintf(file_name, "ACM_QA_outgoingPL_%03d_%d%d%d%d%d%d.dat", _id, + rand() % 10, rand() % 10, rand() % 10, rand() % 10, rand() % 10, + rand() % 10); + _outgoingPL = fopen(file_name, "wb"); #endif + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceAudioCoding, id, "Created"); +} + +AudioCodingModuleImpl::~AudioCodingModuleImpl() { + { + CriticalSectionScoped lock(*_acmCritSect); + _currentSendCodecIdx = -1; + + for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) { + if (_codecs[i] != NULL) { + // True stereo codecs share the same memory for master and + // slave, so slave codec need to be nullified here, since the + // memory will be deleted. + if (_slaveCodecs[i] == _codecs[i]) { + _slaveCodecs[i] = NULL; + } + + // Mirror index holds the address of the codec memory. + assert(_mirrorCodecIdx[i] > -1); + if (_codecs[_mirrorCodecIdx[i]] != NULL) { + delete _codecs[_mirrorCodecIdx[i]]; + _codecs[_mirrorCodecIdx[i]] = NULL; + } + + _codecs[i] = NULL; + } + + if (_slaveCodecs[i] != NULL) { + // Delete memory for stereo usage of mono codecs. + assert(_mirrorCodecIdx[i] > -1); + if (_slaveCodecs[_mirrorCodecIdx[i]] != NULL) { + delete _slaveCodecs[_mirrorCodecIdx[i]]; + _slaveCodecs[_mirrorCodecIdx[i]] = NULL; + } + _slaveCodecs[i] = NULL; + } + } + + if (_dtmfDetector != NULL) { + delete _dtmfDetector; + _dtmfDetector = NULL; + } + if (_dummyRTPHeader != NULL) { + delete _dummyRTPHeader; + _dummyRTPHeader = NULL; + } + if (_redBuffer != NULL) { + delete[] _redBuffer; + _redBuffer = NULL; + } + if (_fragmentation != NULL) { + // Only need to delete fragmentation header, it will clean + // up it's own memory. + delete _fragmentation; + _fragmentation = NULL; + } + } + #ifdef ACM_QA_TEST + if(_incomingPL != NULL) { + fclose(_incomingPL); + } + + if(_outgoingPL != NULL) { + fclose(_outgoingPL); + } +#endif + + delete _callbackCritSect; + _callbackCritSect = NULL; + + delete _acmCritSect; + _acmCritSect = NULL; + WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceAudioCoding, _id, + "Destroyed"); +} + +WebRtc_Word32 AudioCodingModuleImpl::ChangeUniqueId(const WebRtc_Word32 id) { + { + CriticalSectionScoped lock(*_acmCritSect); + _id = id; + +#ifdef ACM_QA_TEST + if (_incomingPL != NULL) { + fclose (_incomingPL); + } + if (_outgoingPL != NULL) { + fclose (_outgoingPL); + } char fileName[500]; - sprintf(fileName, "ACM_QA_incomingPL_%03d_%d%d%d%d%d%d.dat", - _id, - rand() % 10, - rand() % 10, - rand() % 10, - rand() % 10, - rand() % 10, - rand() % 10); - + sprintf(fileName, "ACM_QA_incomingPL_%03d_%d%d%d%d%d%d.dat", _id, + rand() % 10, rand() % 10, rand() % 10, rand() % 10, rand() % 10, + rand() % 10); _incomingPL = fopen(fileName, "wb"); - - sprintf(fileName, "ACM_QA_outgoingPL_%03d_%d%d%d%d%d%d.dat", - _id, - rand() % 10, - rand() % 10, - rand() % 10, - rand() % 10, - rand() % 10, - rand() % 10); + sprintf(fileName, "ACM_QA_outgoingPL_%03d_%d%d%d%d%d%d.dat", _id, + rand() % 10, rand() % 10, rand() % 10, rand() % 10, rand() % 10, + rand() % 10); _outgoingPL = fopen(fileName, "wb"); #endif - WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceAudioCoding, id, "Created"); -} - -AudioCodingModuleImpl::~AudioCodingModuleImpl() -{ - { - CriticalSectionScoped lock(*_acmCritSect); - _currentSendCodecIdx = -1; - - for (int i=0; i < ACMCodecDB::kMaxNumCodecs; i++) - { - if (_codecs[i] != NULL) - { - // True stereo codecs share the same memory for master and - // slave, so slave codec need to be nullified here, since the - // memory will be deleted. - if(_slaveCodecs[i] == _codecs[i]) { - _slaveCodecs[i] = NULL; - } - - // Mirror index holds the address of the codec memory. - assert(_mirrorCodecIdx[i] > -1); - if(_codecs[_mirrorCodecIdx[i]] != NULL) - { - delete _codecs[_mirrorCodecIdx[i]]; - _codecs[_mirrorCodecIdx[i]] = NULL; - } - - _codecs[i] = NULL; - } - - if(_slaveCodecs[i] != NULL) - { - // Delete memory for stereo usage of mono codecs. - assert(_mirrorCodecIdx[i] > -1); - if(_slaveCodecs[_mirrorCodecIdx[i]] != NULL) - { - delete _slaveCodecs[_mirrorCodecIdx[i]]; - _slaveCodecs[_mirrorCodecIdx[i]] = NULL; - } - _slaveCodecs[i] = NULL; - } - } - - if(_dtmfDetector != NULL) - { - delete _dtmfDetector; - _dtmfDetector = NULL; - } - if(_dummyRTPHeader != NULL) - { - delete _dummyRTPHeader; - _dummyRTPHeader = NULL; - } - if(_redBuffer != NULL) - { - delete [] _redBuffer; - _redBuffer = NULL; - } - if(_fragmentation != NULL) - { - // Only need to delete fragmentation header, it will clean - // up it's own memory - delete _fragmentation; - _fragmentation = NULL; - } + for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) { + if (_codecs[i] != NULL) { + _codecs[i]->SetUniqueID(id); + } } + } -#ifdef ACM_QA_TEST - if(_incomingPL != NULL) - { - fclose(_incomingPL); - } - - if(_outgoingPL != NULL) - { - fclose(_outgoingPL); - } -#endif - - delete _callbackCritSect; - _callbackCritSect = NULL; - - delete _acmCritSect; - _acmCritSect = NULL; - WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceAudioCoding, _id, "Destroyed"); + _netEq.SetUniqueId(_id); + return 0; } -WebRtc_Word32 -AudioCodingModuleImpl::ChangeUniqueId( - const WebRtc_Word32 id) -{ - { - CriticalSectionScoped lock(*_acmCritSect); - _id = id; -#ifdef ACM_QA_TEST - if(_incomingPL != NULL) - { - fclose(_incomingPL); - } +// Returns the number of milliseconds until the module want a +// worker thread to call Process. +WebRtc_Word32 AudioCodingModuleImpl::TimeUntilNextProcess() { + CriticalSectionScoped lock(*_acmCritSect); - if(_outgoingPL != NULL) - { - fclose(_outgoingPL); - } - - char fileName[500]; - sprintf(fileName, "ACM_QA_incomingPL_%03d_%d%d%d%d%d%d.dat", - _id, - rand() % 10, - rand() % 10, - rand() % 10, - rand() % 10, - rand() % 10, - rand() % 10); - - _incomingPL = fopen(fileName, "wb"); - - sprintf(fileName, "ACM_QA_outgoingPL_%03d_%d%d%d%d%d%d.dat", - _id, - rand() % 10, - rand() % 10, - rand() % 10, - rand() % 10, - rand() % 10, - rand() % 10); - _outgoingPL = fopen(fileName, "wb"); -#endif - - for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) - { - if(_codecs[i] != NULL) - { - _codecs[i]->SetUniqueID(id); - } - } - } - - _netEq.SetUniqueId(_id); - return 0; + if (!HaveValidEncoder("TimeUntilNextProcess")) { + return -1; + } + return _codecs[_currentSendCodecIdx]->SamplesLeftToEncode() / + (_sendCodecInst.plfreq / 1000); } -// returns the number of milliseconds until the module want a -// worker thread to call Process -WebRtc_Word32 -AudioCodingModuleImpl::TimeUntilNextProcess() -{ +// Process any pending tasks such as timeouts. +WebRtc_Word32 AudioCodingModuleImpl::Process() { + // Make room for 1 RED payload. + WebRtc_UWord8 stream[2 * MAX_PAYLOAD_SIZE_BYTE]; + WebRtc_Word16 length_bytes = 2 * MAX_PAYLOAD_SIZE_BYTE; + WebRtc_Word16 red_length_bytes = length_bytes; + WebRtc_UWord32 rtp_timestamp; + WebRtc_Word16 status; + WebRtcACMEncodingType encoding_type; + FrameType frame_type = kAudioFrameSpeech; + WebRtc_UWord8 current_payload_type = 0; + bool has_data_to_send = false; + bool fec_active = false; + + // Keep the scope of the ACM critical section limited. + { CriticalSectionScoped lock(*_acmCritSect); - - if(!HaveValidEncoder("TimeUntilNextProcess")) - { - return -1; - } - return _codecs[_currentSendCodecIdx]->SamplesLeftToEncode() / - (_sendCodecInst.plfreq / 1000); -} - -// Process any pending tasks such as timeouts -WebRtc_Word32 -AudioCodingModuleImpl::Process() -{ - WebRtc_UWord8 bitStream[2 * MAX_PAYLOAD_SIZE_BYTE]; // Make room for 1 RED payload - WebRtc_Word16 lengthBytes = 2 * MAX_PAYLOAD_SIZE_BYTE; - WebRtc_Word16 redLengthBytes = lengthBytes; - WebRtc_UWord32 rtpTimestamp; - WebRtc_Word16 status; - WebRtcACMEncodingType encodingType; - FrameType frameType = kAudioFrameSpeech; - WebRtc_UWord8 currentPayloadType = 0; - bool hasDataToSend = false; - bool fecActive = false; - - // keep the scope of the ACM critical section limited - { - CriticalSectionScoped lock(*_acmCritSect); - if(!HaveValidEncoder("Process")) - { - return -1; - } - - status = _codecs[_currentSendCodecIdx]->Encode(bitStream, &lengthBytes, - &rtpTimestamp, &encodingType); - if (status < 0) // Encode failed - { - // logging error - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Process(): Encoding Failed"); - lengthBytes = 0; - return -1; - } - else if(status == 0) - { - // Not enough data - return 0; - } - else - { - switch(encodingType) - { - case kNoEncoding: - { - currentPayloadType = _previousPayloadType; - frameType = kFrameEmpty; - lengthBytes = 0; - break; - } - case kActiveNormalEncoded: - case kPassiveNormalEncoded: - { - currentPayloadType = (WebRtc_UWord8)_sendCodecInst.pltype; - frameType = kAudioFrameSpeech; - break; - } - case kPassiveDTXNB: - { - currentPayloadType = _cng_nb_pltype; - frameType = kAudioFrameCN; - _isFirstRED = true; - break; - } - case kPassiveDTXWB: - { - currentPayloadType = _cng_wb_pltype; - frameType = kAudioFrameCN; - _isFirstRED = true; - break; - } - case kPassiveDTXSWB: - { - currentPayloadType = _cng_swb_pltype; - frameType = kAudioFrameCN; - _isFirstRED = true; - break; - } - } - hasDataToSend = true; - _previousPayloadType = currentPayloadType; - - // Redundancy encode is done here, - // the two bitstreams packetized into - // one RTP packet and the fragmentation points - // are set. - // Only apply RED on speech data. - if((_fecEnabled) && - ((encodingType == kActiveNormalEncoded) || - (encodingType == kPassiveNormalEncoded))) - { - // FEC is enabled within this scope. - // - // Note that, a special solution exists for iSAC since it is the only codec for - // which getRedPayload has a non-empty implementation. - // - // Summary of the FEC scheme below (use iSAC as example): - // - // 1st (_firstRED is true) encoded iSAC frame (primary #1) => - // - call getRedPayload() and store redundancy for packet #1 in second - // fragment of RED buffer (old data) - // - drop the primary iSAC frame - // - don't call SendData - // 2nd (_firstRED is false) encoded iSAC frame (primary #2) => - // - store primary #2 in 1st fragment of RED buffer and send the combined - // packet - // - the transmitted packet contains primary #2 (new) and reduncancy for - // packet #1 (old) - // - call getRedPayload() and store redundancy for packet #2 in second - // fragment of RED buffer - // - // ... - // - // Nth encoded iSAC frame (primary #N) => - // - store primary #N in 1st fragment of RED buffer and send the combined - // packet - // - the transmitted packet contains primary #N (new) and reduncancy for - // packet #(N-1) (old) - // - call getRedPayload() and store redundancy for packet #N in second - // fragment of RED buffer - // - // For all other codecs, getRedPayload does nothing and returns -1 => - // redundant data is only a copy. - // - // First combined packet contains : #2 (new) and #1 (old) - // Second combined packet contains: #3 (new) and #2 (old) - // Third combined packet contains : #4 (new) and #3 (old) - // - // Hence, even if every second packet is dropped, perfect reconstruction is - // possible. - fecActive = true; - - hasDataToSend = false; - if(!_isFirstRED) // skip this part for the first packet in a RED session - { - // Rearrange bitStream such that FEC packets are included. - // Replace bitStream now that we have stored current bitStream. - memcpy(bitStream + _fragmentation->fragmentationOffset[1], _redBuffer, - _fragmentation->fragmentationLength[1]); - // Update the fragmentation time difference vector - WebRtc_UWord16 timeSinceLastTimestamp = - WebRtc_UWord16(rtpTimestamp - _lastFECTimestamp); - - // Update fragmentation vectors - _fragmentation->fragmentationPlType[1] = - _fragmentation->fragmentationPlType[0]; - _fragmentation->fragmentationTimeDiff[1] = timeSinceLastTimestamp; - hasDataToSend = true; - } - - // Insert new packet length. - _fragmentation->fragmentationLength[0] = lengthBytes; - - // Insert new packet payload type. - _fragmentation->fragmentationPlType[0] = currentPayloadType; - _lastFECTimestamp = rtpTimestamp; - - // can be modified by the GetRedPayload() call if iSAC is utilized - redLengthBytes = lengthBytes; - // A fragmentation header is provided => packetization according to RFC 2198 - // (RTP Payload for Redundant Audio Data) will be used. - // First fragment is the current data (new). - // Second fragment is the previous data (old). - lengthBytes = - static_cast (_fragmentation->fragmentationLength[0] + - _fragmentation->fragmentationLength[1]); - - // Get, and store, redundant data from the encoder based on the recently - // encoded frame. - // NOTE - only iSAC contains an implementation; all other codecs does nothing - // and returns -1. - if (_codecs[_currentSendCodecIdx]->GetRedPayload(_redBuffer, - &redLengthBytes) == -1) - { - // The codec was not iSAC => use current encoder output as redundant data - // instead (trivial FEC scheme) - memcpy(_redBuffer, bitStream, redLengthBytes); - } - - _isFirstRED = false; - // Update payload type with RED payload type - currentPayloadType = _red_pltype; - } - } + if (!HaveValidEncoder("Process")) { + return -1; } - if(hasDataToSend) - { - CriticalSectionScoped lock(*_callbackCritSect); + status = _codecs[_currentSendCodecIdx]->Encode(stream, &length_bytes, + &rtp_timestamp, + &encoding_type); + if (status < 0) { + // Encode failed. + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Process(): Encoding Failed"); + length_bytes = 0; + return -1; + } else if (status == 0) { + // Not enough data. + return 0; + } else { + switch (encoding_type) { + case kNoEncoding: { + current_payload_type = _previousPayloadType; + frame_type = kFrameEmpty; + length_bytes = 0; + break; + } + case kActiveNormalEncoded: + case kPassiveNormalEncoded: { + current_payload_type = (WebRtc_UWord8) _sendCodecInst.pltype; + frame_type = kAudioFrameSpeech; + break; + } + case kPassiveDTXNB: { + current_payload_type = _cng_nb_pltype; + frame_type = kAudioFrameCN; + _isFirstRED = true; + break; + } + case kPassiveDTXWB: { + current_payload_type = _cng_wb_pltype; + frame_type = kAudioFrameCN; + _isFirstRED = true; + break; + } + case kPassiveDTXSWB: { + current_payload_type = _cng_swb_pltype; + frame_type = kAudioFrameCN; + _isFirstRED = true; + break; + } + } + has_data_to_send = true; + _previousPayloadType = current_payload_type; + + // Redundancy encode is done here. The two bitstreams packetized into + // one RTP packet and the fragmentation points are set. + // Only apply RED on speech data. + if ((_fecEnabled) && + ((encoding_type == kActiveNormalEncoded) || + (encoding_type == kPassiveNormalEncoded))) { + // FEC is enabled within this scope. + // + // Note that, a special solution exists for iSAC since it is the only + // codec for which getRedPayload has a non-empty implementation. + // + // Summary of the FEC scheme below (use iSAC as example): + // + // 1st (_firstRED is true) encoded iSAC frame (primary #1) => + // - call getRedPayload() and store redundancy for packet #1 in + // second fragment of RED buffer (old data) + // - drop the primary iSAC frame + // - don't call SendData + // 2nd (_firstRED is false) encoded iSAC frame (primary #2) => + // - store primary #2 in 1st fragment of RED buffer and send the + // combined packet + // - the transmitted packet contains primary #2 (new) and + // reduncancy for packet #1 (old) + // - call getRedPayload() and store redundancy for packet #2 in + // second fragment of RED buffer + // + // ... + // + // Nth encoded iSAC frame (primary #N) => + // - store primary #N in 1st fragment of RED buffer and send the + // combined packet + // - the transmitted packet contains primary #N (new) and + // reduncancy for packet #(N-1) (old) + // - call getRedPayload() and store redundancy for packet #N in + // second fragment of RED buffer + // + // For all other codecs, getRedPayload does nothing and returns -1 => + // redundant data is only a copy. + // + // First combined packet contains : #2 (new) and #1 (old) + // Second combined packet contains: #3 (new) and #2 (old) + // Third combined packet contains : #4 (new) and #3 (old) + // + // Hence, even if every second packet is dropped, perfect + // reconstruction is possible. + fec_active = true; + + has_data_to_send = false; + // Skip the following part for the first packet in a RED session. + if (!_isFirstRED) { + // Rearrange stream such that FEC packets are included. + // Replace stream now that we have stored current stream. + memcpy(stream + _fragmentation->fragmentationOffset[1], _redBuffer, + _fragmentation->fragmentationLength[1]); + // Update the fragmentation time difference vector, in number of + // timestamps. + WebRtc_UWord16 time_since_last = WebRtc_UWord16( + rtp_timestamp - _lastFECTimestamp); + + // Update fragmentation vectors. + _fragmentation->fragmentationPlType[1] = _fragmentation + ->fragmentationPlType[0]; + _fragmentation->fragmentationTimeDiff[1] = time_since_last; + has_data_to_send = true; + } + + // Insert new packet length. + _fragmentation->fragmentationLength[0] = length_bytes; + + // Insert new packet payload type. + _fragmentation->fragmentationPlType[0] = current_payload_type; + _lastFECTimestamp = rtp_timestamp; + + // Can be modified by the GetRedPayload() call if iSAC is utilized. + red_length_bytes = length_bytes; + + // A fragmentation header is provided => packetization according to + // RFC 2198 (RTP Payload for Redundant Audio Data) will be used. + // First fragment is the current data (new). + // Second fragment is the previous data (old). + length_bytes = static_cast( + _fragmentation->fragmentationLength[0] + + _fragmentation->fragmentationLength[1]); + + // Get, and store, redundant data from the encoder based on the recently + // encoded frame. + // NOTE - only iSAC contains an implementation; all other codecs does + // nothing and returns -1. + if (_codecs[_currentSendCodecIdx]->GetRedPayload( + _redBuffer, + &red_length_bytes) == -1) { + // The codec was not iSAC => use current encoder output as redundant + // data instead (trivial FEC scheme). + memcpy(_redBuffer, stream, red_length_bytes); + } + + _isFirstRED = false; + // Update payload type with RED payload type. + current_payload_type = _red_pltype; + } + } + } + + if (has_data_to_send) { + CriticalSectionScoped lock(*_callbackCritSect); #ifdef ACM_QA_TEST - if(_outgoingPL != NULL) - { - fwrite(&rtpTimestamp, sizeof(WebRtc_UWord32), 1, _outgoingPL); - fwrite(¤tPayloadType, sizeof(WebRtc_UWord8), 1, _outgoingPL); - fwrite(&lengthBytes, sizeof(WebRtc_Word16), 1, _outgoingPL); - } + if(_outgoingPL != NULL) { + fwrite(&rtp_timestamp, sizeof(WebRtc_UWord32), 1, _outgoingPL); + fwrite(¤t_payload_type, sizeof(WebRtc_UWord8), 1, _outgoingPL); + fwrite(&length_bytes, sizeof(WebRtc_Word16), 1, _outgoingPL); + } #endif - if(_packetizationCallback != NULL) - { - if (fecActive) { - _packetizationCallback->SendData(frameType, currentPayloadType, - rtpTimestamp, bitStream, lengthBytes, _fragmentation); - } else { - _packetizationCallback->SendData(frameType, currentPayloadType, - rtpTimestamp, bitStream, lengthBytes, NULL); - } - } + if (_packetizationCallback != NULL) { + if (fec_active) { + // Callback with payload data, including redundant data (FEC/RED). + _packetizationCallback->SendData(frame_type, current_payload_type, + rtp_timestamp, stream, length_bytes, + _fragmentation); + } else { + // Callback with payload data. + _packetizationCallback->SendData(frame_type, current_payload_type, + rtp_timestamp, stream, length_bytes, + NULL); + } + } - // This is for test - if(_vadCallback != NULL) - { - _vadCallback->InFrameType(((WebRtc_Word16)encodingType)); - } + if (_vadCallback != NULL) { + // Callback with VAD decision. + _vadCallback->InFrameType(((WebRtc_Word16) encoding_type)); } - if (fecActive) { - _fragmentation->fragmentationLength[1] = redLengthBytes; - } - return lengthBytes; + } + if (fec_active) { + // Store RED length in bytes. + _fragmentation->fragmentationLength[1] = red_length_bytes; + } + return length_bytes; } - - - ///////////////////////////////////////// // Sender // -// Initialize send codec -WebRtc_Word32 -AudioCodingModuleImpl::InitializeSender() -{ - CriticalSectionScoped lock(*_acmCritSect); +// Initialize send codec. +WebRtc_Word32 AudioCodingModuleImpl::InitializeSender() { + CriticalSectionScoped lock(*_acmCritSect); - _sendCodecRegistered = false; - _currentSendCodecIdx = -1; // invalid value + // Start with invalid values. + _sendCodecRegistered = false; + _currentSendCodecIdx = -1; + _sendCodecInst.plname[0] = '\0'; - _sendCodecInst.plname[0] = '\0'; - - for(int codecCntr = 0; codecCntr < ACMCodecDB::kMaxNumCodecs; codecCntr++) - { - if(_codecs[codecCntr] != NULL) - { - _codecs[codecCntr]->DestructEncoder(); - } - } - // Initialize FEC/RED - _isFirstRED = true; - if(_fecEnabled) - { - if(_redBuffer != NULL) - { - memset(_redBuffer, 0, MAX_PAYLOAD_SIZE_BYTE); - } - if(_fragmentation != NULL) - { - _fragmentation->fragmentationVectorSize = 2; - _fragmentation->fragmentationOffset[0] = 0; - _fragmentation->fragmentationOffset[0] = MAX_PAYLOAD_SIZE_BYTE; - memset(_fragmentation->fragmentationLength, 0, sizeof(WebRtc_UWord32) * 2); - memset(_fragmentation->fragmentationTimeDiff, 0, sizeof(WebRtc_UWord16) * 2); - memset(_fragmentation->fragmentationPlType, 0, sizeof(WebRtc_UWord8) * 2); - } + // Delete all encoders to start fresh. + for (int id = 0; id < ACMCodecDB::kMaxNumCodecs; id++) { + if (_codecs[id] != NULL) { + _codecs[id]->DestructEncoder(); } + } - return 0; + // Initialize FEC/RED. + _isFirstRED = true; + if (_fecEnabled) { + if (_redBuffer != NULL) { + memset(_redBuffer, 0, MAX_PAYLOAD_SIZE_BYTE); + } + if (_fragmentation != NULL) { + _fragmentation->fragmentationVectorSize = 2; + _fragmentation->fragmentationOffset[0] = 0; + _fragmentation->fragmentationOffset[0] = MAX_PAYLOAD_SIZE_BYTE; + memset(_fragmentation->fragmentationLength, 0, + sizeof(WebRtc_UWord32) * 2); + memset(_fragmentation->fragmentationTimeDiff, 0, + sizeof(WebRtc_UWord16) * 2); + memset(_fragmentation->fragmentationPlType, 0, sizeof(WebRtc_UWord8) * 2); + } + } + + return 0; } -WebRtc_Word32 -AudioCodingModuleImpl::ResetEncoder() -{ - CriticalSectionScoped lock(*_acmCritSect); - if(!HaveValidEncoder("ResetEncoder")) - { - return -1; - } - return _codecs[_currentSendCodecIdx]->ResetEncoder(); +WebRtc_Word32 AudioCodingModuleImpl::ResetEncoder() { + CriticalSectionScoped lock(*_acmCritSect); + if (!HaveValidEncoder("ResetEncoder")) { + return -1; + } + return _codecs[_currentSendCodecIdx]->ResetEncoder(); } -void -AudioCodingModuleImpl::UnregisterSendCodec() -{ - CriticalSectionScoped lock(*_acmCritSect); - _sendCodecRegistered = false; - _currentSendCodecIdx = -1; // invalid value - - return; +void AudioCodingModuleImpl::UnregisterSendCodec() { + CriticalSectionScoped lock(*_acmCritSect); + _sendCodecRegistered = false; + _currentSendCodecIdx = -1; + return; } -ACMGenericCodec* -AudioCodingModuleImpl::CreateCodec( - const CodecInst& codec) -{ - ACMGenericCodec* myCodec = NULL; +ACMGenericCodec* AudioCodingModuleImpl::CreateCodec(const CodecInst& codec) { + ACMGenericCodec* my_codec = NULL; - myCodec = ACMCodecDB::CreateCodecInstance(&codec); - if(myCodec == NULL) - { - // Error, could not create the codec + my_codec = ACMCodecDB::CreateCodecInstance(&codec); + if (my_codec == NULL) { + // Error, could not create the codec. + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "ACMCodecDB::CreateCodecInstance() failed in CreateCodec()"); + return my_codec; + } + my_codec->SetUniqueID(_id); + my_codec->SetNetEqDecodeLock(_netEq.DecodeLock()); - // logging error - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "ACMCodecDB::CreateCodecInstance() failed in \ -CreateCodec()"); - return myCodec; - } - myCodec->SetUniqueID(_id); - myCodec->SetNetEqDecodeLock(_netEq.DecodeLock()); - - return myCodec; + return my_codec; } -// can be called multiple times for Codec, CNG, RED -WebRtc_Word32 -AudioCodingModuleImpl::RegisterSendCodec( - const CodecInst& sendCodec) -{ - if((sendCodec.channels != 1) && (sendCodec.channels != 2)) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Registering Send codec failed due to wrong number of channels, %d. Only\ -mono codecs are supported, i.e. channels=1.", sendCodec.channels); - return -1; +// Can be called multiple times for Codec, CNG, RED. +WebRtc_Word32 AudioCodingModuleImpl::RegisterSendCodec( + const CodecInst& send_codec) { + if ((send_codec.channels != 1) && (send_codec.channels != 2)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Registering Send codec failed due to wrong number of " + "channels, %d. Only mono codecs are supported, i.e. " + "channels=1.", send_codec.channels); + return -1; + } + + char error_message[500]; + int mirror_id; + int codec_id = ACMCodecDB::CodecNumber(&send_codec, &mirror_id, error_message, + sizeof(error_message)); + CriticalSectionScoped lock(*_acmCritSect); + + // Check for reported errors from function CodecNumber(). + if (codec_id < 0) { + if (!_sendCodecRegistered) { + // This values has to be NULL if there is no codec registered. + _currentSendCodecIdx = -1; } + // Failed to register Send Codec. + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + error_message); + return -1; + } - char errMsg[500]; - int mirrorId; - int codecID = ACMCodecDB::CodecNumber(&sendCodec, &mirrorId, errMsg, - sizeof(errMsg)); - CriticalSectionScoped lock(*_acmCritSect); - - // Check for reported errors from function CodecNumber() - if(codecID < 0) - { - if(!_sendCodecRegistered) - { - // This values has to be NULL if there is no codec registered - _currentSendCodecIdx = -1; // invalid value - } - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, errMsg); - // Failed to register Send Codec - return -1; - } - - // telephone-event cannot be a send codec - if(!STR_CASE_CMP(sendCodec.plname, "telephone-event")) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "telephone-event cannot be registered as send codec"); - return -1; - } - - // RED can be registered with other payload type. If not registered a default - // payload type is used. - if (IsCodecRED(sendCodec)) - { - // TODO(tlegrand): Remove this check. Already taken care of in - // ACMCodecDB::CodecNumber(). - // Check if the payload-type is valid - if(!ACMCodecDB::ValidPayloadType(sendCodec.pltype)) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Invalid payload-type %d for %s.", - sendCodec.pltype, sendCodec.plname); - return -1; - } - // Set RED payload type - _red_pltype = static_cast(sendCodec.pltype); - return 0; - } - - // CNG can be registered with other payload type. If not registered the - // default payload types from codec database will be used. - if (IsCodecCN(sendCodec)) - { - // CNG is registered - switch(sendCodec.plfreq) - { - case 8000: - { - _cng_nb_pltype = static_cast(sendCodec.pltype); - break; - } - case 16000: - { - _cng_wb_pltype = static_cast(sendCodec.pltype); - break; - } - case 32000: - { - _cng_swb_pltype = static_cast(sendCodec.pltype); - break; - } - default : - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "RegisterSendCodec() failed, invalid frequency for CNG registeration"); - return -1; - } - } - - return 0; - } + // Telephone-event cannot be a send codec. + if (!STR_CASE_CMP(send_codec.plname, "telephone-event")) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "telephone-event cannot be registered as send codec"); + return -1; + } + // RED can be registered with other payload type. If not registered a default + // payload type is used. + if (IsCodecRED(send_codec)) { // TODO(tlegrand): Remove this check. Already taken care of in // ACMCodecDB::CodecNumber(). // Check if the payload-type is valid - if(!ACMCodecDB::ValidPayloadType(sendCodec.pltype)) - { + if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Invalid payload-type %d for %s.", send_codec.pltype, + send_codec.plname); + return -1; + } + // Set RED payload type. + _red_pltype = static_cast(send_codec.pltype); + return 0; + } + + // CNG can be registered with other payload type. If not registered the + // default payload types from codec database will be used. + if (IsCodecCN(send_codec)) { + // CNG is registered. + switch (send_codec.plfreq) { + case 8000: { + _cng_nb_pltype = static_cast(send_codec.pltype); + break; + } + case 16000: { + _cng_wb_pltype = static_cast(send_codec.pltype); + break; + } + case 32000: { + _cng_swb_pltype = static_cast(send_codec.pltype); + break; + } + default: { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Invalid payload-type %d for %s.", - sendCodec.pltype, sendCodec.plname); + "RegisterSendCodec() failed, invalid frequency for CNG " + "registration"); return -1; + } } - // Check if codec supports the number of channels - if(ACMCodecDB::codec_settings_[codecID].channel_support < sendCodec.channels) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "%d number of channels not supportedn for %s.", - sendCodec.channels, sendCodec.plname); - return -1; - } - - // Set Stereo - if (sendCodec.channels == 2) - { - _stereoSend = true; - } - - // check if the codec is already registered as send codec - bool oldCodecFamily; - if(_sendCodecRegistered) - { - int sendCodecMirrorID; - int sendCodecID = - ACMCodecDB::CodecNumber(&_sendCodecInst, &sendCodecMirrorID); - assert(sendCodecID >= 0); - oldCodecFamily = (sendCodecID == codecID) || (mirrorId == sendCodecMirrorID); - } - else - { - oldCodecFamily = false; - } - - // If new codec, register - if (!oldCodecFamily) - { - if(_codecs[mirrorId] == NULL) - { - - _codecs[mirrorId] = CreateCodec(sendCodec); - if(_codecs[mirrorId] == NULL) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot Create the codec"); - return -1; - } - _mirrorCodecIdx[mirrorId] = mirrorId; - } - - if(mirrorId != codecID) - { - _codecs[codecID] = _codecs[mirrorId]; - _mirrorCodecIdx[codecID] = mirrorId; - } - - ACMGenericCodec* tmpCodecPtr = _codecs[codecID]; - WebRtc_Word16 status; - WebRtcACMCodecParams codecParams; - - memcpy(&(codecParams.codecInstant), &sendCodec, - sizeof(CodecInst)); - codecParams.enableVAD = _vadEnabled; - codecParams.enableDTX = _dtxEnabled; - codecParams.vadMode = _vadMode; - // force initialization - status = tmpCodecPtr->InitEncoder(&codecParams, true); - - // Check if VAD was turned on, or if error is reported - if (status == 1) { - _vadEnabled = true; - } else if (status < 0) - { - // could not initialize the encoder - - // Check if already have a registered codec - // Depending on that different messages are logged - if(!_sendCodecRegistered) - { - _currentSendCodecIdx = -1; // invalid value - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot Initialize the encoder No Encoder is registered"); - } - else - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot Initialize the encoder, continue encoding \ -with the previously registered codec"); - } - return -1; - } - - // Everything is fine so we can replace the previous codec - // with this one - if(_sendCodecRegistered) - { - // If we change codec we start fresh with FEC. - // This is not strictly required by the standard. - _isFirstRED = true; - - if(tmpCodecPtr->SetVAD(_dtxEnabled, _vadEnabled, _vadMode) < 0){ - // SetVAD failed - _vadEnabled = false; - _dtxEnabled = false; - } - - } - - _currentSendCodecIdx = codecID; - _sendCodecRegistered = true; - memcpy(&_sendCodecInst, &sendCodec, sizeof(CodecInst)); - _previousPayloadType = _sendCodecInst.pltype; - return 0; - } - else - { - // If codec is the same as already registers check if any parameters - // has changed compared to the current values. - // If any parameter is valid then apply it and record. - bool forceInit = false; - - if(mirrorId != codecID) - { - _codecs[codecID] = _codecs[mirrorId]; - _mirrorCodecIdx[codecID] = mirrorId; - } - - // check the payload-type - if(sendCodec.pltype != _sendCodecInst.pltype) - { - // At this point check if the given payload type is valid. - // Record it later when the sampling frequency is changed - // successfully. - if(!ACMCodecDB::ValidPayloadType(sendCodec.pltype)) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Out of range payload type"); - return -1; - } - - } - - // If there is a codec that ONE instance of codec supports multiple - // sampling frequencies, then we need to take care of it here. - // one such a codec is iSAC. Both WB and SWB are encoded and decoded - // with one iSAC instance. Therefore, we need to update the encoder - // frequency if required. - if(_sendCodecInst.plfreq != sendCodec.plfreq) - { - forceInit = true; - - // if sampling frequency is changed we have to start fresh with RED. - _isFirstRED = true; - } - - // If packet size or number of channels has changed, we need to - // re-initialize the encoder. - if(_sendCodecInst.pacsize != sendCodec.pacsize) - { - forceInit = true; - } - if(_sendCodecInst.channels != sendCodec.channels) - { - forceInit = true; - } - - if(forceInit) - { - WebRtcACMCodecParams codecParams; - - memcpy(&(codecParams.codecInstant), &sendCodec, - sizeof(CodecInst)); - codecParams.enableVAD = _vadEnabled; - codecParams.enableDTX = _dtxEnabled; - codecParams.vadMode = _vadMode; - - // force initialization - if(_codecs[_currentSendCodecIdx]->InitEncoder(&codecParams, true) < 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Could not change the codec packet-size."); - return -1; - } - - _sendCodecInst.plfreq = sendCodec.plfreq; - _sendCodecInst.pacsize = sendCodec.pacsize; - _sendCodecInst.channels = sendCodec.channels; - } - - // If the change of sampling frequency has been successful then - // we store the payload-type. - _sendCodecInst.pltype = sendCodec.pltype; - - // check if a change in Rate is required - if(sendCodec.rate != _sendCodecInst.rate) - { - if(_codecs[codecID]->SetBitRate(sendCodec.rate) < 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Could not change the codec rate."); - return -1; - } - _sendCodecInst.rate = sendCodec.rate; - } - _previousPayloadType = _sendCodecInst.pltype; - - return 0; - } -} - -// get current send codec -WebRtc_Word32 -AudioCodingModuleImpl::SendCodec( - CodecInst& currentSendCodec) const -{ - WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, - "SendCodec()"); - CriticalSectionScoped lock(*_acmCritSect); - - if(!_sendCodecRegistered) - { - WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, - "SendCodec Failed, no codec is registered"); - - return -1; - } - WebRtcACMCodecParams encoderParam; - _codecs[_currentSendCodecIdx]->EncoderParams(&encoderParam); - encoderParam.codecInstant.pltype = _sendCodecInst.pltype; - memcpy(¤tSendCodec, &(encoderParam.codecInstant), - sizeof(CodecInst)); - return 0; -} + } -// get current send freq -WebRtc_Word32 -AudioCodingModuleImpl::SendFrequency() const -{ - WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, - "SendFrequency()"); - CriticalSectionScoped lock(*_acmCritSect); - - if(!_sendCodecRegistered) - { - WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, - "SendFrequency Failed, no codec is registered"); - - return -1; - } - - return _sendCodecInst.plfreq; -} - -// Get encode bitrate -// Adaptive rate codecs return their current encode target rate, while other codecs -// return there longterm avarage or their fixed rate. -WebRtc_Word32 -AudioCodingModuleImpl::SendBitrate() const -{ - CriticalSectionScoped lock(*_acmCritSect); - - if(!_sendCodecRegistered) - { - WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, - "SendBitrate Failed, no codec is registered"); - - return -1; - } - - WebRtcACMCodecParams encoderParam; - _codecs[_currentSendCodecIdx]->EncoderParams(&encoderParam); - - return encoderParam.codecInstant.rate; -} - -// set available bandwidth, inform the encoder about the estimated bandwidth -// received from the remote party -WebRtc_Word32 -AudioCodingModuleImpl::SetReceivedEstimatedBandwidth( - const WebRtc_Word32 bw ) -{ - return _codecs[_currentSendCodecIdx]->SetEstimatedBandwidth(bw); -} - -// register a transport callback wich will be called to deliver -// the encoded buffers -WebRtc_Word32 -AudioCodingModuleImpl::RegisterTransportCallback( - AudioPacketizationCallback* transport) -{ - CriticalSectionScoped lock(*_callbackCritSect); - _packetizationCallback = transport; - return 0; -} - -// Used by the module to deliver messages to the codec module/appliation -// AVT(DTMF) -WebRtc_Word32 -AudioCodingModuleImpl::RegisterIncomingMessagesCallback( -#ifndef WEBRTC_DTMF_DETECTION - AudioCodingFeedback* /* incomingMessagesCallback */, - const ACMCountries /* cpt */) -{ + // TODO(tlegrand): Remove this check. Already taken care of in + // ACMCodecDB::CodecNumber(). + // Check if the payload-type is valid + if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Invalid payload-type %d for %s.", send_codec.pltype, + send_codec.plname); return -1; + } + + // Check if codec supports the number of channels. + if (ACMCodecDB::codec_settings_[codec_id].channel_support + < send_codec.channels) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "%d number of channels not supportedn for %s.", + send_codec.channels, send_codec.plname); + return -1; + } + + // Set Stereo. + if (send_codec.channels == 2) { + _stereoSend = true; + } + + // Check if the codec is already registered as send codec. + bool is_send_codec; + if (_sendCodecRegistered) { + int send_codec_mirror_id; + int send_codec_id = ACMCodecDB::CodecNumber(&_sendCodecInst, + &send_codec_mirror_id); + assert(send_codec_id >= 0); + is_send_codec = (send_codec_id == codec_id) || + (mirror_id == send_codec_mirror_id); + } else { + is_send_codec = false; + } + + // If new codec, or new settings, register. + if (!is_send_codec) { + if (_codecs[mirror_id] == NULL) { + + _codecs[mirror_id] = CreateCodec(send_codec); + if (_codecs[mirror_id] == NULL) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot Create the codec"); + return -1; + } + _mirrorCodecIdx[mirror_id] = mirror_id; + } + + if (mirror_id != codec_id) { + _codecs[codec_id] = _codecs[mirror_id]; + _mirrorCodecIdx[codec_id] = mirror_id; + } + + ACMGenericCodec* codec_ptr = _codecs[codec_id]; + WebRtc_Word16 status; + WebRtcACMCodecParams codec_params; + + memcpy(&(codec_params.codecInstant), &send_codec, sizeof(CodecInst)); + codec_params.enableVAD = _vadEnabled; + codec_params.enableDTX = _dtxEnabled; + codec_params.vadMode = _vadMode; + // Force initialization. + status = codec_ptr->InitEncoder(&codec_params, true); + + // Check if VAD was turned on, or if error is reported. + if (status == 1) { + _vadEnabled = true; + } else if (status < 0) { + // Could not initialize the encoder. + + // Check if already have a registered codec. + // Depending on that different messages are logged. + if (!_sendCodecRegistered) { + _currentSendCodecIdx = -1; + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot Initialize the encoder No Encoder is registered"); + } else { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot Initialize the encoder, continue encoding with " + "the previously registered codec"); + } + return -1; + } + + // Everything is fine so we can replace the previous codec with this one. + if (_sendCodecRegistered) { + // If we change codec we start fresh with FEC. + // This is not strictly required by the standard. + _isFirstRED = true; + + if (codec_ptr->SetVAD(_dtxEnabled, _vadEnabled, _vadMode) < 0) { + // SetVAD failed. + _vadEnabled = false; + _dtxEnabled = false; + } + } + + _currentSendCodecIdx = codec_id; + _sendCodecRegistered = true; + memcpy(&_sendCodecInst, &send_codec, sizeof(CodecInst)); + _previousPayloadType = _sendCodecInst.pltype; + return 0; + } else { + // If codec is the same as already registered check if any parameters + // has changed compared to the current values. + // If any parameter is valid then apply it and record. + bool force_init = false; + + if (mirror_id != codec_id) { + _codecs[codec_id] = _codecs[mirror_id]; + _mirrorCodecIdx[codec_id] = mirror_id; + } + + // Check the payload type. + if (send_codec.pltype != _sendCodecInst.pltype) { + // At this point check if the given payload type is valid. + // Record it later when the sampling frequency is changed + // successfully. + if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Out of range payload type"); + return -1; + } + } + + // If there is a codec that ONE instance of codec supports multiple + // sampling frequencies, then we need to take care of it here. + // one such a codec is iSAC. Both WB and SWB are encoded and decoded + // with one iSAC instance. Therefore, we need to update the encoder + // frequency if required. + if (_sendCodecInst.plfreq != send_codec.plfreq) { + force_init = true; + + // If sampling frequency is changed we have to start fresh with RED. + _isFirstRED = true; + } + + // If packet size or number of channels has changed, we need to + // re-initialize the encoder. + if (_sendCodecInst.pacsize != send_codec.pacsize) { + force_init = true; + } + if (_sendCodecInst.channels != send_codec.channels) { + force_init = true; + } + + if (force_init) { + WebRtcACMCodecParams codec_params; + + memcpy(&(codec_params.codecInstant), &send_codec, sizeof(CodecInst)); + codec_params.enableVAD = _vadEnabled; + codec_params.enableDTX = _dtxEnabled; + codec_params.vadMode = _vadMode; + + // Force initialization. + if (_codecs[_currentSendCodecIdx]->InitEncoder(&codec_params, true) < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Could not change the codec packet-size."); + return -1; + } + + _sendCodecInst.plfreq = send_codec.plfreq; + _sendCodecInst.pacsize = send_codec.pacsize; + _sendCodecInst.channels = send_codec.channels; + } + + // If the change of sampling frequency has been successful then + // we store the payload-type. + _sendCodecInst.pltype = send_codec.pltype; + + // Check if a change in Rate is required. + if (send_codec.rate != _sendCodecInst.rate) { + if (_codecs[codec_id]->SetBitRate(send_codec.rate) < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Could not change the codec rate."); + return -1; + } + _sendCodecInst.rate = send_codec.rate; + } + _previousPayloadType = _sendCodecInst.pltype; + + return 0; + } +} + +// Get current send codec. +WebRtc_Word32 AudioCodingModuleImpl::SendCodec( + CodecInst& current_codec) const { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, + "SendCodec()"); + CriticalSectionScoped lock(*_acmCritSect); + + if (!_sendCodecRegistered) { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, + "SendCodec Failed, no codec is registered"); + + return -1; + } + WebRtcACMCodecParams encoder_param; + _codecs[_currentSendCodecIdx]->EncoderParams(&encoder_param); + encoder_param.codecInstant.pltype = _sendCodecInst.pltype; + memcpy(¤t_codec, &(encoder_param.codecInstant), sizeof(CodecInst)); + + return 0; +} + +// Get current send frequency. +WebRtc_Word32 AudioCodingModuleImpl::SendFrequency() const { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, + "SendFrequency()"); + CriticalSectionScoped lock(*_acmCritSect); + + if (!_sendCodecRegistered) { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, + "SendFrequency Failed, no codec is registered"); + + return -1; + } + + return _sendCodecInst.plfreq; +} + +// Get encode bitrate. +// Adaptive rate codecs return their current encode target rate, while other +// codecs return there longterm avarage or their fixed rate. +WebRtc_Word32 AudioCodingModuleImpl::SendBitrate() const { + CriticalSectionScoped lock(*_acmCritSect); + + if (!_sendCodecRegistered) { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, + "SendBitrate Failed, no codec is registered"); + + return -1; + } + + WebRtcACMCodecParams encoder_param; + _codecs[_currentSendCodecIdx]->EncoderParams(&encoder_param); + + return encoder_param.codecInstant.rate; +} + +// Set available bandwidth, inform the encoder about the estimated bandwidth +// received from the remote party. +WebRtc_Word32 AudioCodingModuleImpl::SetReceivedEstimatedBandwidth( + const WebRtc_Word32 bw) { + return _codecs[_currentSendCodecIdx]->SetEstimatedBandwidth(bw); +} + +// Register a transport callback which will be called to deliver +// the encoded buffers. +WebRtc_Word32 AudioCodingModuleImpl::RegisterTransportCallback( + AudioPacketizationCallback* transport) { + CriticalSectionScoped lock(*_callbackCritSect); + _packetizationCallback = transport; + return 0; +} + +// Used by the module to deliver messages to the codec module/application +// AVT(DTMF). +WebRtc_Word32 AudioCodingModuleImpl::RegisterIncomingMessagesCallback( +#ifndef WEBRTC_DTMF_DETECTION + AudioCodingFeedback* /* incoming_message */, + const ACMCountries /* cpt */) { + return -1; #else - AudioCodingFeedback* incomingMessagesCallback, - const ACMCountries cpt) -{ - WebRtc_Word16 status = 0; + AudioCodingFeedback* incoming_message, + const ACMCountries cpt) { + WebRtc_Word16 status = 0; - // Enter the critical section for callback - { - CriticalSectionScoped lock(*_callbackCritSect); - _dtmfCallback = incomingMessagesCallback; - } - // enter the ACM critical section to set up the DTMF class. - { - CriticalSectionScoped lock(*_acmCritSect); - // Check if the call is to disable or enable the callback - if(incomingMessagesCallback == NULL) - { - // callback is disabled, delete DTMF-detector class - if(_dtmfDetector != NULL) - { - delete _dtmfDetector; - _dtmfDetector = NULL; - } - status = 0; + // Enter the critical section for callback. + { + CriticalSectionScoped lock(*_callbackCritSect); + _dtmfCallback = incoming_message; + } + // Enter the ACM critical section to set up the DTMF class. + { + CriticalSectionScoped lock(*_acmCritSect); + // Check if the call is to disable or enable the callback. + if (incoming_message == NULL) { + // Callback is disabled, delete DTMF-detector class. + if (_dtmfDetector != NULL) { + delete _dtmfDetector; + _dtmfDetector = NULL; + } + status = 0; + } else { + status = 0; + if (_dtmfDetector == NULL) { + _dtmfDetector = new (ACMDTMFDetection); + if (_dtmfDetector == NULL) { + status = -1; } - else - { - status = 0; - if(_dtmfDetector == NULL) - { - _dtmfDetector = new(ACMDTMFDetection); - if(_dtmfDetector == NULL) - { - status = -1; - } - } - if(status >= 0) - { - status = _dtmfDetector->Enable(cpt); - if(status < 0) - { - // failed to initialize if DTMF-detection was not enabled before, - // delete the class, and set the callback to NULL and return -1. - delete _dtmfDetector; - _dtmfDetector = NULL; - } - } + } + if (status >= 0) { + status = _dtmfDetector->Enable(cpt); + if (status < 0) { + // Failed to initialize if DTMF-detection was not enabled before, + // delete the class, and set the callback to NULL and return -1. + delete _dtmfDetector; + _dtmfDetector = NULL; } + } } - // check if we failed in setting up the DTMF-detector class - if((status < 0)) - { - // we failed, we cannot have the callback - CriticalSectionScoped lock(*_callbackCritSect); - _dtmfCallback = NULL; - } + } + // Check if we failed in setting up the DTMF-detector class. + if ((status < 0)) { + // We failed, we cannot have the callback. + CriticalSectionScoped lock(*_callbackCritSect); + _dtmfCallback = NULL; + } - return status; + return status; #endif } +// Add 10MS of raw (PCM) audio data to the encoder. +WebRtc_Word32 AudioCodingModuleImpl::Add10MsData( + const AudioFrame& audio_frame) { + // Do we have a codec registered? + CriticalSectionScoped lock(*_acmCritSect); + if (!HaveValidEncoder("Add10MsData")) { + return -1; + } -// Add 10MS of raw (PCM) audio data to the encoder -WebRtc_Word32 -AudioCodingModuleImpl::Add10MsData( - const AudioFrame& audioFrame) -{ - // Do we have a codec registered? - CriticalSectionScoped lock(*_acmCritSect); - if(!HaveValidEncoder("Add10MsData")) - { - return -1; - } + if (audio_frame._payloadDataLengthInSamples == 0) { + assert(false); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot Add 10 ms audio, payload length is zero"); + return -1; + } + // Allow for 8, 16, 32 and 48kHz input audio. + if ((audio_frame._frequencyInHz != 8000) + && (audio_frame._frequencyInHz != 16000) + && (audio_frame._frequencyInHz != 32000) + && (audio_frame._frequencyInHz != 48000)) { + assert(false); + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot Add 10 ms audio, input frequency not valid"); + return -1; + } - if(audioFrame._payloadDataLengthInSamples == 0) - { - assert(false); - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot Add 10 ms audio, payload length is zero"); - return -1; - } - // Allow for 8, 16, 32 and 48kHz input audio - if((audioFrame._frequencyInHz != 8000) && - (audioFrame._frequencyInHz != 16000) && - (audioFrame._frequencyInHz != 32000) && - (audioFrame._frequencyInHz != 48000)) - { - assert(false); - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot Add 10 ms audio, input frequency not valid"); - return -1; - } + // If the length and frequency matches. We currently just support raw PCM. + if ((audio_frame._frequencyInHz / 100) + != audio_frame._payloadDataLengthInSamples) { + WEBRTC_TRACE( + webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot Add 10 ms audio, input frequency and length doesn't match"); + return -1; + } + // Calculate the timestamp that should be pushed to codec. + // This might be different from the timestamp of the frame + // due to re-sampling. + bool resample = ((WebRtc_Word32) audio_frame._frequencyInHz + != _sendCodecInst.plfreq); - // If the length and frequency matches. We currently just support raw PCM - if((audioFrame._frequencyInHz/ 100) != - audioFrame._payloadDataLengthInSamples) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot Add 10 ms audio, input frequency and length doesn't \ -match"); - return -1; - } - - // Calculate the timestamp that should be pushed to codec. - // This might be different from the timestamp of the frame - // due to re-sampling - bool resamplingRequired = - ((WebRtc_Word32)audioFrame._frequencyInHz != _sendCodecInst.plfreq); - - // If number of channels in audio doesn't match codec mode, we need - // either mono-to-stereo or stereo-to-mono conversion. - WebRtc_Word16 audio[WEBRTC_10MS_PCM_AUDIO]; - int audio_channels = _sendCodecInst.channels; - if (audioFrame._audioChannel != _sendCodecInst.channels) { - if (_sendCodecInst.channels == 2) { - // Do mono-to-stereo conversion by copying each sample. - for (int k = 0; k < audioFrame._payloadDataLengthInSamples; k++) { - audio[k * 2] = audioFrame._payloadData[k]; - audio[(k * 2) + 1] = audioFrame._payloadData[k]; - } - } else if (_sendCodecInst.channels == 1) { - // Do stereo-to-mono conversion by creating the average of the stereo - // samples. - for (int k = 0; k < audioFrame._payloadDataLengthInSamples; k++) { - audio[k] = (audioFrame._payloadData[k * 2] + - audioFrame._payloadData[(k * 2) + 1]) >> 1; - } + // If number of channels in audio doesn't match codec mode, we need + // either mono-to-stereo or stereo-to-mono conversion. + WebRtc_Word16 audio[WEBRTC_10MS_PCM_AUDIO]; + int audio_channels = _sendCodecInst.channels; + if (audio_frame._audioChannel != _sendCodecInst.channels) { + if (_sendCodecInst.channels == 2) { + // Do mono-to-stereo conversion by copying each sample. + for (int k = 0; k < audio_frame._payloadDataLengthInSamples; k++) { + audio[k * 2] = audio_frame._payloadData[k]; + audio[(k * 2) + 1] = audio_frame._payloadData[k]; } + } else if (_sendCodecInst.channels == 1) { + // Do stereo-to-mono conversion by creating the average of the stereo + // samples. + for (int k = 0; k < audio_frame._payloadDataLengthInSamples; k++) { + audio[k] = (audio_frame._payloadData[k * 2] + + audio_frame._payloadData[(k * 2) + 1]) >> 1; + } + } + } else { + // Copy payload data for future use. + size_t length = static_cast(audio_frame._payloadDataLengthInSamples + * audio_channels); + memcpy(audio, audio_frame._payloadData, length * sizeof(WebRtc_UWord16)); + } + + WebRtc_UWord32 current_timestamp; + WebRtc_Word32 status; + // If it is required, we have to do a resampling. + if (resample) { + WebRtc_Word16 resampled_audio[WEBRTC_10MS_PCM_AUDIO]; + WebRtc_Word32 send_freq = _sendCodecInst.plfreq; + WebRtc_UWord32 timestamp_diff; + WebRtc_Word16 new_length; + + // Calculate the timestamp of this frame. + if (_lastInTimestamp > audio_frame._timeStamp) { + // A wrap around has happened. + timestamp_diff = ((WebRtc_UWord32) 0xFFFFFFFF - _lastInTimestamp) + + audio_frame._timeStamp; } else { - // Copy payload data for future use. - size_t length = static_cast( - audioFrame._payloadDataLengthInSamples * audio_channels); - memcpy(audio, audioFrame._payloadData, length * sizeof(WebRtc_UWord16)); + timestamp_diff = audio_frame._timeStamp - _lastInTimestamp; } + current_timestamp = _lastTimestamp + (WebRtc_UWord32)(timestamp_diff * + ((double) _sendCodecInst.plfreq / (double) audio_frame._frequencyInHz)); - WebRtc_UWord32 currentTimestamp; - WebRtc_Word32 status; - // if it is required, we have to do a resampling. - if(resamplingRequired) - { - WebRtc_Word16 resampledAudio[WEBRTC_10MS_PCM_AUDIO]; - WebRtc_Word32 sendPlFreq = _sendCodecInst.plfreq; - WebRtc_UWord32 diffInputTimestamp; - WebRtc_Word16 newLengthSmpl; + new_length = _inputResampler.Resample10Msec(audio, + audio_frame._frequencyInHz, + resampled_audio, send_freq, + audio_channels); - // calculate the timestamp of this frame - if(_lastInTimestamp > audioFrame._timeStamp) - { - // a wrap around has happened - diffInputTimestamp = ((WebRtc_UWord32)0xFFFFFFFF - _lastInTimestamp) - + audioFrame._timeStamp; - } - else - { - diffInputTimestamp = audioFrame._timeStamp - _lastInTimestamp; - } - currentTimestamp = _lastTimestamp + (WebRtc_UWord32)(diffInputTimestamp * - ((double)_sendCodecInst.plfreq / (double)audioFrame._frequencyInHz)); - - newLengthSmpl = _inputResampler.Resample10Msec( - audio, audioFrame._frequencyInHz, resampledAudio, sendPlFreq, - audio_channels); - - if(newLengthSmpl < 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot add 10 ms audio, resmapling failed"); - return -1; - } - status = _codecs[_currentSendCodecIdx]->Add10MsData(currentTimestamp, - resampledAudio, newLengthSmpl, audio_channels); + if (new_length < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot add 10 ms audio, resmapling failed"); + return -1; } - else - { - currentTimestamp = audioFrame._timeStamp; + status = _codecs[_currentSendCodecIdx]->Add10MsData(current_timestamp, + resampled_audio, + new_length, + audio_channels); + } else { + current_timestamp = audio_frame._timeStamp; - status = _codecs[_currentSendCodecIdx]->Add10MsData(currentTimestamp, - audio, audioFrame._payloadDataLengthInSamples, - audio_channels); - } - _lastInTimestamp = audioFrame._timeStamp; - _lastTimestamp = currentTimestamp; - return status; + status = _codecs[_currentSendCodecIdx]->Add10MsData( + current_timestamp, audio, audio_frame._payloadDataLengthInSamples, + audio_channels); + } + _lastInTimestamp = audio_frame._timeStamp; + _lastTimestamp = current_timestamp; + return status; } ///////////////////////////////////////// // (FEC) Forward Error Correction // -bool -AudioCodingModuleImpl::FECStatus() const -{ - CriticalSectionScoped lock(*_acmCritSect); - return _fecEnabled; +bool AudioCodingModuleImpl::FECStatus() const { + CriticalSectionScoped lock(*_acmCritSect); + return _fecEnabled; } -// configure FEC status i.e on/off +// Configure FEC status i.e on/off. WebRtc_Word32 AudioCodingModuleImpl::SetFECStatus( #ifdef WEBRTC_CODEC_RED - const bool enableFEC) -{ - CriticalSectionScoped lock(*_acmCritSect); + const bool enable_fec) { + CriticalSectionScoped lock(*_acmCritSect); - if (_fecEnabled != enableFEC) - { - // Reset the RED buffer - memset(_redBuffer, 0, MAX_PAYLOAD_SIZE_BYTE); + if (_fecEnabled != enable_fec) { + // Reset the RED buffer. + memset(_redBuffer, 0, MAX_PAYLOAD_SIZE_BYTE); - // Reset fragmentation buffers - _fragmentation->fragmentationVectorSize = 2; - _fragmentation->fragmentationOffset[0] = 0; - _fragmentation->fragmentationOffset[1] = MAX_PAYLOAD_SIZE_BYTE; - memset(_fragmentation->fragmentationLength, 0, sizeof(WebRtc_UWord32) * 2); - memset(_fragmentation->fragmentationTimeDiff, 0, sizeof(WebRtc_UWord16) * 2); - memset(_fragmentation->fragmentationPlType, 0, sizeof(WebRtc_UWord8) * 2); + // Reset fragmentation buffers. + _fragmentation->fragmentationVectorSize = 2; + _fragmentation->fragmentationOffset[0] = 0; + _fragmentation->fragmentationOffset[1] = MAX_PAYLOAD_SIZE_BYTE; + memset(_fragmentation->fragmentationLength, 0, sizeof(WebRtc_UWord32) * 2); + memset(_fragmentation->fragmentationTimeDiff, 0, + sizeof(WebRtc_UWord16) * 2); + memset(_fragmentation->fragmentationPlType, 0, sizeof(WebRtc_UWord8) * 2); - // set _fecEnabled - _fecEnabled = enableFEC; - } - _isFirstRED = true; // Make sure we restart FEC - return 0; + // Set _fecEnabled. + _fecEnabled = enable_fec; + } + _isFirstRED = true; // Make sure we restart FEC. + return 0; #else - const bool /* enableFEC */) -{ - _fecEnabled = false; - WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, _id, - " WEBRTC_CODEC_RED is undefined => _fecEnabled = %d", _fecEnabled); - return -1; + const bool /* enable_fec */) { + _fecEnabled = false; + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, _id, + " WEBRTC_CODEC_RED is undefined => _fecEnabled = %d", + _fecEnabled); + return -1; #endif } - ///////////////////////////////////////// // (VAD) Voice Activity Detection // -WebRtc_Word32 -AudioCodingModuleImpl::SetVAD( - const bool enableDTX, - const bool enableVAD, - const ACMVADMode vadMode) -{ - CriticalSectionScoped lock(*_acmCritSect); +WebRtc_Word32 AudioCodingModuleImpl::SetVAD(const bool enable_dtx, + const bool enable_vad, + const ACMVADMode mode) { + CriticalSectionScoped lock(*_acmCritSect); - // sanity check of the mode - if((vadMode != VADNormal) && - (vadMode != VADLowBitrate) && - (vadMode != VADAggr) && - (vadMode != VADVeryAggr)) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Invalid VAD Mode %d, no change is made to VAD/DTX status", - (int)vadMode); - return -1; + // Sanity check of the mode. + if ((mode != VADNormal) && (mode != VADLowBitrate) + && (mode != VADAggr) && (mode != VADVeryAggr)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Invalid VAD Mode %d, no change is made to VAD/DTX status", + (int) mode); + return -1; + } + + // If a send codec is registered, set VAD/DTX for the codec. + if (HaveValidEncoder("SetVAD")) { + WebRtc_Word16 status = _codecs[_currentSendCodecIdx]->SetVAD(enable_dtx, + enable_vad, + mode); + if (status == 1) { + // Vad was enabled. + _vadEnabled = true; + _dtxEnabled = enable_dtx; + _vadMode = mode; + + return 0; + } else if (status < 0) { + // SetVAD failed. + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "SetVAD failed"); + + _vadEnabled = false; + _dtxEnabled = false; + + return -1; } + } - // If a send codec is registered, set VAD/DTX for the codec - if(HaveValidEncoder("SetVAD")) { - WebRtc_Word16 status = - _codecs[_currentSendCodecIdx]->SetVAD(enableDTX, enableVAD, vadMode); - if(status == 1) { - // Vad was enabled; - _vadEnabled = true; - _dtxEnabled = enableDTX; - _vadMode = vadMode; + _vadEnabled = enable_vad; + _dtxEnabled = enable_dtx; + _vadMode = mode; - return 0; - } else if (status < 0) { - // SetVAD failed - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "SetVAD failed"); - - _vadEnabled = false; - _dtxEnabled = false; - - return -1; - } - } - - _vadEnabled = enableVAD; - _dtxEnabled = enableDTX; - _vadMode = vadMode; - - return 0; + return 0; } -WebRtc_Word32 -AudioCodingModuleImpl::VAD( - bool& dtxEnabled, - bool& vadEnabled, - ACMVADMode& vadMode) const -{ - CriticalSectionScoped lock(*_acmCritSect); +// Get VAD/DTX settings. +WebRtc_Word32 AudioCodingModuleImpl::VAD(bool& dtx_enabled, bool& vad_enabled, + ACMVADMode& mode) const { + CriticalSectionScoped lock(*_acmCritSect); - dtxEnabled = _dtxEnabled; - vadEnabled = _vadEnabled; - vadMode = _vadMode; + dtx_enabled = _dtxEnabled; + vad_enabled = _vadEnabled; + mode = _vadMode; - return 0; + return 0; } ///////////////////////////////////////// // Receiver // -WebRtc_Word32 -AudioCodingModuleImpl::InitializeReceiver() -{ - CriticalSectionScoped lock(*_acmCritSect); - return InitializeReceiverSafe(); +WebRtc_Word32 AudioCodingModuleImpl::InitializeReceiver() { + CriticalSectionScoped lock(*_acmCritSect); + return InitializeReceiverSafe(); } // Initialize receiver, resets codec database etc. @@ -1370,31 +1169,31 @@ WebRtc_Word32 AudioCodingModuleImpl::InitializeReceiverSafe() { for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) { if (UnregisterReceiveCodecSafe(i) < 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "InitializeReceiver() failed, Could not unregister codec"); + "InitializeReceiver() failed, Could not unregister codec"); return -1; } } } if (_netEq.Init() != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "InitializeReceiver() failed, Could not initialize NetEQ"); + "InitializeReceiver() failed, Could not initialize NetEQ"); return -1; } _netEq.SetUniqueId(_id); if (_netEq.AllocatePacketBuffer(ACMCodecDB::NetEQDecoders(), ACMCodecDB::kNumCodecs) != 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "NetEQ cannot allocatePacket Buffer"); + "NetEQ cannot allocatePacket Buffer"); return -1; } - // Register RED and CN + // Register RED and CN. for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) { if (IsCodecRED(i) || IsCodecCN(i)) { if (RegisterRecCodecMSSafe(ACMCodecDB::database_[i], i, i, ACMNetEQ::masterJB) < 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot register master codec."); + "Cannot register master codec."); return -1; } _registeredPlTypes[i] = ACMCodecDB::database_[i].pltype; @@ -1405,411 +1204,346 @@ WebRtc_Word32 AudioCodingModuleImpl::InitializeReceiverSafe() { return 0; } -// Reset the decoder state -WebRtc_Word32 -AudioCodingModuleImpl::ResetDecoder() -{ - CriticalSectionScoped lock(*_acmCritSect); +// Reset the decoder state. +WebRtc_Word32 AudioCodingModuleImpl::ResetDecoder() { + CriticalSectionScoped lock(*_acmCritSect); - for(int codecCntr = 0; codecCntr < ACMCodecDB::kMaxNumCodecs; codecCntr++) - { - if((_codecs[codecCntr] != NULL) && (_registeredPlTypes[codecCntr] != -1)) - { - if(_codecs[codecCntr]->ResetDecoder(_registeredPlTypes[codecCntr]) < 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "ResetDecoder failed:"); - return -1; - } - } - } - return _netEq.FlushBuffers(); -} - -// get current receive freq -WebRtc_Word32 -AudioCodingModuleImpl::ReceiveFrequency() const -{ - WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, - "ReceiveFrequency()"); - WebRtcACMCodecParams codecParams; - - CriticalSectionScoped lock(*_acmCritSect); - if(DecoderParamByPlType(_lastRecvAudioCodecPlType, codecParams) < 0) - { - return _netEq.CurrentSampFreqHz(); - } - else - { - return codecParams.codecInstant.plfreq; - } -} - -// get current playout freq -WebRtc_Word32 -AudioCodingModuleImpl::PlayoutFrequency() const -{ - WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, - "PlayoutFrequency()"); - - CriticalSectionScoped lock(*_acmCritSect); - - return _netEq.CurrentSampFreqHz(); -} - - -// register possible reveive codecs, can be called multiple times, -// for codecs, CNG (NB, WB and SWB), DTMF, RED -WebRtc_Word32 -AudioCodingModuleImpl::RegisterReceiveCodec( - const CodecInst& receiveCodec) -{ - CriticalSectionScoped lock(*_acmCritSect); - - if(receiveCodec.channels > 2) - { + for (int id = 0; id < ACMCodecDB::kMaxNumCodecs; id++) { + if ((_codecs[id] != NULL) && (_registeredPlTypes[id] != -1)) { + if (_codecs[id]->ResetDecoder(_registeredPlTypes[id]) < 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "More than 2 audio channel is not supported."); - return -1; - } - - int mirrorId; - int codecId = ACMCodecDB::ReceiverCodecNumber(&receiveCodec, &mirrorId); - - if(codecId < 0 || codecId >= ACMCodecDB::kNumCodecs) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Wrong codec params to be registered as receive codec"); - return -1; - } - // Check if the payload-type is valid. - if(!ACMCodecDB::ValidPayloadType(receiveCodec.pltype)) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Invalid payload-type %d for %s.", - receiveCodec.pltype, receiveCodec.plname); - return -1; - } - - if(!_receiverInitialized) - { - if(InitializeReceiverSafe() < 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot initialize reciver, so failed registering a codec."); - return -1; - } - } - - // If codec already registered, unregister. Except for CN where we only - // unregister if payload type is changing. - if ((_registeredPlTypes[codecId] == receiveCodec.pltype) && - IsCodecCN(receiveCodec)) { - // Codec already registered as receiver with this payload type. Nothing - // to be done. - return 0; - } else if (_registeredPlTypes[codecId] != -1) { - if (UnregisterReceiveCodecSafe(codecId) < 0) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot register master codec."); + "ResetDecoder failed:"); return -1; } } + } + return _netEq.FlushBuffers(); +} - if (RegisterRecCodecMSSafe(receiveCodec, codecId, mirrorId, - ACMNetEQ::masterJB) < 0) { +// Get current receive frequency. +WebRtc_Word32 AudioCodingModuleImpl::ReceiveFrequency() const { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, + "ReceiveFrequency()"); + WebRtcACMCodecParams codec_params; + + CriticalSectionScoped lock(*_acmCritSect); + if (DecoderParamByPlType(_lastRecvAudioCodecPlType, codec_params) < 0) { + return _netEq.CurrentSampFreqHz(); + } else { + return codec_params.codecInstant.plfreq; + } +} + +// Get current playout frequency. +WebRtc_Word32 AudioCodingModuleImpl::PlayoutFrequency() const { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, + "PlayoutFrequency()"); + + CriticalSectionScoped lock(*_acmCritSect); + + return _netEq.CurrentSampFreqHz(); +} + +// Register possible reveive codecs, can be called multiple times, +// for codecs, CNG (NB, WB and SWB), DTMF, RED. +WebRtc_Word32 AudioCodingModuleImpl::RegisterReceiveCodec( + const CodecInst& receive_codec) { + CriticalSectionScoped lock(*_acmCritSect); + + if (receive_codec.channels > 2) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "More than 2 audio channel is not supported."); + return -1; + } + + int mirror_id; + int codec_id = ACMCodecDB::ReceiverCodecNumber(&receive_codec, &mirror_id); + + if (codec_id < 0 || codec_id >= ACMCodecDB::kNumCodecs) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Wrong codec params to be registered as receive codec"); + return -1; + } + // Check if the payload-type is valid. + if (!ACMCodecDB::ValidPayloadType(receive_codec.pltype)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Invalid payload-type %d for %s.", receive_codec.pltype, + receive_codec.plname); + return -1; + } + + if (!_receiverInitialized) { + if (InitializeReceiverSafe() < 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot register master codec."); + "Cannot initialize reciver, so failed registering a codec."); return -1; } + } - // TODO(andrew): Refactor how the slave is initialized. Can we instead - // always start up a slave and pre-register CN and RED? We should be able - // to get rid of _stereoReceiveRegistered. - // http://code.google.com/p/webrtc/issues/detail?id=453 + // If codec already registered, unregister. Except for CN where we only + // unregister if payload type is changing. + if ((_registeredPlTypes[codec_id] == receive_codec.pltype) + && IsCodecCN(receive_codec)) { + // Codec already registered as receiver with this payload type. Nothing + // to be done. + return 0; + } else if (_registeredPlTypes[codec_id] != -1) { + if (UnregisterReceiveCodecSafe(codec_id) < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot register master codec."); + return -1; + } + } - // Register stereo codecs with the slave, or, if we've had already seen a - // stereo codec, register CN or RED as a special case. - if (receiveCodec.channels == 2 || (_stereoReceiveRegistered && - (IsCodecCN(receiveCodec) || IsCodecRED(receiveCodec)))) { - // TODO(andrew): refactor this block to combine with InitStereoSlave(). + if (RegisterRecCodecMSSafe(receive_codec, codec_id, mirror_id, + ACMNetEQ::masterJB) < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot register master codec."); + return -1; + } - if (!_stereoReceiveRegistered) { - // This is the first time a stereo codec has been registered. Make - // some stereo preparations. + // TODO(andrew): Refactor how the slave is initialized. Can we instead + // always start up a slave and pre-register CN and RED? We should be able + // to get rid of _stereoReceiveRegistered. + // http://code.google.com/p/webrtc/issues/detail?id=453 - // Add a stereo slave. - assert(_netEq.NumSlaves() == 0); - if (_netEq.AddSlave(ACMCodecDB::NetEQDecoders(), - ACMCodecDB::kNumCodecs) < 0) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot add slave jitter buffer to NetEQ."); - return -1; - } + // Register stereo codecs with the slave, or, if we've had already seen a + // stereo codec, register CN or RED as a special case. + if (receive_codec.channels == 2 || + (_stereoReceiveRegistered && (IsCodecCN(receive_codec) || + IsCodecRED(receive_codec)))) { + // TODO(andrew): refactor this block to combine with InitStereoSlave(). - // Register any existing CN or RED codecs with the slave and as stereo. - for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) { - if (_registeredPlTypes[i] != -1 && - (IsCodecRED(i) || IsCodecCN(i))) { - _stereoReceive[i] = true; + if (!_stereoReceiveRegistered) { + // This is the first time a stereo codec has been registered. Make + // some stereo preparations. - CodecInst codec; - memcpy(&codec, &ACMCodecDB::database_[i], sizeof(CodecInst)); - codec.pltype = _registeredPlTypes[i]; - if (RegisterRecCodecMSSafe(codec, i, i, ACMNetEQ::slaveJB) < 0) { - WEBRTC_TRACE(kTraceError, kTraceAudioCoding, _id, - "Cannot register slave codec."); - return -1; - } + // Add a stereo slave. + assert(_netEq.NumSlaves() == 0); + if (_netEq.AddSlave(ACMCodecDB::NetEQDecoders(), + ACMCodecDB::kNumCodecs) < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot add slave jitter buffer to NetEQ."); + return -1; + } + + // Register any existing CN or RED codecs with the slave and as stereo. + for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) { + if (_registeredPlTypes[i] != -1 && (IsCodecRED(i) || IsCodecCN(i))) { + _stereoReceive[i] = true; + + CodecInst codec; + memcpy(&codec, &ACMCodecDB::database_[i], sizeof(CodecInst)); + codec.pltype = _registeredPlTypes[i]; + if (RegisterRecCodecMSSafe(codec, i, i, ACMNetEQ::slaveJB) < 0) { + WEBRTC_TRACE(kTraceError, kTraceAudioCoding, _id, + "Cannot register slave codec."); + return -1; } } } - - if (RegisterRecCodecMSSafe(receiveCodec, codecId, mirrorId, - ACMNetEQ::slaveJB) < 0) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot register slave codec."); - return -1; - } - - if (!_stereoReceive[codecId] && - (_lastRecvAudioCodecPlType == receiveCodec.pltype)) { - // The last received payload type is the same as the current one, but - // was marked as mono. Reset to avoid problems. - _lastRecvAudioCodecPlType = -1; - } - - _stereoReceive[codecId] = true; - _stereoReceiveRegistered = true; - } - else { - _stereoReceive[codecId] = false; } - _registeredPlTypes[codecId] = receiveCodec.pltype; - - if (IsCodecRED(receiveCodec)) { - _receiveREDPayloadType = receiveCodec.pltype; + if (RegisterRecCodecMSSafe(receive_codec, codec_id, mirror_id, + ACMNetEQ::slaveJB) < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot register slave codec."); + return -1; } - return 0; + + if (!_stereoReceive[codec_id] + && (_lastRecvAudioCodecPlType == receive_codec.pltype)) { + // The last received payload type is the same as the current one, but + // was marked as mono. Reset to avoid problems. + _lastRecvAudioCodecPlType = -1; + } + + _stereoReceive[codec_id] = true; + _stereoReceiveRegistered = true; + } else { + _stereoReceive[codec_id] = false; + } + + _registeredPlTypes[codec_id] = receive_codec.pltype; + + if (IsCodecRED(receive_codec)) { + _receiveREDPayloadType = receive_codec.pltype; + } + return 0; } - - -WebRtc_Word32 -AudioCodingModuleImpl::RegisterRecCodecMSSafe( - const CodecInst& receiveCodec, - WebRtc_Word16 codecId, - WebRtc_Word16 mirrorId, - ACMNetEQ::JB jitterBuffer) -{ - ACMGenericCodec** codecArray; - if(jitterBuffer == ACMNetEQ::masterJB) - { - codecArray = &_codecs[0]; +WebRtc_Word32 AudioCodingModuleImpl::RegisterRecCodecMSSafe( + const CodecInst& receive_codec, WebRtc_Word16 codec_id, + WebRtc_Word16 mirror_id, ACMNetEQ::JB jitter_buffer) { + ACMGenericCodec** codecs; + if (jitter_buffer == ACMNetEQ::masterJB) { + codecs = &_codecs[0]; + } else if (jitter_buffer == ACMNetEQ::slaveJB) { + codecs = &_slaveCodecs[0]; + if (_codecs[codec_id]->IsTrueStereoCodec()) { + // True stereo codecs need to use the same codec memory + // for both master and slave. + _slaveCodecs[mirror_id] = _codecs[mirror_id]; + _mirrorCodecIdx[mirror_id] = mirror_id; } - else if(jitterBuffer == ACMNetEQ::slaveJB) - { - codecArray = &_slaveCodecs[0]; - if (_codecs[codecId]->IsTrueStereoCodec()) { - // True stereo codecs need to use the same codec memory - // for both master and slave. - _slaveCodecs[mirrorId] = _codecs[mirrorId]; - _mirrorCodecIdx[mirrorId] = mirrorId; - } - } - else - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "RegisterReceiveCodecMSSafe failed, jitterBuffer is neither master or slave "); - return -1; - } - - if (codecArray[mirrorId] == NULL) - { - codecArray[mirrorId] = CreateCodec(receiveCodec); - if(codecArray[mirrorId] == NULL) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot create codec to register as receive codec"); - return -1; - } - _mirrorCodecIdx[mirrorId] = mirrorId; - } - if(mirrorId != codecId) - { - codecArray[codecId] = codecArray[mirrorId]; - _mirrorCodecIdx[codecId] = mirrorId; - } - - codecArray[codecId]->SetIsMaster(jitterBuffer == ACMNetEQ::masterJB); - - WebRtc_Word16 status = 0; - bool registerInNetEq = true; - WebRtcACMCodecParams codecParams; - memcpy(&(codecParams.codecInstant), &receiveCodec, - sizeof(CodecInst)); - codecParams.enableVAD = false; - codecParams.enableDTX = false; - codecParams.vadMode = VADNormal; - if (!codecArray[codecId]->DecoderInitialized()) - { - // force initialization - status = codecArray[codecId]->InitDecoder(&codecParams, true); - if(status < 0) - { - // could not initialize the decoder we don't want to - // continue if we could not initialize properly. - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "could not initialize the receive codec, codec not registered"); - - return -1; - } - } - else if(mirrorId != codecId) - { - // Currently this only happens for iSAC. - // we have to store the decoder parameters - - codecArray[codecId]->SaveDecoderParam(&codecParams); - } - if (registerInNetEq) - { - if(codecArray[codecId]->RegisterInNetEq(&_netEq, receiveCodec) - != 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Receive codec could not be registered in NetEQ"); - - return -1; - } - // Guarantee that the same payload-type that is - // registered in NetEQ is stored in the codec. - codecArray[codecId]->SaveDecoderParam(&codecParams); - } - - return status; -} - - - -// Get current received codec -WebRtc_Word32 -AudioCodingModuleImpl::ReceiveCodec( - CodecInst& currentReceiveCodec) const -{ - WebRtcACMCodecParams decoderParam; - CriticalSectionScoped lock(*_acmCritSect); - - for(int decCntr = 0; decCntr < ACMCodecDB::kMaxNumCodecs; decCntr++) - { - if(_codecs[decCntr] != NULL) - { - if(_codecs[decCntr]->DecoderInitialized()) - { - if(_codecs[decCntr]->DecoderParams(&decoderParam, - _lastRecvAudioCodecPlType)) - { - memcpy(¤tReceiveCodec, &decoderParam.codecInstant, - sizeof(CodecInst)); - return 0; - } - } - } - } - - // if we are here then we haven't found any codec - // set codec pltype to -1 to indicate that the structure - // is invalid and return -1. - currentReceiveCodec.pltype = -1; + } else { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "RegisterReceiveCodecMSSafe failed, jitter_buffer is neither " + "master or slave "); return -1; + } + + if (codecs[mirror_id] == NULL) { + codecs[mirror_id] = CreateCodec(receive_codec); + if (codecs[mirror_id] == NULL) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot create codec to register as receive codec"); + return -1; + } + _mirrorCodecIdx[mirror_id] = mirror_id; + } + if (mirror_id != codec_id) { + codecs[codec_id] = codecs[mirror_id]; + _mirrorCodecIdx[codec_id] = mirror_id; + } + + codecs[codec_id]->SetIsMaster(jitter_buffer == ACMNetEQ::masterJB); + + WebRtc_Word16 status = 0; + WebRtcACMCodecParams codec_params; + memcpy(&(codec_params.codecInstant), &receive_codec, sizeof(CodecInst)); + codec_params.enableVAD = false; + codec_params.enableDTX = false; + codec_params.vadMode = VADNormal; + if (!codecs[codec_id]->DecoderInitialized()) { + // Force initialization. + status = codecs[codec_id]->InitDecoder(&codec_params, true); + if (status < 0) { + // Could not initialize the decoder, we don't want to + // continue if we could not initialize properly. + WEBRTC_TRACE( + webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "could not initialize the receive codec, codec not registered"); + + return -1; + } + } else if (mirror_id != codec_id) { + // Currently this only happens for iSAC. + // We have to store the decoder parameters. + codecs[codec_id]->SaveDecoderParam(&codec_params); + } + + if (codecs[codec_id]->RegisterInNetEq(&_netEq, receive_codec) != 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Receive codec could not be registered in NetEQ"); + return -1; + } + // Guarantee that the same payload-type that is + // registered in NetEQ is stored in the codec. + codecs[codec_id]->SaveDecoderParam(&codec_params); + + return status; } -// Incoming packet from network parsed and ready for decode -WebRtc_Word32 -AudioCodingModuleImpl::IncomingPacket( - const WebRtc_UWord8* incomingPayload, - const WebRtc_Word32 payloadLength, - const WebRtcRTPHeader& rtpInfo) -{ - WebRtcRTPHeader rtp_header; +// Get current received codec. +WebRtc_Word32 AudioCodingModuleImpl::ReceiveCodec( + CodecInst& current_codec) const { + WebRtcACMCodecParams decoderParam; + CriticalSectionScoped lock(*_acmCritSect); - memcpy(&rtp_header, &rtpInfo, sizeof(WebRtcRTPHeader)); - - if (payloadLength < 0) - { - // Log error - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "IncomingPacket() Error, payload-length cannot be negative"); - return -1; - } - { - // store the payload Type. this will be used to retrieve "received codec" - // and "received frequency." - CriticalSectionScoped lock(*_acmCritSect); -#ifdef ACM_QA_TEST - if(_incomingPL != NULL) - { - fwrite(&rtpInfo.header.timestamp, sizeof(WebRtc_UWord32), 1, _incomingPL); - fwrite(&rtpInfo.header.payloadType, sizeof(WebRtc_UWord8), 1, _incomingPL); - fwrite(&payloadLength, sizeof(WebRtc_Word16), 1, _incomingPL); + for (int id = 0; id < ACMCodecDB::kMaxNumCodecs; id++) { + if (_codecs[id] != NULL) { + if (_codecs[id]->DecoderInitialized()) { + if (_codecs[id]->DecoderParams(&decoderParam, + _lastRecvAudioCodecPlType)) { + memcpy(¤t_codec, &decoderParam.codecInstant, sizeof(CodecInst)); + return 0; } + } + } + } + + // If we are here then we haven't found any codec. Set codec pltype to -1 to + // indicate that the structure is invalid and return -1. + current_codec.pltype = -1; + return -1; +} + +// Incoming packet from network parsed and ready for decode. +WebRtc_Word32 AudioCodingModuleImpl::IncomingPacket( + const WebRtc_UWord8* incoming_payload, + const WebRtc_Word32 payload_length, + const WebRtcRTPHeader& rtp_info) { + WebRtcRTPHeader rtp_header; + + memcpy(&rtp_header, &rtp_info, sizeof(WebRtcRTPHeader)); + + if (payload_length < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "IncomingPacket() Error, payload-length cannot be negative"); + return -1; + } + { + // Store the payload Type. This will be used to retrieve "received codec" + // and "received frequency." + CriticalSectionScoped lock(*_acmCritSect); +#ifdef ACM_QA_TEST + if(_incomingPL != NULL) { + fwrite(&rtp_info.header.timestamp, sizeof(WebRtc_UWord32), 1, + _incomingPL); + fwrite(&rtp_info.header.payloadType, sizeof(WebRtc_UWord8), 1, + _incomingPL); + fwrite(&payload_length, sizeof(WebRtc_Word16), 1, _incomingPL); + } #endif - WebRtc_UWord8 myPayloadType; + WebRtc_UWord8 myPayloadType; - // Check if this is an RED payload - if(rtpInfo.header.payloadType == _receiveREDPayloadType) - { - // get the primary payload-type. - myPayloadType = incomingPayload[0] & 0x7F; - } - else - { - myPayloadType = rtpInfo.header.payloadType; - } - - // If payload is audio, check if received payload is different from - // previous. - if(!rtpInfo.type.Audio.isCNG) - { - // This is Audio not CNG - - if(myPayloadType != _lastRecvAudioCodecPlType) - { - // We detect a change in payload type. It is necessary for iSAC - // we are going to use ONE iSAC instance for decoding both WB and - // SWB payloads. If payload is changed there might be a need to reset - // sampling rate of decoder. depending what we have received "now". - for(int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) - { - if(_registeredPlTypes[i] == myPayloadType) - { - if (UpdateUponReceivingCodec(i) != 0) - return -1; - break; - } - } - } - _lastRecvAudioCodecPlType = myPayloadType; - } - } - - // Split the payload for stereo packets, so that first half of payload - // vector holds left channel, and second half holds right channel. - if (_expected_channels == 2) { - // Create a new vector for the payload, maximum payload size. - WebRtc_Word32 length = payloadLength; - WebRtc_UWord8 payload[kMaxPacketSize]; - assert(payloadLength <= kMaxPacketSize); - memcpy(payload, incomingPayload, payloadLength); - _codecs[_current_receive_codec_idx]->SplitStereoPacket(payload, &length); - rtp_header.type.Audio.channel = 2; - // Insert packet into NetEQ. - return _netEq.RecIn(payload, length, rtp_header); + // Check if this is an RED payload. + if (rtp_info.header.payloadType == _receiveREDPayloadType) { + // Get the primary payload-type. + myPayloadType = incoming_payload[0] & 0x7F; } else { - return _netEq.RecIn(incomingPayload, payloadLength, rtp_header); + myPayloadType = rtp_info.header.payloadType; } + + // If payload is audio, check if received payload is different from + // previous. + if (!rtp_info.type.Audio.isCNG) { + // This is Audio not CNG. + + if (myPayloadType != _lastRecvAudioCodecPlType) { + // We detect a change in payload type. It is necessary for iSAC + // we are going to use ONE iSAC instance for decoding both WB and + // SWB payloads. If payload is changed there might be a need to reset + // sampling rate of decoder. depending what we have received "now". + for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) { + if (_registeredPlTypes[i] == myPayloadType) { + if (UpdateUponReceivingCodec(i) != 0) + return -1; + break; + } + } + } + _lastRecvAudioCodecPlType = myPayloadType; + } + } + + // Split the payload for stereo packets, so that first half of payload + // vector holds left channel, and second half holds right channel. + if (_expected_channels == 2) { + // Create a new vector for the payload, maximum payload size. + WebRtc_Word32 length = payload_length; + WebRtc_UWord8 payload[kMaxPacketSize]; + assert(payload_length <= kMaxPacketSize); + memcpy(payload, incoming_payload, payload_length); + _codecs[_current_receive_codec_idx]->SplitStereoPacket(payload, &length); + rtp_header.type.Audio.channel = 2; + // Insert packet into NetEQ. + return _netEq.RecIn(payload, length, rtp_header); + } else { + return _netEq.RecIn(incoming_payload, payload_length, rtp_header); + } } int AudioCodingModuleImpl::UpdateUponReceivingCodec(int index) { @@ -1844,7 +1578,7 @@ int AudioCodingModuleImpl::UpdateUponReceivingCodec(int index) { _expected_channels = 1; } - // Reset previous received channel + // Reset previous received channel. _prev_received_channel = 0; return 0; } @@ -1897,274 +1631,225 @@ int AudioCodingModuleImpl::InitStereoSlave() { return 0; } -// Minimum playout delay (Used for lip-sync) -WebRtc_Word32 -AudioCodingModuleImpl::SetMinimumPlayoutDelay( - const WebRtc_Word32 timeMs) -{ - if((timeMs < 0) || (timeMs > 1000)) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Delay must be in the range of 0-1000 milliseconds."); - return -1; - } - return _netEq.SetExtraDelay(timeMs); -} - -// Get Dtmf playout status -bool -AudioCodingModuleImpl::DtmfPlayoutStatus() const -{ -#ifndef WEBRTC_CODEC_AVT - return false; -#else - return _netEq.AVTPlayout(); -#endif -} - -// configure Dtmf playout status i.e on/off -// playout the incoming outband Dtmf tone -WebRtc_Word32 -AudioCodingModuleImpl::SetDtmfPlayoutStatus( -#ifndef WEBRTC_CODEC_AVT - const bool /* enable */) -{ - WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, _id, - "SetDtmfPlayoutStatus() failed: AVT is not supported."); +// Minimum playout delay (Used for lip-sync). +WebRtc_Word32 AudioCodingModuleImpl::SetMinimumPlayoutDelay( + const WebRtc_Word32 time_ms) { + if ((time_ms < 0) || (time_ms > 1000)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Delay must be in the range of 0-1000 milliseconds."); return -1; + } + return _netEq.SetExtraDelay(time_ms); +} + +// Get Dtmf playout status. +bool AudioCodingModuleImpl::DtmfPlayoutStatus() const { +#ifndef WEBRTC_CODEC_AVT + return false; #else - const bool enable) -{ - return _netEq.SetAVTPlayout(enable); + return _netEq.AVTPlayout(); #endif } -// Estimate the Bandwidth based on the incoming stream -// This is also done in the RTP module -// need this for one way audio where the RTCP send the BW estimate -WebRtc_Word32 -AudioCodingModuleImpl::DecoderEstimatedBandwidth() const -{ - CodecInst codecInst; - WebRtc_Word16 codecID = -1; - int plTypWB; - int plTypSWB; +// Configure Dtmf playout status i.e on/off playout the incoming outband +// Dtmf tone. +WebRtc_Word32 AudioCodingModuleImpl::SetDtmfPlayoutStatus( +#ifndef WEBRTC_CODEC_AVT + const bool /* enable */) { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, _id, + "SetDtmfPlayoutStatus() failed: AVT is not supported."); + return -1; +#else + const bool enable) { + return _netEq.SetAVTPlayout(enable); +#endif +} - // Get iSAC settings - for(int codecCntr = 0; codecCntr < ACMCodecDB::kNumCodecs; codecCntr++) - { - // Store codec settings for codec number "codeCntr" in the output struct - ACMCodecDB::Codec(codecCntr, &codecInst); +// Estimate the Bandwidth based on the incoming stream, needed for one way +// audio where the RTCP send the BW estimate. +// This is also done in the RTP module. +WebRtc_Word32 AudioCodingModuleImpl::DecoderEstimatedBandwidth() const { + CodecInst codec; + WebRtc_Word16 codec_id = -1; + int payloadtype_wb; + int payloadtype_swb; - if(!STR_CASE_CMP(codecInst.plname, "isac")) - { - codecID = 1; - plTypWB = codecInst.pltype; + // Get iSAC settings. + for (int id = 0; id < ACMCodecDB::kNumCodecs; id++) { + // Store codec settings for codec number "codeCntr" in the output struct. + ACMCodecDB::Codec(id, &codec); - ACMCodecDB::Codec(codecCntr+1, &codecInst); - plTypSWB = codecInst.pltype; + if (!STR_CASE_CMP(codec.plname, "isac")) { + codec_id = 1; + payloadtype_wb = codec.pltype; - break; - } + ACMCodecDB::Codec(id + 1, &codec); + payloadtype_swb = codec.pltype; + + break; } + } - if(codecID < 0) - { + if (codec_id < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "DecoderEstimatedBandwidth failed"); + return -1; + } + + if ((_lastRecvAudioCodecPlType == payloadtype_wb) || + (_lastRecvAudioCodecPlType == payloadtype_swb)) { + return _codecs[codec_id]->GetEstimatedBandwidth(); + } else { + return -1; + } +} + +// Set playout mode for: voice, fax, or streaming. +WebRtc_Word32 AudioCodingModuleImpl::SetPlayoutMode( + const AudioPlayoutMode mode) { + if ((mode != voice) && (mode != fax) && (mode != streaming)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Invalid playout mode."); + return -1; + } + return _netEq.SetPlayoutMode(mode); +} + +// Get playout mode voice, fax. +AudioPlayoutMode AudioCodingModuleImpl::PlayoutMode() const { + return _netEq.PlayoutMode(); +} + +// Get 10 milliseconds of raw audio data to play out. +// Automatic resample to the requested frequency. +WebRtc_Word32 AudioCodingModuleImpl::PlayoutData10Ms( + const WebRtc_Word32 desired_freq_hz, AudioFrame& audio_frame) { + bool stereo_mode; + + // RecOut always returns 10 ms. + if (_netEq.RecOut(_audioFrame) != 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "PlayoutData failed, RecOut Failed"); + return -1; + } + + audio_frame._audioChannel = _audioFrame._audioChannel; + audio_frame._vadActivity = _audioFrame._vadActivity; + audio_frame._speechType = _audioFrame._speechType; + + stereo_mode = (_audioFrame._audioChannel > 1); + // For stereo playout: + // Master and Slave samples are interleaved starting with Master. + + const WebRtc_UWord16 receive_freq = + static_cast(_audioFrame._frequencyInHz); + bool tone_detected = false; + WebRtc_Word16 last_detected_tone; + WebRtc_Word16 tone; + + // Limit the scope of ACM Critical section. + { + CriticalSectionScoped lock(*_acmCritSect); + + if ((receive_freq != desired_freq_hz) && (desired_freq_hz != -1)) { + // Resample payloadData. + WebRtc_Word16 temp_len = _outputResampler.Resample10Msec( + _audioFrame._payloadData, receive_freq, audio_frame._payloadData, + desired_freq_hz, _audioFrame._audioChannel); + + if (temp_len < 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "DecoderEstimatedBandwidth failed"); + "PlayoutData failed, resampler failed"); return -1; - } + } - if ((_lastRecvAudioCodecPlType == plTypWB) || (_lastRecvAudioCodecPlType == plTypSWB)) - { - return _codecs[codecID]->GetEstimatedBandwidth(); + // Set the payload data length from the resampler. + audio_frame._payloadDataLengthInSamples = (WebRtc_UWord16) temp_len; + // Set the sampling frequency. + audio_frame._frequencyInHz = desired_freq_hz; } else { - return -1; - } -} - -// Set playout mode for: voice, fax, or streaming -WebRtc_Word32 -AudioCodingModuleImpl::SetPlayoutMode( - const AudioPlayoutMode mode) -{ - if((mode != voice) && - (mode != fax) && - (mode != streaming)) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Invalid playout mode."); - return -1; - } - return _netEq.SetPlayoutMode(mode); -} - -// Get playout mode voice, fax -AudioPlayoutMode -AudioCodingModuleImpl::PlayoutMode() const -{ - return _netEq.PlayoutMode(); -} - - -// Get 10 milliseconds of raw audio data to play out -// automatic resample to the requested frequency -WebRtc_Word32 -AudioCodingModuleImpl::PlayoutData10Ms( - const WebRtc_Word32 desiredFreqHz, - AudioFrame& audioFrame) -{ - bool stereoMode; - - // recOut always returns 10 ms - if (_netEq.RecOut(_audioFrame) != 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "PlayoutData failed, RecOut Failed"); - return -1; + memcpy(audio_frame._payloadData, _audioFrame._payloadData, + _audioFrame._payloadDataLengthInSamples * audio_frame._audioChannel + * sizeof(WebRtc_Word16)); + // Set the payload length. + audio_frame._payloadDataLengthInSamples = + _audioFrame._payloadDataLengthInSamples; + // Set the sampling frequency. + audio_frame._frequencyInHz = receive_freq; } - audioFrame._audioChannel = _audioFrame._audioChannel; - audioFrame._vadActivity = _audioFrame._vadActivity; - audioFrame._speechType = _audioFrame._speechType; - - stereoMode = (_audioFrame._audioChannel > 1); - //For stereo playout: - // Master and Slave samples are interleaved starting with Master - - const WebRtc_UWord16 recvFreq = static_cast(_audioFrame._frequencyInHz); - bool toneDetected = false; - WebRtc_Word16 lastDetectedTone; - WebRtc_Word16 tone; - - // limit the scope of ACM Critical section - // perhaps we don't need to have output resampler in - // critical section, it is supposed to be called in this - // function and no where else. However, it won't degrade complexity - { - CriticalSectionScoped lock(*_acmCritSect); - - if ((recvFreq != desiredFreqHz) && (desiredFreqHz != -1)) - { - // resample payloadData - WebRtc_Word16 tmpLen = _outputResampler.Resample10Msec( - _audioFrame._payloadData, recvFreq, audioFrame._payloadData, desiredFreqHz, - _audioFrame._audioChannel); - - if(tmpLen < 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "PlayoutData failed, resampler failed"); - return -1; - } - - //Set the payload data length from the resampler - audioFrame._payloadDataLengthInSamples = (WebRtc_UWord16)tmpLen; - // set the ssampling frequency - audioFrame._frequencyInHz = desiredFreqHz; + // Tone detection done for master channel. + if (_dtmfDetector != NULL) { + // Dtmf Detection. + if (audio_frame._frequencyInHz == 8000) { + // Use audio_frame._payloadData then Dtmf detector doesn't + // need resampling. + if (!stereo_mode) { + _dtmfDetector->Detect(audio_frame._payloadData, + audio_frame._payloadDataLengthInSamples, + audio_frame._frequencyInHz, tone_detected, + tone); + } else { + // We are in 8 kHz so the master channel needs only 80 samples. + WebRtc_Word16 master_channel[80]; + for (int n = 0; n < 80; n++) { + master_channel[n] = audio_frame._payloadData[n << 1]; + } + _dtmfDetector->Detect(master_channel, + audio_frame._payloadDataLengthInSamples, + audio_frame._frequencyInHz, tone_detected, + tone); } - else - { - memcpy(audioFrame._payloadData, _audioFrame._payloadData, - _audioFrame._payloadDataLengthInSamples * audioFrame._audioChannel - * sizeof(WebRtc_Word16)); - // set the payload length - audioFrame._payloadDataLengthInSamples = _audioFrame._payloadDataLengthInSamples; - // set the sampling frequency - audioFrame._frequencyInHz = recvFreq; - } - - //Tone detection done for master channel - if(_dtmfDetector != NULL) - { - // Dtmf Detection - if(audioFrame._frequencyInHz == 8000) - { - // use audioFrame._payloadData then Dtmf detector doesn't - // need resampling - if(!stereoMode) - { - _dtmfDetector->Detect(audioFrame._payloadData, - audioFrame._payloadDataLengthInSamples, - audioFrame._frequencyInHz, toneDetected, tone); - } - else - { - // we are in 8 kHz so the master channel needs only 80 samples - WebRtc_Word16 masterChannel[80]; - for(int n = 0; n < 80; n++) - { - masterChannel[n] = audioFrame._payloadData[n<<1]; - } - _dtmfDetector->Detect(masterChannel, - audioFrame._payloadDataLengthInSamples, - audioFrame._frequencyInHz, toneDetected, tone); - } - } - else - { - // Do the detection on the audio that we got from NetEQ (_audioFrame). - if(!stereoMode) - { - _dtmfDetector->Detect(_audioFrame._payloadData, - _audioFrame._payloadDataLengthInSamples, recvFreq, - toneDetected, tone); - } - else - { - WebRtc_Word16 masterChannel[WEBRTC_10MS_PCM_AUDIO]; - for(int n = 0; n < _audioFrame._payloadDataLengthInSamples; n++) - { - masterChannel[n] = _audioFrame._payloadData[n<<1]; - } - _dtmfDetector->Detect(masterChannel, - _audioFrame._payloadDataLengthInSamples, recvFreq, - toneDetected, tone); - } - } - } - - // we want to do this while we are in _acmCritSect - // doesn't really need to initialize the following - // variable but Linux complains if we don't - lastDetectedTone = kACMToneEnd; - if(toneDetected) - { - lastDetectedTone = _lastDetectedTone; - _lastDetectedTone = tone; + } else { + // Do the detection on the audio that we got from NetEQ (_audioFrame). + if (!stereo_mode) { + _dtmfDetector->Detect(_audioFrame._payloadData, + _audioFrame._payloadDataLengthInSamples, + receive_freq, tone_detected, tone); + } else { + WebRtc_Word16 master_channel[WEBRTC_10MS_PCM_AUDIO]; + for (int n = 0; n < _audioFrame._payloadDataLengthInSamples; n++) { + master_channel[n] = _audioFrame._payloadData[n << 1]; + } + _dtmfDetector->Detect(master_channel, + _audioFrame._payloadDataLengthInSamples, + receive_freq, tone_detected, tone); } + } } - if(toneDetected) - { - // we will deal with callback here, so enter callback critical - // section - CriticalSectionScoped lock(*_callbackCritSect); - - if(_dtmfCallback != NULL) - { - if(tone != kACMToneEnd) - { - // just a tone - _dtmfCallback->IncomingDtmf((WebRtc_UWord8)tone, false); - } - else if((tone == kACMToneEnd) && - (lastDetectedTone != kACMToneEnd)) - { - // The tone is "END" and the previously detected tone is - // not "END," so call fir an end. - _dtmfCallback->IncomingDtmf((WebRtc_UWord8)lastDetectedTone, - true); - } - } + // We want to do this while we are in _acmCritSect. + // (Doesn't really need to initialize the following + // variable but Linux complains if we don't.) + last_detected_tone = kACMToneEnd; + if (tone_detected) { + last_detected_tone = _lastDetectedTone; + _lastDetectedTone = tone; } + } - audioFrame._id = _id; - audioFrame._volume = -1; - audioFrame._energy = -1; - audioFrame._timeStamp = 0; + if (tone_detected) { + // We will deal with callback here, so enter callback critical section. + CriticalSectionScoped lock(*_callbackCritSect); - return 0; + if (_dtmfCallback != NULL) { + if (tone != kACMToneEnd) { + // just a tone + _dtmfCallback->IncomingDtmf((WebRtc_UWord8) tone, false); + } else if ((tone == kACMToneEnd) && (last_detected_tone != kACMToneEnd)) { + // The tone is "END" and the previously detected tone is + // not "END," so call fir an end. + _dtmfCallback->IncomingDtmf((WebRtc_UWord8) last_detected_tone, true); + } + } + } + + audio_frame._id = _id; + audio_frame._volume = -1; + audio_frame._energy = -1; + audio_frame._timeStamp = 0; + + return 0; } ///////////////////////////////////////// @@ -2173,542 +1858,440 @@ AudioCodingModuleImpl::PlayoutData10Ms( // // Get VAD aggressiveness on the incoming stream -ACMVADMode -AudioCodingModuleImpl::ReceiveVADMode() const -{ - return _netEq.VADMode(); +ACMVADMode AudioCodingModuleImpl::ReceiveVADMode() const { + return _netEq.VADMode(); } -// Configure VAD aggressiveness on the incoming stream -WebRtc_Word16 -AudioCodingModuleImpl::SetReceiveVADMode( - const ACMVADMode mode) -{ - return _netEq.SetVADMode(mode); +// Configure VAD aggressiveness on the incoming stream. +WebRtc_Word16 AudioCodingModuleImpl::SetReceiveVADMode(const ACMVADMode mode) { + return _netEq.SetVADMode(mode); } ///////////////////////////////////////// -// statistics +// Statistics // -WebRtc_Word32 -AudioCodingModuleImpl::NetworkStatistics( - ACMNetworkStatistics& statistics) const -{ - WebRtc_Word32 status; - status = _netEq.NetworkStatistics(&statistics); - return status; -} - -void -AudioCodingModuleImpl::DestructEncoderInst( - void* ptrInst) -{ - WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, _id, - "DestructEncoderInst()"); - if(!HaveValidEncoder("DestructEncoderInst")) - { - return; - } - - _codecs[_currentSendCodecIdx]->DestructEncoderInst(ptrInst); -} - -WebRtc_Word16 -AudioCodingModuleImpl::AudioBuffer( - WebRtcACMAudioBuff& audioBuff) -{ - WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, _id, - "AudioBuffer()"); - if(!HaveValidEncoder("AudioBuffer")) - { - return -1; - } - - audioBuff.lastInTimestamp = _lastInTimestamp; - return _codecs[_currentSendCodecIdx]->AudioBuffer(audioBuff); -} - -WebRtc_Word16 -AudioCodingModuleImpl::SetAudioBuffer( - WebRtcACMAudioBuff& audioBuff) -{ - WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, _id, - "SetAudioBuffer()"); - if(!HaveValidEncoder("SetAudioBuffer")) - { - return -1; - } - - return _codecs[_currentSendCodecIdx]->SetAudioBuffer(audioBuff); +WebRtc_Word32 AudioCodingModuleImpl::NetworkStatistics( + ACMNetworkStatistics& statistics) const { + WebRtc_Word32 status; + status = _netEq.NetworkStatistics(&statistics); + return status; } -WebRtc_UWord32 -AudioCodingModuleImpl::EarliestTimestamp() const -{ - WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, _id, - "EarliestTimestamp()"); - if(!HaveValidEncoder("EarliestTimestamp")) - { - return -1; - } +void AudioCodingModuleImpl::DestructEncoderInst(void* inst) { + WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, _id, + "DestructEncoderInst()"); + if (!HaveValidEncoder("DestructEncoderInst")) { + return; + } - return _codecs[_currentSendCodecIdx]->EarliestTimestamp(); + _codecs[_currentSendCodecIdx]->DestructEncoderInst(inst); } -WebRtc_Word32 -AudioCodingModuleImpl::RegisterVADCallback( - ACMVADCallback* vadCallback) -{ - WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, _id, - "RegisterVADCallback()"); - CriticalSectionScoped lock(*_callbackCritSect); - _vadCallback = vadCallback; - return 0; +WebRtc_Word16 AudioCodingModuleImpl::AudioBuffer( + WebRtcACMAudioBuff& buffer) { + WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, _id, + "AudioBuffer()"); + if (!HaveValidEncoder("AudioBuffer")) { + return -1; + } + buffer.lastInTimestamp = _lastInTimestamp; + return _codecs[_currentSendCodecIdx]->AudioBuffer(buffer); +} + +WebRtc_Word16 AudioCodingModuleImpl::SetAudioBuffer( + WebRtcACMAudioBuff& buffer) { + WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, _id, + "SetAudioBuffer()"); + if (!HaveValidEncoder("SetAudioBuffer")) { + return -1; + } + return _codecs[_currentSendCodecIdx]->SetAudioBuffer(buffer); +} + +WebRtc_UWord32 AudioCodingModuleImpl::EarliestTimestamp() const { + WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, _id, + "EarliestTimestamp()"); + if (!HaveValidEncoder("EarliestTimestamp")) { + return -1; + } + return _codecs[_currentSendCodecIdx]->EarliestTimestamp(); +} + +WebRtc_Word32 AudioCodingModuleImpl::RegisterVADCallback( + ACMVADCallback* vad_callback) { + WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, _id, + "RegisterVADCallback()"); + CriticalSectionScoped lock(*_callbackCritSect); + _vadCallback = vad_callback; + return 0; } // TODO(tlegrand): Modify this function to work for stereo, and add tests. -WebRtc_Word32 -AudioCodingModuleImpl::IncomingPayload( - const WebRtc_UWord8* incomingPayload, - const WebRtc_Word32 payloadLength, - const WebRtc_UWord8 payloadType, - const WebRtc_UWord32 timestamp) -{ - if (payloadLength < 0) - { - // Log error in trace file. - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "IncomingPacket() Error, payload-length cannot be negative"); - return -1; - } - - if(_dummyRTPHeader == NULL) - { - // This is the first time that we are using _dummyRTPHeader - // so we have to create it. - WebRtcACMCodecParams codecParams; - _dummyRTPHeader = new WebRtcRTPHeader; - if (_dummyRTPHeader == NULL) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "IncomingPacket() Error, out of memory"); - return -1; - } - _dummyRTPHeader->header.payloadType = payloadType; - // Don't matter in this case - _dummyRTPHeader->header.ssrc = 0; - _dummyRTPHeader->header.markerBit = false; - // start with random numbers - _dummyRTPHeader->header.sequenceNumber = rand(); - _dummyRTPHeader->header.timestamp = (((WebRtc_UWord32)rand()) << 16) + - (WebRtc_UWord32)rand(); - _dummyRTPHeader->type.Audio.channel = 1; - - if(DecoderParamByPlType(payloadType, codecParams) < 0) - { - // we didn't find a codec with the given payload. - // something is wrong we exit, but we delete _dummyRTPHeader - // and set it to NULL to start clean next time - delete _dummyRTPHeader; - _dummyRTPHeader = NULL; - return -1; - } - _recvPlFrameSizeSmpls = codecParams.codecInstant.pacsize; - } - - if(payloadType != _dummyRTPHeader->header.payloadType) - { - // payload type has changed since the last time we might need to - // update the frame-size - WebRtcACMCodecParams codecParams; - if(DecoderParamByPlType(payloadType, codecParams) < 0) - { - // we didn't find a codec with the given payload. - // something is wrong we exit - return -1; - } - _recvPlFrameSizeSmpls = codecParams.codecInstant.pacsize; - _dummyRTPHeader->header.payloadType = payloadType; - } - - if(timestamp > 0) - { - _dummyRTPHeader->header.timestamp = timestamp; - } - - // store the payload Type. this will be used to retrieve "received codec" - // and "received frequency." - _lastRecvAudioCodecPlType = payloadType; - - // Insert in NetEQ - if(_netEq.RecIn(incomingPayload, payloadLength, (*_dummyRTPHeader)) < 0) - { - return -1; - } - - // get ready for the next payload - _dummyRTPHeader->header.sequenceNumber++; - _dummyRTPHeader->header.timestamp += _recvPlFrameSizeSmpls; - return 0; -} - -WebRtc_Word16 -AudioCodingModuleImpl::DecoderParamByPlType( - const WebRtc_UWord8 payloadType, - WebRtcACMCodecParams& codecParams) const -{ - CriticalSectionScoped lock(*_acmCritSect); - for(WebRtc_Word16 codecCntr = 0; codecCntr < ACMCodecDB::kMaxNumCodecs; codecCntr++) - { - if(_codecs[codecCntr] != NULL) - { - if(_codecs[codecCntr]->DecoderInitialized()) - { - if(_codecs[codecCntr]->DecoderParams(&codecParams, - payloadType)) - { - return 0; - } - } - } - } - // if we are here it means that we could not find a - // codec with that payload type. reset the values to - // not acceptable values and return -1; - codecParams.codecInstant.plname[0] = '\0'; - codecParams.codecInstant.pacsize = 0; - codecParams.codecInstant.rate = 0; - codecParams.codecInstant.pltype = -1; +WebRtc_Word32 AudioCodingModuleImpl::IncomingPayload( + const WebRtc_UWord8* incoming_payload, const WebRtc_Word32 payload_length, + const WebRtc_UWord8 payload_type, const WebRtc_UWord32 timestamp) { + if (payload_length < 0) { + // Log error in trace file. + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "IncomingPacket() Error, payload-length cannot be negative"); return -1; -} + } - - -WebRtc_Word16 -AudioCodingModuleImpl::DecoderListIDByPlName( - const char* payloadName, - const WebRtc_UWord16 sampFreqHz) const -{ - WebRtcACMCodecParams codecParams; - CriticalSectionScoped lock(*_acmCritSect); - for(WebRtc_Word16 codecCntr = 0; codecCntr < ACMCodecDB::kMaxNumCodecs; codecCntr++) - { - if((_codecs[codecCntr] != NULL)) - { - if(_codecs[codecCntr]->DecoderInitialized()) - { - assert(_registeredPlTypes[codecCntr] >= 0); - assert(_registeredPlTypes[codecCntr] <= 255); - _codecs[codecCntr]->DecoderParams(&codecParams, - (WebRtc_UWord8)_registeredPlTypes[codecCntr]); - if(!STR_CASE_CMP(codecParams.codecInstant.plname, payloadName)) - { - // Check if the given sampling frequency matches. - // A zero sampling frequency means we matching the names - // is sufficient and we don't need to check for the - // frequencies. - // Currently it is only iSAC which has one name but two - // sampling frequencies. - if((sampFreqHz == 0) || - (codecParams.codecInstant.plfreq == sampFreqHz)) - { - return codecCntr; - } - } - } - } + if (_dummyRTPHeader == NULL) { + // This is the first time that we are using _dummyRTPHeader + // so we have to create it. + WebRtcACMCodecParams codec_params; + _dummyRTPHeader = new WebRtcRTPHeader; + if (_dummyRTPHeader == NULL) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "IncomingPacket() Error, out of memory"); + return -1; } - // if we are here it means that we could not find a - // codec with that payload type. return -1; + _dummyRTPHeader->header.payloadType = payload_type; + // Don't matter in this case. + _dummyRTPHeader->header.ssrc = 0; + _dummyRTPHeader->header.markerBit = false; + // Start with random numbers. + _dummyRTPHeader->header.sequenceNumber = rand(); + _dummyRTPHeader->header.timestamp = (((WebRtc_UWord32) rand()) << 16) + + (WebRtc_UWord32) rand(); + _dummyRTPHeader->type.Audio.channel = 1; + + if (DecoderParamByPlType(payload_type, codec_params) < 0) { + // We didn't find a codec with the given payload. + // Something is wrong we exit, but we delete _dummyRTPHeader + // and set it to NULL to start clean next time. + delete _dummyRTPHeader; + _dummyRTPHeader = NULL; + return -1; + } + _recvPlFrameSizeSmpls = codec_params.codecInstant.pacsize; + } + + if (payload_type != _dummyRTPHeader->header.payloadType) { + // Payload type has changed since the last time we might need to + // update the frame-size. + WebRtcACMCodecParams codec_params; + if (DecoderParamByPlType(payload_type, codec_params) < 0) { + // We didn't find a codec with the given payload. + return -1; + } + _recvPlFrameSizeSmpls = codec_params.codecInstant.pacsize; + _dummyRTPHeader->header.payloadType = payload_type; + } + + if (timestamp > 0) { + _dummyRTPHeader->header.timestamp = timestamp; + } + + // Store the payload Type. this will be used to retrieve "received codec" + // and "received frequency." + _lastRecvAudioCodecPlType = payload_type; + + // Insert in NetEQ. + if (_netEq.RecIn(incoming_payload, payload_length, (*_dummyRTPHeader)) < 0) { return -1; + } + + // Get ready for the next payload. + _dummyRTPHeader->header.sequenceNumber++; + _dummyRTPHeader->header.timestamp += _recvPlFrameSizeSmpls; + return 0; } -WebRtc_Word32 -AudioCodingModuleImpl::LastEncodedTimestamp(WebRtc_UWord32& timestamp) const -{ - CriticalSectionScoped lock(*_acmCritSect); - if(!HaveValidEncoder("LastEncodedTimestamp")) - { - return -1; +WebRtc_Word16 AudioCodingModuleImpl::DecoderParamByPlType( + const WebRtc_UWord8 payload_type, + WebRtcACMCodecParams& codec_params) const { + CriticalSectionScoped lock(*_acmCritSect); + for (WebRtc_Word16 id = 0; id < ACMCodecDB::kMaxNumCodecs; + id++) { + if (_codecs[id] != NULL) { + if (_codecs[id]->DecoderInitialized()) { + if (_codecs[id]->DecoderParams(&codec_params, payload_type)) { + return 0; + } + } } - timestamp = _codecs[_currentSendCodecIdx]->LastEncodedTimestamp(); + } + // If we are here it means that we could not find a + // codec with that payload type. reset the values to + // not acceptable values and return -1. + codec_params.codecInstant.plname[0] = '\0'; + codec_params.codecInstant.pacsize = 0; + codec_params.codecInstant.rate = 0; + codec_params.codecInstant.pltype = -1; + return -1; +} + +WebRtc_Word16 AudioCodingModuleImpl::DecoderListIDByPlName( + const char* name, const WebRtc_UWord16 frequency) const { + WebRtcACMCodecParams codec_params; + CriticalSectionScoped lock(*_acmCritSect); + for (WebRtc_Word16 id = 0; id < ACMCodecDB::kMaxNumCodecs; id++) { + if ((_codecs[id] != NULL)) { + if (_codecs[id]->DecoderInitialized()) { + assert(_registeredPlTypes[id] >= 0); + assert(_registeredPlTypes[id] <= 255); + _codecs[id]->DecoderParams( + &codec_params, (WebRtc_UWord8) _registeredPlTypes[id]); + if (!STR_CASE_CMP(codec_params.codecInstant.plname, name)) { + // Check if the given sampling frequency matches. + // A zero sampling frequency means we matching the names + // is sufficient and we don't need to check for the + // frequencies. + // Currently it is only iSAC which has one name but two + // sampling frequencies. + if ((frequency == 0)|| + (codec_params.codecInstant.plfreq == frequency)) { + return id; + } + } + } + } + } + // If we are here it means that we could not find a + // codec with that payload type. return -1. + return -1; +} + +WebRtc_Word32 AudioCodingModuleImpl::LastEncodedTimestamp( + WebRtc_UWord32& timestamp) const { + CriticalSectionScoped lock(*_acmCritSect); + if (!HaveValidEncoder("LastEncodedTimestamp")) { + return -1; + } + timestamp = _codecs[_currentSendCodecIdx]->LastEncodedTimestamp(); + return 0; +} + +WebRtc_Word32 AudioCodingModuleImpl::ReplaceInternalDTXWithWebRtc( + bool use_webrtc_dtx) { + CriticalSectionScoped lock(*_acmCritSect); + + if (!HaveValidEncoder("ReplaceInternalDTXWithWebRtc")) { + WEBRTC_TRACE( + webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Cannot replace codec internal DTX when no send codec is registered."); + return -1; + } + + WebRtc_Word32 res = _codecs[_currentSendCodecIdx]->ReplaceInternalDTX( + use_webrtc_dtx); + // Check if VAD is turned on, or if there is any error. + if (res == 1) { + _vadEnabled = true; + } else if (res < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "Failed to set ReplaceInternalDTXWithWebRtc(%d)", + use_webrtc_dtx); + return res; + } + + return 0; +} + +WebRtc_Word32 AudioCodingModuleImpl::IsInternalDTXReplacedWithWebRtc( + bool& uses_webrtc_dtx) { + CriticalSectionScoped lock(*_acmCritSect); + + if (!HaveValidEncoder("IsInternalDTXReplacedWithWebRtc")) { + return -1; + } + if (_codecs[_currentSendCodecIdx]->IsInternalDTXReplaced(&uses_webrtc_dtx) + < 0) { + return -1; + } + return 0; +} + +WebRtc_Word32 AudioCodingModuleImpl::SetISACMaxRate( + const WebRtc_UWord32 max_bit_per_sec) { + CriticalSectionScoped lock(*_acmCritSect); + + if (!HaveValidEncoder("SetISACMaxRate")) { + return -1; + } + + return _codecs[_currentSendCodecIdx]->SetISACMaxRate(max_bit_per_sec); +} + +WebRtc_Word32 AudioCodingModuleImpl::SetISACMaxPayloadSize( + const WebRtc_UWord16 max_size_bytes) { + CriticalSectionScoped lock(*_acmCritSect); + + if (!HaveValidEncoder("SetISACMaxPayloadSize")) { + return -1; + } + + return _codecs[_currentSendCodecIdx]->SetISACMaxPayloadSize( + max_size_bytes); +} + +WebRtc_Word32 AudioCodingModuleImpl::ConfigISACBandwidthEstimator( + const WebRtc_UWord8 frame_size_ms, + const WebRtc_UWord16 rate_bit_per_sec, + const bool enforce_frame_size) { + CriticalSectionScoped lock(*_acmCritSect); + + if (!HaveValidEncoder("ConfigISACBandwidthEstimator")) { + return -1; + } + + return _codecs[_currentSendCodecIdx]->ConfigISACBandwidthEstimator( + frame_size_ms, rate_bit_per_sec, enforce_frame_size); +} + +WebRtc_Word32 AudioCodingModuleImpl::SetBackgroundNoiseMode( + const ACMBackgroundNoiseMode mode) { + if ((mode < On) || (mode > Off)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "The specified background noise is out of range.\n"); + return -1; + } + return _netEq.SetBackgroundNoiseMode(mode); +} + +WebRtc_Word32 AudioCodingModuleImpl::BackgroundNoiseMode( + ACMBackgroundNoiseMode& mode) { + return _netEq.BackgroundNoiseMode(mode); +} + +WebRtc_Word32 AudioCodingModuleImpl::PlayoutTimestamp( + WebRtc_UWord32& timestamp) { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, + "PlayoutTimestamp()"); + return _netEq.PlayoutTimestamp(timestamp); +} + +bool AudioCodingModuleImpl::HaveValidEncoder(const char* caller_name) const { + if ((!_sendCodecRegistered) || (_currentSendCodecIdx < 0) || + (_currentSendCodecIdx >= ACMCodecDB::kNumCodecs)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "%s failed: No send codec is registered.", caller_name); + return false; + } + if ((_currentSendCodecIdx < 0) || + (_currentSendCodecIdx >= ACMCodecDB::kNumCodecs)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "%s failed: Send codec index out of range.", caller_name); + return false; + } + if (_codecs[_currentSendCodecIdx] == NULL) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, + "%s failed: Send codec is NULL pointer.", caller_name); + return false; + } + return true; +} + +WebRtc_Word32 AudioCodingModuleImpl::UnregisterReceiveCodec( + const WebRtc_Word16 payload_type) { + CriticalSectionScoped lock(*_acmCritSect); + int id; + + // Search through the list of registered payload types. + for (id = 0; id < ACMCodecDB::kMaxNumCodecs; id++) { + if (_registeredPlTypes[id] == payload_type) { + // We have found the id registered with the payload type. + break; + } + } + + if (id >= ACMCodecDB::kNumCodecs) { + // Payload type was not registered. No need to unregister. return 0; + } + + // Unregister the codec with the given payload type. + return UnregisterReceiveCodecSafe(id); } -WebRtc_Word32 -AudioCodingModuleImpl::ReplaceInternalDTXWithWebRtc(bool useWebRtcDTX) -{ - CriticalSectionScoped lock(*_acmCritSect); +WebRtc_Word32 AudioCodingModuleImpl::UnregisterReceiveCodecSafe( + const WebRtc_Word16 codec_id) { + const WebRtcNetEQDecoder *neteq_decoder = ACMCodecDB::NetEQDecoders(); + WebRtc_Word16 mirror_id = ACMCodecDB::MirrorID(codec_id); + bool stereo_receiver = false; - if(!HaveValidEncoder("ReplaceInternalDTXWithWebRtc")) - { + if (_codecs[codec_id] != NULL) { + if (_registeredPlTypes[codec_id] != -1) { + // Store stereo information for future use. + stereo_receiver = _stereoReceive[codec_id]; + + // Before deleting the decoder instance unregister from NetEQ. + if (_netEq.RemoveCodec(neteq_decoder[codec_id], + _stereoReceive[codec_id]) < 0) { + CodecInst codec; + ACMCodecDB::Codec(codec_id, &codec); WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Cannot replace codec internal DTX when no send codec is registered."); + "Unregistering %s-%d from NetEQ failed.", codec.plname, + codec.plfreq); return -1; - } + } - WebRtc_Word32 res = _codecs[_currentSendCodecIdx]->ReplaceInternalDTX(useWebRtcDTX); - // Check if VAD is turned on, or if there is any error - if(res == 1) - { - _vadEnabled = true; - } else if(res < 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Failed to set ReplaceInternalDTXWithWebRtc(%d)", useWebRtcDTX); - return res; - } + // CN is a special case for NetEQ, all three sampling frequencies + // are unregistered if one is deleted. + if (IsCodecCN(codec_id)) { + for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) { + if (IsCodecCN(i)) { + _stereoReceive[i] = false; + _registeredPlTypes[i] = -1; + } + } + } else { + if (codec_id == mirror_id) { + _codecs[codec_id]->DestructDecoder(); + if (_stereoReceive[codec_id]) { + _slaveCodecs[codec_id]->DestructDecoder(); + _stereoReceive[codec_id] = false; - return 0; -} + } + } + } -WebRtc_Word32 -AudioCodingModuleImpl::IsInternalDTXReplacedWithWebRtc(bool& usesWebRtcDTX) -{ - CriticalSectionScoped lock(*_acmCritSect); + // Check if this is the last registered stereo receive codec. + if (stereo_receiver) { + bool no_stereo = true; - if(!HaveValidEncoder("IsInternalDTXReplacedWithWebRtc")) - { - return -1; - } - if(_codecs[_currentSendCodecIdx]->IsInternalDTXReplaced(&usesWebRtcDTX) < 0) - { - return -1; - } - return 0; -} - - -WebRtc_Word32 -AudioCodingModuleImpl::SetISACMaxRate( - const WebRtc_UWord32 maxRateBitPerSec) -{ - CriticalSectionScoped lock(*_acmCritSect); - - if(!HaveValidEncoder("SetISACMaxRate")) - { - return -1; - } - - return _codecs[_currentSendCodecIdx]->SetISACMaxRate(maxRateBitPerSec); -} - - -WebRtc_Word32 -AudioCodingModuleImpl::SetISACMaxPayloadSize( - const WebRtc_UWord16 maxPayloadLenBytes) -{ - CriticalSectionScoped lock(*_acmCritSect); - - if(!HaveValidEncoder("SetISACMaxPayloadSize")) - { - return -1; - } - - return _codecs[_currentSendCodecIdx]->SetISACMaxPayloadSize(maxPayloadLenBytes); -} - -WebRtc_Word32 -AudioCodingModuleImpl::ConfigISACBandwidthEstimator( - const WebRtc_UWord8 initFrameSizeMsec, - const WebRtc_UWord16 initRateBitPerSec, - const bool enforceFrameSize) -{ - CriticalSectionScoped lock(*_acmCritSect); - - if(!HaveValidEncoder("ConfigISACBandwidthEstimator")) - { - return -1; - } - - return _codecs[_currentSendCodecIdx]->ConfigISACBandwidthEstimator( - initFrameSizeMsec, initRateBitPerSec, enforceFrameSize); -} - -WebRtc_Word32 -AudioCodingModuleImpl::SetBackgroundNoiseMode( - const ACMBackgroundNoiseMode mode) -{ - if((mode < On) || - (mode > Off)) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "The specified background noise is out of range.\n"); - return -1; - } - return _netEq.SetBackgroundNoiseMode(mode); -} - -WebRtc_Word32 -AudioCodingModuleImpl::BackgroundNoiseMode( - ACMBackgroundNoiseMode& mode) -{ - return _netEq.BackgroundNoiseMode(mode); -} - -WebRtc_Word32 -AudioCodingModuleImpl::PlayoutTimestamp( - WebRtc_UWord32& timestamp) -{ - WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, _id, - "PlayoutTimestamp()"); - return _netEq.PlayoutTimestamp(timestamp); -} - -bool -AudioCodingModuleImpl::HaveValidEncoder( - const char* callerName) const -{ - if((!_sendCodecRegistered) || - (_currentSendCodecIdx < 0) || - (_currentSendCodecIdx >= ACMCodecDB::kNumCodecs)) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "%s failed: No send codec is registered.", callerName); - return false; - } - if((_currentSendCodecIdx < 0) || - (_currentSendCodecIdx >= ACMCodecDB::kNumCodecs)) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "%s failed: Send codec index out of range.", callerName); - return false; - } - if(_codecs[_currentSendCodecIdx] == NULL) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "%s failed: Send codec is NULL pointer.", callerName); - return false; - } - return true; -} - -WebRtc_Word32 -AudioCodingModuleImpl::UnregisterReceiveCodec( - const WebRtc_Word16 payloadType) -{ - CriticalSectionScoped lock(*_acmCritSect); - WebRtc_Word16 codecID; - - // Search through the list of registered payload types - for (codecID = 0; codecID < ACMCodecDB::kMaxNumCodecs; codecID++) - { - if (_registeredPlTypes[codecID] == payloadType) - { - // we have found the codecID registered with the payload type + for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) { + if (_stereoReceive[i]) { + // We still have stereo codecs registered. + no_stereo = false; break; + } } - } - if(codecID >= ACMCodecDB::kNumCodecs) - { - // payload type was not registered. No need to unregister - return 0; - } - - // Unregister the codec with the given payload type - return UnregisterReceiveCodecSafe(codecID); -} - -WebRtc_Word32 -AudioCodingModuleImpl::UnregisterReceiveCodecSafe( - const WebRtc_Word16 codecID) -{ - const WebRtcNetEQDecoder *neteqDecoder = ACMCodecDB::NetEQDecoders(); - WebRtc_Word16 mirrorID = ACMCodecDB::MirrorID(codecID); - bool stereo_receiver = false; - - if(_codecs[codecID] != NULL) - { - if(_registeredPlTypes[codecID] != -1) - { - // Store stereo information for future use. - stereo_receiver = _stereoReceive[codecID]; - - // Before deleting the decoder instance unregister from NetEQ. - if(_netEq.RemoveCodec(neteqDecoder[codecID], _stereoReceive[codecID]) < 0) - { - CodecInst codecInst; - ACMCodecDB::Codec(codecID, &codecInst); - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, - "Unregistering %s-%d from NetEQ failed.", - codecInst.plname, codecInst.plfreq); - return -1; - } - - // CN is a special case for NetEQ, all three sampling frequencies - // are unregistered if one is deleted. - if (IsCodecCN(codecID)) { - for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) { - if (IsCodecCN(i)) { - _stereoReceive[i] = false; - _registeredPlTypes[i] = -1; - } - } - } else { - if(codecID == mirrorID) - { - _codecs[codecID]->DestructDecoder(); - if(_stereoReceive[codecID]) - { - _slaveCodecs[codecID]->DestructDecoder(); - _stereoReceive[codecID] = false; - - } - } - } - - // Check if this is the last registered stereo receive codec. - if (stereo_receiver) { - bool no_stereo = true; - - for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) { - if (_stereoReceive[i]) { - // We still have stereo codecs registered. - no_stereo = false; - break; - } - } - - // If we don't have any stereo codecs left, change status. - if (no_stereo) { - _netEq.RemoveSlaves(); // No longer need the slave. - _stereoReceiveRegistered = false; - } - } + // If we don't have any stereo codecs left, change status. + if (no_stereo) { + _netEq.RemoveSlaves(); // No longer need the slave. + _stereoReceiveRegistered = false; } + } } + } - if(_registeredPlTypes[codecID] == _receiveREDPayloadType) - { - // RED is going to be unregistered. - // set the following to an invalid value. - _receiveREDPayloadType = 255; - } - _registeredPlTypes[codecID] = -1; + if (_registeredPlTypes[codec_id] == _receiveREDPayloadType) { + // RED is going to be unregistered, set to an invalid value. + _receiveREDPayloadType = 255; + } + _registeredPlTypes[codec_id] = -1; - return 0; + return 0; } -WebRtc_Word32 -AudioCodingModuleImpl::REDPayloadISAC( - const WebRtc_Word32 isacRate, - const WebRtc_Word16 isacBwEstimate, - WebRtc_UWord8* payload, - WebRtc_Word16* payloadLenByte) -{ - if(!HaveValidEncoder("EncodeData")) - { - return -1; - } - WebRtc_Word16 status; - - status = _codecs[_currentSendCodecIdx]->REDPayloadISAC(isacRate, isacBwEstimate, - payload, payloadLenByte); - - return status; +WebRtc_Word32 AudioCodingModuleImpl::REDPayloadISAC( + const WebRtc_Word32 isac_rate, const WebRtc_Word16 isac_bw_estimate, + WebRtc_UWord8* payload, WebRtc_Word16* length_bytes) { + if (!HaveValidEncoder("EncodeData")) { + return -1; + } + WebRtc_Word16 status; + status = _codecs[_currentSendCodecIdx]->REDPayloadISAC(isac_rate, + isac_bw_estimate, + payload, + length_bytes); + return status; } -} // namespace webrtc +} // namespace webrtc diff --git a/src/modules/audio_coding/main/source/audio_coding_module_impl.h b/src/modules/audio_coding/main/source/audio_coding_module_impl.h index 42acd9e84c..eed192586c 100644 --- a/src/modules/audio_coding/main/source/audio_coding_module_impl.h +++ b/src/modules/audio_coding/main/source/audio_coding_module_impl.h @@ -24,383 +24,323 @@ class ACMGenericCodec; class CriticalSectionWrapper; class RWLockWrapper; -//#define TIMED_LOGGING - -#ifdef TIMED_LOGGING - #include "../test/timedtrace.h" -#endif - #ifdef ACM_QA_TEST # include #endif -class AudioCodingModuleImpl : public AudioCodingModule -{ -public: - // constructor - AudioCodingModuleImpl( - const WebRtc_Word32 id); +class AudioCodingModuleImpl : public AudioCodingModule { + public: + // Constructor + AudioCodingModuleImpl(const WebRtc_Word32 id); - // destructor - ~AudioCodingModuleImpl(); + // Destructor + ~AudioCodingModuleImpl(); - // get version information for ACM and all components - WebRtc_Word32 Version( - char* version, - WebRtc_UWord32& remainingBufferInBytes, - WebRtc_UWord32& position) const; - - // change the unique identifier of this object - virtual WebRtc_Word32 ChangeUniqueId( - const WebRtc_Word32 id); - - // returns the number of milliseconds until the module want - // a worker thread to call Process - WebRtc_Word32 TimeUntilNextProcess(); - - // Process any pending tasks such as timeouts - WebRtc_Word32 Process(); + // Change the unique identifier of this object. + virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id); - // used in conference to go to and from active encoding, hence - // in and out of mix - WebRtc_Word32 SetMode( - const bool passive); + // Returns the number of milliseconds until the module want a worker thread + // to call Process. + WebRtc_Word32 TimeUntilNextProcess(); + // Process any pending tasks such as timeouts. + WebRtc_Word32 Process(); + ///////////////////////////////////////// + // Sender + // - ///////////////////////////////////////// - // Sender - // + // Initialize send codec. + WebRtc_Word32 InitializeSender(); - // initialize send codec - WebRtc_Word32 InitializeSender(); + // Reset send codec. + WebRtc_Word32 ResetEncoder(); - // reset send codec - WebRtc_Word32 ResetEncoder(); + // Can be called multiple times for Codec, CNG, RED. + WebRtc_Word32 RegisterSendCodec(const CodecInst& send_codec); - // can be called multiple times for Codec, CNG, RED - WebRtc_Word32 RegisterSendCodec( - const CodecInst& sendCodec); + // Get current send codec. + WebRtc_Word32 SendCodec(CodecInst& current_codec) const; - // get current send codec - WebRtc_Word32 SendCodec( - CodecInst& currentSendCodec) const; + // Get current send frequency. + WebRtc_Word32 SendFrequency() const; - // get current send freq - WebRtc_Word32 SendFrequency() const; + // Get encode bitrate. + // Adaptive rate codecs return their current encode target rate, while other + // codecs return there longterm avarage or their fixed rate. + WebRtc_Word32 SendBitrate() const; - // Get encode bitrate - // Adaptive rate codecs return their current encode target rate, while other codecs - // return there longterm avarage or their fixed rate. - WebRtc_Word32 SendBitrate() const; + // Set available bandwidth, inform the encoder about the + // estimated bandwidth received from the remote party. + virtual WebRtc_Word32 SetReceivedEstimatedBandwidth(const WebRtc_Word32 bw); - // set available bandwidth, inform the encoder about the - // estimated bandwidth received from the remote party - virtual WebRtc_Word32 SetReceivedEstimatedBandwidth( - const WebRtc_Word32 bw); + // Register a transport callback which will be + // called to deliver the encoded buffers. + WebRtc_Word32 RegisterTransportCallback( + AudioPacketizationCallback* transport); - // register a transport callback which will be - // called to deliver the encoded buffers - WebRtc_Word32 RegisterTransportCallback( - AudioPacketizationCallback* transport); + // Used by the module to deliver messages to the codec module/application + // AVT(DTMF). + WebRtc_Word32 RegisterIncomingMessagesCallback( + AudioCodingFeedback* incoming_message, const ACMCountries cpt); - // Used by the module to deliver messages to the codec module/application - // AVT(DTMF) - WebRtc_Word32 RegisterIncomingMessagesCallback( - AudioCodingFeedback* incomingMessagesCallback, - const ACMCountries cpt); + // Add 10MS of raw (PCM) audio data to the encoder. + WebRtc_Word32 Add10MsData(const AudioFrame& audio_frame); - // Add 10MS of raw (PCM) audio data to the encoder - WebRtc_Word32 Add10MsData( - const AudioFrame& audioFrame); - - // set background noise mode for NetEQ, on, off or fade - WebRtc_Word32 SetBackgroundNoiseMode( - const ACMBackgroundNoiseMode mode); - - // get current background noise mode - WebRtc_Word32 BackgroundNoiseMode( - ACMBackgroundNoiseMode& mode); + // Set background noise mode for NetEQ, on, off or fade. + WebRtc_Word32 SetBackgroundNoiseMode(const ACMBackgroundNoiseMode mode); - ///////////////////////////////////////// - // (FEC) Forward Error Correction - // + // Get current background noise mode. + WebRtc_Word32 BackgroundNoiseMode(ACMBackgroundNoiseMode& mode); - // configure FEC status i.e on/off - WebRtc_Word32 SetFECStatus( - const bool enable); - - // Get FEC status - bool FECStatus() const; + ///////////////////////////////////////// + // (FEC) Forward Error Correction + // - ///////////////////////////////////////// - // (VAD) Voice Activity Detection - // and - // (CNG) Comfort Noise Generation - // + // Configure FEC status i.e on/off. + WebRtc_Word32 SetFECStatus(const bool enable_fec); - WebRtc_Word32 SetVAD( - const bool enableDTX = true, - const bool enableVAD = false, - const ACMVADMode vadMode = VADNormal); + // Get FEC status. + bool FECStatus() const; - WebRtc_Word32 VAD( - bool& dtxEnabled, - bool& vadEnabled, - ACMVADMode& vadMode) const; + ///////////////////////////////////////// + // (VAD) Voice Activity Detection + // and + // (CNG) Comfort Noise Generation + // - WebRtc_Word32 RegisterVADCallback( - ACMVADCallback* vadCallback); + WebRtc_Word32 SetVAD(const bool enable_dtx = true, + const bool enable_vad = false, + const ACMVADMode mode = VADNormal); - // Get VAD aggressiveness on the incoming stream - ACMVADMode ReceiveVADMode() const; + WebRtc_Word32 VAD(bool& dtx_enabled, bool& vad_enabled, + ACMVADMode& mode) const; - // Configure VAD aggressiveness on the incoming stream - WebRtc_Word16 SetReceiveVADMode( - const ACMVADMode mode); + WebRtc_Word32 RegisterVADCallback(ACMVADCallback* vadCallback); + // Get VAD aggressiveness on the incoming stream. + ACMVADMode ReceiveVADMode() const; - ///////////////////////////////////////// - // Receiver - // + // Configure VAD aggressiveness on the incoming stream. + WebRtc_Word16 SetReceiveVADMode(const ACMVADMode mode); - // initialize receiver, resets codec database etc - WebRtc_Word32 InitializeReceiver(); + ///////////////////////////////////////// + // Receiver + // - // reset the decoder state - WebRtc_Word32 ResetDecoder(); + // Initialize receiver, resets codec database etc. + WebRtc_Word32 InitializeReceiver(); - // get current receive freq - WebRtc_Word32 ReceiveFrequency() const; + // Reset the decoder state. + WebRtc_Word32 ResetDecoder(); - // get current playout freq - WebRtc_Word32 PlayoutFrequency() const; + // Get current receive frequency. + WebRtc_Word32 ReceiveFrequency() const; - // register possible reveive codecs, can be called multiple times, - // for codecs, CNG, DTMF, RED - WebRtc_Word32 RegisterReceiveCodec( - const CodecInst& receiveCodec); + // Get current playout frequency. + WebRtc_Word32 PlayoutFrequency() const; - // get current received codec - WebRtc_Word32 ReceiveCodec( - CodecInst& currentReceiveCodec) const; + // Register possible reveive codecs, can be called multiple times, + // for codecs, CNG, DTMF, RED. + WebRtc_Word32 RegisterReceiveCodec(const CodecInst& receive_codec); - // incoming packet from network parsed and ready for decode - WebRtc_Word32 IncomingPacket( - const WebRtc_UWord8* incomingPayload, - const WebRtc_Word32 payloadLength, - const WebRtcRTPHeader& rtpInfo); + // Get current received codec. + WebRtc_Word32 ReceiveCodec(CodecInst& current_codec) const; - // Incoming payloads, without rtp-info, the rtp-info will be created in ACM. - // One usage for this API is when pre-encoded files are pushed in ACM. - WebRtc_Word32 IncomingPayload( - const WebRtc_UWord8* incomingPayload, - const WebRtc_Word32 payloadLength, - const WebRtc_UWord8 payloadType, - const WebRtc_UWord32 timestamp = 0); + // Incoming packet from network parsed and ready for decode. + WebRtc_Word32 IncomingPacket(const WebRtc_UWord8* incoming_payload, + const WebRtc_Word32 payload_length, + const WebRtcRTPHeader& rtp_info); - // Minimum playout dealy (Used for lip-sync) - WebRtc_Word32 SetMinimumPlayoutDelay( - const WebRtc_Word32 timeMs); + // Incoming payloads, without rtp-info, the rtp-info will be created in ACM. + // One usage for this API is when pre-encoded files are pushed in ACM. + WebRtc_Word32 IncomingPayload(const WebRtc_UWord8* incoming_payload, + const WebRtc_Word32 payload_length, + const WebRtc_UWord8 payload_type, + const WebRtc_UWord32 timestamp = 0); - // configure Dtmf playout status i.e on/off playout the incoming outband Dtmf tone - WebRtc_Word32 SetDtmfPlayoutStatus( - const bool enable); + // Minimum playout dealy (used for lip-sync). + WebRtc_Word32 SetMinimumPlayoutDelay(const WebRtc_Word32 time_ms); - // Get Dtmf playout status - bool DtmfPlayoutStatus() const; + // Configure Dtmf playout status i.e on/off playout the incoming outband Dtmf + // tone. + WebRtc_Word32 SetDtmfPlayoutStatus(const bool enable); - // Estimate the Bandwidth based on the incoming stream - // This is also done in the RTP module - // need this for one way audio where the RTCP send the BW estimate - WebRtc_Word32 DecoderEstimatedBandwidth() const; + // Get Dtmf playout status. + bool DtmfPlayoutStatus() const; - // Set playout mode voice, fax - WebRtc_Word32 SetPlayoutMode( - const AudioPlayoutMode mode); + // Estimate the Bandwidth based on the incoming stream, needed + // for one way audio where the RTCP send the BW estimate. + // This is also done in the RTP module . + WebRtc_Word32 DecoderEstimatedBandwidth() const; - // Get playout mode voice, fax - AudioPlayoutMode PlayoutMode() const; + // Set playout mode voice, fax. + WebRtc_Word32 SetPlayoutMode(const AudioPlayoutMode mode); - // Get playout timestamp - WebRtc_Word32 PlayoutTimestamp( - WebRtc_UWord32& timestamp); + // Get playout mode voice, fax. + AudioPlayoutMode PlayoutMode() const; - // Get 10 milliseconds of raw audio data to play out - // automatic resample to the requested frequency if > 0 - WebRtc_Word32 PlayoutData10Ms( - const WebRtc_Word32 desiredFreqHz, - AudioFrame &audioFrame); + // Get playout timestamp. + WebRtc_Word32 PlayoutTimestamp(WebRtc_UWord32& timestamp); + // Get 10 milliseconds of raw audio data to play out, and + // automatic resample to the requested frequency if > 0. + WebRtc_Word32 PlayoutData10Ms(const WebRtc_Word32 desired_freq_hz, + AudioFrame &audio_frame); - ///////////////////////////////////////// - // Statistics - // + ///////////////////////////////////////// + // Statistics + // - WebRtc_Word32 NetworkStatistics( - ACMNetworkStatistics& statistics) const; + WebRtc_Word32 NetworkStatistics(ACMNetworkStatistics& statistics) const; - void DestructEncoderInst(void* ptrInst); + void DestructEncoderInst(void* inst); - WebRtc_Word16 AudioBuffer(WebRtcACMAudioBuff& audioBuff); + WebRtc_Word16 AudioBuffer(WebRtcACMAudioBuff& buffer); - // GET RED payload for iSAC. The method id called - // when 'this' ACM is default ACM. - WebRtc_Word32 REDPayloadISAC( - const WebRtc_Word32 isacRate, - const WebRtc_Word16 isacBwEstimate, - WebRtc_UWord8* payload, - WebRtc_Word16* payloadLenByte); - - WebRtc_Word16 SetAudioBuffer(WebRtcACMAudioBuff& audioBuff); - - WebRtc_UWord32 EarliestTimestamp() const; - - WebRtc_Word32 LastEncodedTimestamp(WebRtc_UWord32& timestamp) const; - - WebRtc_Word32 ReplaceInternalDTXWithWebRtc( - const bool useWebRtcDTX); - - WebRtc_Word32 IsInternalDTXReplacedWithWebRtc( - bool& usesWebRtcDTX); - - WebRtc_Word32 SetISACMaxRate( - const WebRtc_UWord32 rateBitPerSec); - - WebRtc_Word32 SetISACMaxPayloadSize( - const WebRtc_UWord16 payloadLenBytes); - - WebRtc_Word32 ConfigISACBandwidthEstimator( - const WebRtc_UWord8 initFrameSizeMsec, - const WebRtc_UWord16 initRateBitPerSec, - const bool enforceFrameSize = false); - - WebRtc_Word32 UnregisterReceiveCodec( - const WebRtc_Word16 payloadType); - -protected: - void UnregisterSendCodec(); - - WebRtc_Word32 UnregisterReceiveCodecSafe( - const WebRtc_Word16 codecID); - - ACMGenericCodec* CreateCodec( - const CodecInst& codec); - - WebRtc_Word16 DecoderParamByPlType( - const WebRtc_UWord8 payloadType, - WebRtcACMCodecParams& codecParams) const; - - WebRtc_Word16 DecoderListIDByPlName( - const char* payloadName, - const WebRtc_UWord16 sampFreqHz = 0) const; - - WebRtc_Word32 InitializeReceiverSafe(); - - bool HaveValidEncoder(const char* callerName) const; - - WebRtc_Word32 RegisterRecCodecMSSafe( - const CodecInst& receiveCodec, - WebRtc_Word16 codecId, - WebRtc_Word16 mirrorId, - ACMNetEQ::JB jitterBuffer); - -private: - // Change required states after starting to receive the codec corresponding - // to |index|. - int UpdateUponReceivingCodec(int index); - - // Remove all slaves and initialize a stereo slave with required codecs - // from the master. - int InitStereoSlave(); - - // Returns true if the codec's |index| is registered with the master and - // is a stereo codec, RED or CN. - bool IsCodecForSlave(int index); - - // Returns true if the |codec| is RED. - bool IsCodecRED(CodecInst codec); - // ...or if its |index| is RED. - bool IsCodecRED(int index); - - // Returns true if the |codec| is CN. - bool IsCodecCN(int index); - // ...or if its |index| is CN. - bool IsCodecCN(CodecInst codec); - - AudioPacketizationCallback* _packetizationCallback; - WebRtc_Word32 _id; - WebRtc_UWord32 _lastTimestamp; - WebRtc_UWord32 _lastInTimestamp; - CodecInst _sendCodecInst; - uint8_t _cng_nb_pltype; - uint8_t _cng_wb_pltype; - uint8_t _cng_swb_pltype; - uint8_t _red_pltype; - bool _vadEnabled; - bool _dtxEnabled; - ACMVADMode _vadMode; - ACMGenericCodec* _codecs[ACMCodecDB::kMaxNumCodecs]; - ACMGenericCodec* _slaveCodecs[ACMCodecDB::kMaxNumCodecs]; - WebRtc_Word16 _mirrorCodecIdx[ACMCodecDB::kMaxNumCodecs]; - bool _stereoReceive[ACMCodecDB::kMaxNumCodecs]; - bool _stereoReceiveRegistered; - bool _stereoSend; - int _prev_received_channel; - int _expected_channels; - WebRtc_Word32 _currentSendCodecIdx; - int _current_receive_codec_idx; - bool _sendCodecRegistered; - ACMResampler _inputResampler; - ACMResampler _outputResampler; - ACMNetEQ _netEq; - CriticalSectionWrapper* _acmCritSect; - ACMVADCallback* _vadCallback; - WebRtc_UWord8 _lastRecvAudioCodecPlType; - - // RED/FEC - bool _isFirstRED; - bool _fecEnabled; - WebRtc_UWord8* _redBuffer; - RTPFragmentationHeader* _fragmentation; - WebRtc_UWord32 _lastFECTimestamp; - // if no RED is registered as receive codec this - // will have an invalid value. - WebRtc_UWord8 _receiveREDPayloadType; - - // This is to keep track of CN instances where we can send DTMFs - WebRtc_UWord8 _previousPayloadType; - - // This keeps track of payload types associated with _codecs[]. - // We define it as signed variable and initialize with -1 to indicate - // unused elements. - WebRtc_Word16 _registeredPlTypes[ACMCodecDB::kMaxNumCodecs]; - - // Used when payloads are pushed into ACM without any RTP info - // One example is when pre-encoded bit-stream is pushed from - // a file. - WebRtcRTPHeader* _dummyRTPHeader; - WebRtc_UWord16 _recvPlFrameSizeSmpls; - - bool _receiverInitialized; - ACMDTMFDetection* _dtmfDetector; - - AudioCodingFeedback* _dtmfCallback; - WebRtc_Word16 _lastDetectedTone; - CriticalSectionWrapper* _callbackCritSect; -#ifdef TIMED_LOGGING - TimedTrace _trace; -#endif - - AudioFrame _audioFrame; + // GET RED payload for iSAC. The method id called when 'this' ACM is + // the default ACM. + WebRtc_Word32 REDPayloadISAC(const WebRtc_Word32 isac_rate, + const WebRtc_Word16 isac_bw_estimate, + WebRtc_UWord8* payload, + WebRtc_Word16* length_bytes); + + WebRtc_Word16 SetAudioBuffer(WebRtcACMAudioBuff& buffer); + + WebRtc_UWord32 EarliestTimestamp() const; + + WebRtc_Word32 LastEncodedTimestamp(WebRtc_UWord32& timestamp) const; + + WebRtc_Word32 ReplaceInternalDTXWithWebRtc(const bool use_webrtc_dtx); + + WebRtc_Word32 IsInternalDTXReplacedWithWebRtc(bool& uses_webrtc_dtx); + + WebRtc_Word32 SetISACMaxRate(const WebRtc_UWord32 max_bit_per_sec); + + WebRtc_Word32 SetISACMaxPayloadSize(const WebRtc_UWord16 max_size_bytes); + + WebRtc_Word32 ConfigISACBandwidthEstimator( + const WebRtc_UWord8 frame_size_ms, + const WebRtc_UWord16 rate_bit_per_sec, + const bool enforce_frame_size = false); + + WebRtc_Word32 UnregisterReceiveCodec(const WebRtc_Word16 payload_type); + + protected: + void UnregisterSendCodec(); + + WebRtc_Word32 UnregisterReceiveCodecSafe(const WebRtc_Word16 id); + + ACMGenericCodec* CreateCodec(const CodecInst& codec); + + WebRtc_Word16 DecoderParamByPlType(const WebRtc_UWord8 payload_type, + WebRtcACMCodecParams& codec_params) const; + + WebRtc_Word16 DecoderListIDByPlName( + const char* name, const WebRtc_UWord16 frequency = 0) const; + + WebRtc_Word32 InitializeReceiverSafe(); + + bool HaveValidEncoder(const char* caller_name) const; + + WebRtc_Word32 RegisterRecCodecMSSafe(const CodecInst& receive_codec, + WebRtc_Word16 codec_id, + WebRtc_Word16 mirror_id, + ACMNetEQ::JB jitter_buffer); + + private: + // Change required states after starting to receive the codec corresponding + // to |index|. + int UpdateUponReceivingCodec(int index); + + // Remove all slaves and initialize a stereo slave with required codecs + // from the master. + int InitStereoSlave(); + + // Returns true if the codec's |index| is registered with the master and + // is a stereo codec, RED or CN. + bool IsCodecForSlave(int index); + + // Returns true if the |codec| is RED. + bool IsCodecRED(CodecInst codec); + // ...or if its |index| is RED. + bool IsCodecRED(int index); + + // Returns true if the |codec| is CN. + bool IsCodecCN(int index); + // ...or if its |index| is CN. + bool IsCodecCN(CodecInst codec); + + AudioPacketizationCallback* _packetizationCallback; + WebRtc_Word32 _id; + WebRtc_UWord32 _lastTimestamp; + WebRtc_UWord32 _lastInTimestamp; + CodecInst _sendCodecInst; + uint8_t _cng_nb_pltype; + uint8_t _cng_wb_pltype; + uint8_t _cng_swb_pltype; + uint8_t _red_pltype; + bool _vadEnabled; + bool _dtxEnabled; + ACMVADMode _vadMode; + ACMGenericCodec* _codecs[ACMCodecDB::kMaxNumCodecs]; + ACMGenericCodec* _slaveCodecs[ACMCodecDB::kMaxNumCodecs]; + WebRtc_Word16 _mirrorCodecIdx[ACMCodecDB::kMaxNumCodecs]; + bool _stereoReceive[ACMCodecDB::kMaxNumCodecs]; + bool _stereoReceiveRegistered; + bool _stereoSend; + int _prev_received_channel; + int _expected_channels; + WebRtc_Word32 _currentSendCodecIdx; + int _current_receive_codec_idx; + bool _sendCodecRegistered; + ACMResampler _inputResampler; + ACMResampler _outputResampler; + ACMNetEQ _netEq; + CriticalSectionWrapper* _acmCritSect; + ACMVADCallback* _vadCallback; + WebRtc_UWord8 _lastRecvAudioCodecPlType; + + // RED/FEC. + bool _isFirstRED; + bool _fecEnabled; + WebRtc_UWord8* _redBuffer; + RTPFragmentationHeader* _fragmentation; + WebRtc_UWord32 _lastFECTimestamp; + // If no RED is registered as receive codec this + // will have an invalid value. + WebRtc_UWord8 _receiveREDPayloadType; + + // This is to keep track of CN instances where we can send DTMFs. + WebRtc_UWord8 _previousPayloadType; + + // This keeps track of payload types associated with _codecs[]. + // We define it as signed variable and initialize with -1 to indicate + // unused elements. + WebRtc_Word16 _registeredPlTypes[ACMCodecDB::kMaxNumCodecs]; + + // Used when payloads are pushed into ACM without any RTP info + // One example is when pre-encoded bit-stream is pushed from + // a file. + WebRtcRTPHeader* _dummyRTPHeader; + WebRtc_UWord16 _recvPlFrameSizeSmpls; + + bool _receiverInitialized; + ACMDTMFDetection* _dtmfDetector; + + AudioCodingFeedback* _dtmfCallback; + WebRtc_Word16 _lastDetectedTone; + CriticalSectionWrapper* _callbackCritSect; + + AudioFrame _audioFrame; #ifdef ACM_QA_TEST - FILE* _outgoingPL; - FILE* _incomingPL; + FILE* _outgoingPL; + FILE* _incomingPL; #endif }; -} // namespace webrtc +} // namespace webrtc #endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_SOURCE_AUDIO_CODING_MODULE_IMPL_H_