/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // 'conversion' conversion from 'type1' to 'type2', possible loss of data #pragma warning(disable: 4267) #include #include "acm_codec_database.h" #include "acm_common_defs.h" #include "trace.h" // Includes needed to get version info // and to create the codecs #include "acm_pcma.h" #include "acm_pcmu.h" #include "g711_interface.h" #include "webrtc_neteq.h" #include "webrtc_cng.h" #include "acm_cng.h" #ifdef WEBRTC_CODEC_AVT #include "acm_dtmf_playout.h" #endif #ifdef WEBRTC_CODEC_RED #include "acm_red.h" #endif #ifdef WEBRTC_CODEC_ILBC #include "acm_ilbc.h" #include "ilbc.h" #endif #ifdef WEBRTC_CODEC_ISAC #include "acm_isac.h" #include "acm_isac_macros.h" #include "isac.h" #endif #ifdef WEBRTC_CODEC_ISACFX #include "acm_isac.h" #include "acm_isac_macros.h" #include "isacfix.h" #endif #ifdef WEBRTC_CODEC_PCM16 #include "pcm16b.h" #include "acm_pcm16b.h" #endif #ifdef WEBRTC_CODEC_G722 #include "acm_g722.h" #include "g722_interface.h" #endif namespace webrtc { #define TEMPORARY_BUFFER_SIZE 500 bool ACMCodecDB::_isInitiated = false; WebRtc_Word16 ACMCodecDB::_noOfCodecs = 0; WebRtc_Word16 ACMCodecDB::_noNetEqDecoders = 0; WebRtc_Word16 ACMCodecDB::_noPayloads = 0; WebRtc_Word16 ACMCodecDB::isac = -1; WebRtc_Word16 ACMCodecDB::isacswb = -1; WebRtc_Word16 ACMCodecDB::pcm16b = -1; WebRtc_Word16 ACMCodecDB::pcm16bwb = -1; WebRtc_Word16 ACMCodecDB::pcm16bswb32 = -1; WebRtc_Word16 ACMCodecDB::pcm16bswb48 = -1; WebRtc_Word16 ACMCodecDB::pcmu = -1; WebRtc_Word16 ACMCodecDB::pcma = -1; WebRtc_Word16 ACMCodecDB::ilbc = -1; WebRtc_Word16 ACMCodecDB::gsmAMR = -1; WebRtc_Word16 ACMCodecDB::gsmAMRWB = -1; WebRtc_Word16 ACMCodecDB::g722 = -1; WebRtc_Word16 ACMCodecDB::g722_1_32 = -1; WebRtc_Word16 ACMCodecDB::g722_1_24 = -1; WebRtc_Word16 ACMCodecDB::g722_1_16 = -1; WebRtc_Word16 ACMCodecDB::g722_1C_48 = -1; WebRtc_Word16 ACMCodecDB::g722_1C_32 = -1; WebRtc_Word16 ACMCodecDB::g722_1C_24 = -1; WebRtc_Word16 ACMCodecDB::g729 = -1; WebRtc_Word16 ACMCodecDB::gsmfr = -1; WebRtc_Word16 ACMCodecDB::speex8 = -1; WebRtc_Word16 ACMCodecDB::speex16 = -1; WebRtc_Word16 ACMCodecDB::cnNB = -1; WebRtc_Word16 ACMCodecDB::cnWB = -1; WebRtc_Word16 ACMCodecDB::cnSWB = -1; WebRtc_Word16 ACMCodecDB::avt = -1; WebRtc_Word16 ACMCodecDB::red = -1; WebRtc_UWord8 ACMCodecDB::_nrOfAllowedPacSizes[MAX_NR_OF_CODECS]; WebRtc_UWord16 ACMCodecDB::_allowedPacSizesSmpl[MAX_NR_OF_CODECS][MAX_NR_OF_PACSIZES]; CodecInst ACMCodecDB::_mycodecs[MAX_NR_OF_CODECS]; enum WebRtcNetEQDecoder ACMCodecDB::_netEqDecoders[MAX_NR_OF_CODECS]; WebRtc_Word8 ACMCodecDB::_versions[VERSION_SIZE]; WebRtc_UWord16 ACMCodecDB::_basicCodingBlockSmpl[MAX_NR_OF_CODECS]; WebRtc_UWord16 ACMCodecDB::_channelSupport[MAX_NR_OF_CODECS]; WebRtc_UWord32 ACMCodecDB::_versionStringSize = 0; // We dynamically allocate some of the dynamic payload types to the defined codecs // Note! There are a limited number of payload types. If more codecs are defined // they will receive reserved fixed payload types (values 65-95). static int kDynamicPayloadtypes[MAX_NR_OF_CODECS] = { 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65 }; WebRtc_Word16 ACMCodecDB::Codec( WebRtc_Word16 listnr, CodecInst* codec_inst) { // Error check to se that listnr is between 0 and (_noOfCodecs - 1) if ((listnr < 0) || (listnr >= _noOfCodecs)) { return -1; } memcpy(codec_inst,&_mycodecs[listnr],sizeof(CodecInst)); return 0; } WebRtc_Word16 ACMCodecDB::CodecNumber( const CodecInst* codecInst, WebRtc_Word16& mirrorID, WebRtc_Word8* errMessage, WebRtc_Word16 maxErrMsgLenByte) { WebRtc_Word16 codecID = ACMCodecDB::CodecNumber(codecInst, mirrorID); if((codecID < 0) && (errMessage != NULL)) { WebRtc_Word8 myErrMsg[1000]; if (codecID == -10) { // Codec not supported sprintf(myErrMsg, "Call to ACMCodecDB::CodecNumber failed, plname=%s is \ not a valid codec", codecInst->plname); } else if (codecID == -20) { // Sampling frequency doesn't match codec sprintf(myErrMsg, "Call to ACMCodecDB::CodecNumber failed, plfreq=%d is \ not a valid frequency for the codec %s", codecInst->plfreq, codecInst->plname); } else if (codecID == -30) { // Wrong payload type for Comfort Noise sprintf(myErrMsg, "Call to ACMCodecDB::CodecNumber failed, payload \ number %d is out of range for %s", codecInst->pltype, codecInst->plname); } else if (codecID == -40) { // Wrong payload type for RED sprintf(myErrMsg, "Call to ACMCodecDB::CodecNumber failed, payload \ number %d is out of range for %s", codecInst->pltype, codecInst->plname); } else if (codecID == -50) { // Packet size is out of range for the codec sprintf(myErrMsg, "Call to ACMCodecDB::CodecNumber failed, Packet \ size is out of range for %s", codecInst->plname); } else if (codecID == -60) { // Not a valid rate for the codec sprintf(myErrMsg, "Call to ACMCodecDB::CodecNumber failed, rate=%d \ is not a valid rate for %s", codecInst->rate, codecInst->plname); } else { // Other error sprintf(myErrMsg, "invalid codec parameters to be registered, \ ACMCodecDB::CodecNumber failed"); } strncpy(errMessage, myErrMsg, maxErrMsgLenByte - 1); // make sure that the massage is null-terminated. errMessage[maxErrMsgLenByte - 1] = '\0'; } return codecID; } WebRtc_Word16 ACMCodecDB::CodecNumber( const CodecInst* codec_inst, WebRtc_Word16& mirrorID) { WebRtc_Word16 codecNumber = -1; WebRtc_Word16 nameMatch = 0; // Find a matching payload name and frequency in the codec list // Need to check both since some codecs have several codec entries with // Different frequencies (like iSAC) for(WebRtc_Word16 i = 0; i < _noOfCodecs; i++) { if(STR_CASE_CMP(_mycodecs[i].plname, codec_inst->plname) == 0) { //We have found a matching codec name in the list nameMatch = 1; // Check if frequncy match if (codec_inst->plfreq == _mycodecs[i].plfreq) { codecNumber = i; break; } } } if(codecNumber == -1) { if (!nameMatch) { // Codec name doesn't match any codec in the list return -10; } else { // Error in payload frequency, doesn't match codec return -20; } } // Check the validity of payload type if(ValidPayloadType(codec_inst->pltype) < 0) { // Payload type out of range return -40; } // Comfort Noise is special case, packet-size & rate is not checked if(STR_CASE_CMP(_mycodecs[codecNumber].plname, "CN") == 0) { mirrorID = codecNumber; return codecNumber; } // RED is special case, packet-size & rate is not checked if(STR_CASE_CMP(_mycodecs[codecNumber].plname, "red") == 0) { mirrorID = codecNumber; return codecNumber; } // Check the validity of packet size if(_nrOfAllowedPacSizes[codecNumber] > 0) { // Check that the new packet size is in the valid range. bool pacSizeOK = false; for(WebRtc_Word32 i=0;i< _nrOfAllowedPacSizes[codecNumber];i++) { if(codec_inst->pacsize == _allowedPacSizesSmpl[codecNumber][i]) { pacSizeOK = true; break; } } if(!pacSizeOK) { // Packet size is out of range return -50; } } if( codec_inst->pacsize < 1) { // Packet size is out of range return -50; } mirrorID = codecNumber; // Check the validity of rate if(STR_CASE_CMP("isac", codec_inst->plname) == 0) { if(IsISACRateValid(codec_inst->rate)) { // Set mirrorID to iSAC WB which is only created // once to be used both for iSAC WB and SWB, because // they need to share struct mirrorID = ACMCodecDB::isac; return codecNumber; } else { // Not a valid rate return -60; } } else if(STR_CASE_CMP("ilbc", codec_inst->plname) == 0) { return IsILBCRateValid(codec_inst->rate, codec_inst->pacsize) ? codecNumber : -60; } return IsRateValid(codecNumber, codec_inst->rate) ? codecNumber : -60; } WebRtc_Word16 ACMCodecDB::ReceiverCodecNumber( const CodecInst& codecInst, WebRtc_Word16& mirrorID) { WebRtc_Word16 codecNumber = -1; WebRtc_Word16 nameMatch = 0; // Find a matching payload name and frequency in the codec list // Need to check both since some codecs have several codec entries with // Different frequencies (like iSAC) for(WebRtc_Word16 i = 0; i < _noOfCodecs; i++) { if(STR_CASE_CMP(_mycodecs[i].plname, codecInst.plname) == 0) { //We have found a matching codec name in the list nameMatch = 1; // Check if frequency match if (codecInst.plfreq == _mycodecs[i].plfreq) { codecNumber = i; mirrorID = codecNumber; // Check if codec is iSAC, set mirrorID to iSAC WB // which is only created once to be used both for // iSAC WB and SWB, because they need to share struct if(STR_CASE_CMP(codecInst.plname, "ISAC") == 0) { mirrorID = ACMCodecDB::isac; } break; } } } if(codecNumber == -1) { return codecNumber; } return codecNumber; } // Return number of codecs in the database WebRtc_Word16 ACMCodecDB::NoOfCodecs() { return _noOfCodecs; } // Return number of NetEQ decoders in the database. // Note that the number is huigher than _moOfCodecs because some payload names // are treated as different decoders in NetEQ, like iSAC wb and swb. WebRtc_Word16 ACMCodecDB::NoNetEqDecoders() { return _noNetEqDecoders; } // Return the codec sampling frequency for code number "listnr" in database WebRtc_Word32 ACMCodecDB::CodecFreq(WebRtc_Word16 listnr) { // Error check to se that listnr is between 0 and (_noOfCodecs - 1) if ( listnr < 0 || listnr >= _noOfCodecs) return -1; return _mycodecs[listnr].plfreq; } // Return the codecs basic coding block size in samples WebRtc_Word16 ACMCodecDB::BasicCodingBlock( WebRtc_Word16 listNr) { // Error check to se that listnr is between 0 and (_noOfCodecs - 1) if ( listNr < 0 || listNr >= _noOfCodecs) return -1; return _basicCodingBlockSmpl[listNr]; } // Return the NetEQ decoder database enum WebRtcNetEQDecoder* ACMCodecDB::NetEqDecoders() { return _netEqDecoders; } // All version numbers for the codecs in the data base are listed in text. WebRtc_Word16 ACMCodecDB::CodecsVersion( WebRtc_Word8* version, WebRtc_UWord32& remainingBufferInBytes, WebRtc_UWord32& position) { WebRtc_UWord32 len = position; strncpy(&version[len], _versions, remainingBufferInBytes); position = (WebRtc_UWord32)strlen(version); remainingBufferInBytes -= (position - len); if(remainingBufferInBytes < _versionStringSize) { return -1; } return 0; } // Get mirror id. The Id is used for codecs sharing struct for settings that // need different payload types. WebRtc_Word16 ACMCodecDB::MirrorID( const WebRtc_Word16 codecID) { if(STR_CASE_CMP(_mycodecs[codecID].plname, "isac") == 0) { return ACMCodecDB::isac; } else { return codecID; } } ACMGenericCodec* ACMCodecDB::CreateCodecInstance( const CodecInst* codecInst) { // All we have support for right now if(!STR_CASE_CMP(codecInst->plname, "ISAC")) { #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) return new ACMISAC(isac); #endif } else if(!STR_CASE_CMP(codecInst->plname, "PCMU")) { return new ACMPCMU(pcmu); } else if(!STR_CASE_CMP(codecInst->plname, "PCMA")) { return new ACMPCMA(pcma); } else if(!STR_CASE_CMP(codecInst->plname, "ILBC")) { #ifdef WEBRTC_CODEC_ILBC return new ACMILBC(ilbc); #endif } else if(!STR_CASE_CMP(codecInst->plname, "G722")) { #ifdef WEBRTC_CODEC_G722 return new ACMG722(g722); #endif } else if(!STR_CASE_CMP(codecInst->plname, "CN")) { // We need to check sampling frequency // know what codec to create. WebRtc_Word16 codecID; switch(codecInst->plfreq) { case 8000: { codecID = ACMCodecDB::cnNB; break; } case 16000: { codecID = ACMCodecDB::cnWB; break; } case 32000: { codecID = ACMCodecDB::cnSWB; break; } default: return NULL; } return new ACMCNG(codecID); } else if(!STR_CASE_CMP(codecInst->plname, "L16")) { #ifdef WEBRTC_CODEC_PCM16 // For this codec we need to check sampling frequency // to know what codec to create. WebRtc_Word16 codecID; switch(codecInst->plfreq) { case 8000: { codecID = ACMCodecDB::pcm16b; break; } case 16000: { codecID = ACMCodecDB::pcm16bwb; break; } case 32000: { codecID = ACMCodecDB::pcm16bswb32; break; } default: return NULL; } return new ACMPCM16B(codecID); #endif } else if(!STR_CASE_CMP(codecInst->plname, "telephone-event")) { #ifdef WEBRTC_CODEC_AVT return new ACMDTMFPlayout(avt); #endif } else if(!STR_CASE_CMP(codecInst->plname, "red")) { #ifdef WEBRTC_CODEC_RED return new ACMRED(red); #endif } return NULL; } //Here we build the complete database "_mycodecs" of our codecs void ACMCodecDB::initACMCodecDB() { if(_isInitiated) { return; } else { _isInitiated = true; } WebRtc_Word8 versionNrBuff[TEMPORARY_BUFFER_SIZE]; WebRtc_Word32 remainingSize = VERSION_SIZE; _versions[0] = '\0'; // Init the stereo settings vector for (int i=0; i= 10000))) { return true; } else { return false; } #endif } // Check if the bitrate is valid for iLBC bool ACMCodecDB::IsILBCRateValid( #ifndef WEBRTC_CODEC_ILBC const WebRtc_Word32 /* rate */, const WebRtc_Word16 /* frameSizeSamples */) { return false; #else const WebRtc_Word32 rate, const WebRtc_Word16 frameSizeSamples) { if(((frameSizeSamples == 240) || (frameSizeSamples == 480)) && (rate == 13300)) { return true; } else if(((frameSizeSamples == 160) || (frameSizeSamples == 320)) && (rate == 15200)) { return true; } else { return false; } #endif } // Check if the payload type is valid WebRtc_Word16 ACMCodecDB::ValidPayloadType( const int payloadType) { if((payloadType < 0) || (payloadType > 127)) { return -1; } return 0; } } // namespace webrtc