int WebRtcNetEQ_DbAdd(CodecDbInst_t *inst, enum WebRtcNetEQDecoder codec, WebRtc_Word16 payloadType, FuncDecode funcDecode, FuncDecode funcDecodeRCU, FuncDecodePLC funcDecodePLC, FuncDecodeInit funcDecodeInit, FuncAddLatePkt funcAddLatePkt, FuncGetMDinfo funcGetMDinfo, FuncGetPitchInfo funcGetPitch, FuncUpdBWEst funcUpdBWEst, FuncGetErrorCode funcGetErrorCode, void* codec_state, WebRtc_UWord16 codec_fs) { int temp; int insertCNGcodec = 0, overwriteCNGcodec = 0, CNGpos = -1; #ifndef NETEQ_RED_CODEC if (codec == kDecoderRED) { return CODEC_DB_UNSUPPORTED_CODEC; } #endif if (((int) codec <= (int) kDecoderReservedStart) || ((int) codec >= (int) kDecoderReservedEnd)) { return CODEC_DB_UNSUPPORTED_CODEC; } if ((codec_fs != 8000) #ifdef NETEQ_WIDEBAND &&(codec_fs!=16000) #endif #ifdef NETEQ_32KHZ_WIDEBAND &&(codec_fs!=32000) #endif #if defined(NETEQ_48KHZ_WIDEBAND) || defined(NETEQ_OPUS_CODEC) &&(codec_fs!=48000) #endif ) { return CODEC_DB_UNSUPPORTED_FS; } /* Ensure that the codec type is supported */ switch (codec) { #ifdef NETEQ_PCM16B_CODEC case kDecoderPCM16B : case kDecoderPCM16B_2ch : #endif #ifdef NETEQ_G711_CODEC case kDecoderPCMu : case kDecoderPCMa : case kDecoderPCMu_2ch : case kDecoderPCMa_2ch : #endif #ifdef NETEQ_ILBC_CODEC case kDecoderILBC : #endif #ifdef NETEQ_ISAC_CODEC case kDecoderISAC : #endif #ifdef NETEQ_ISAC_SWB_CODEC case kDecoderISACswb : #endif #ifdef NETEQ_OPUS_CODEC case kDecoderOpus : case kDecoderOpus_2ch : #endif #ifdef NETEQ_G722_CODEC case kDecoderG722 : case kDecoderG722_2ch : #endif #ifdef NETEQ_WIDEBAND case kDecoderPCM16Bwb : case kDecoderPCM16Bwb_2ch : #endif #ifdef NETEQ_32KHZ_WIDEBAND case kDecoderPCM16Bswb32kHz : case kDecoderPCM16Bswb32kHz_2ch : #endif #ifdef NETEQ_CNG_CODEC case kDecoderCNG : #endif #ifdef NETEQ_ATEVENT_DECODE case kDecoderAVT : #endif #ifdef NETEQ_RED_CODEC case kDecoderRED : #endif #ifdef NETEQ_48KHZ_WIDEBAND case kDecoderPCM16Bswb48kHz : #endif #ifdef NETEQ_ARBITRARY_CODEC case kDecoderArbitrary: #endif #ifdef NETEQ_G729_CODEC case kDecoderG729: #endif #ifdef NETEQ_G729_1_CODEC case kDecoderG729_1 : #endif #ifdef NETEQ_G726_CODEC case kDecoderG726_16 : case kDecoderG726_24 : case kDecoderG726_32 : case kDecoderG726_40 : #endif #ifdef NETEQ_G722_1_CODEC case kDecoderG722_1_16 : case kDecoderG722_1_24 : case kDecoderG722_1_32 : #endif #ifdef NETEQ_G722_1C_CODEC case kDecoderG722_1C_24 : case kDecoderG722_1C_32 : case kDecoderG722_1C_48 : #endif #ifdef NETEQ_SPEEX_CODEC case kDecoderSPEEX_8 : case kDecoderSPEEX_16 : #endif #ifdef NETEQ_CELT_CODEC case kDecoderCELT_32 : case kDecoderCELT_32_2ch : #endif #ifdef NETEQ_GSMFR_CODEC case kDecoderGSMFR : #endif #ifdef NETEQ_AMR_CODEC case kDecoderAMR : #endif #ifdef NETEQ_AMRWB_CODEC case kDecoderAMRWB : #endif { /* If we end up here, the inserted codec is supported => Do nothing */ break; } default: { /* If we get to this point, the inserted codec is not supported */ return CODEC_DB_UNSUPPORTED_CODEC; } } /* Check to see if payload type is taken */ if (WebRtcNetEQ_DbGetCodec(inst, payloadType) > 0) { return CODEC_DB_PAYLOAD_TAKEN; } /* Special case for CNG codecs */ if (codec == kDecoderCNG) { /* check if this is first CNG codec to be registered */ if (WebRtcNetEQ_DbGetPayload(inst, codec) == CODEC_DB_NOT_EXIST2) { /* no other CNG codec found */ insertCNGcodec = 1; } /* find the appropriate insert position in CNG payload vector */ switch (codec_fs) { #ifdef NETEQ_WIDEBAND case 16000: CNGpos = 1; break; #endif #ifdef NETEQ_32KHZ_WIDEBAND case 32000: CNGpos = 2; break; #endif #ifdef NETEQ_48KHZ_WIDEBAND case 48000: CNGpos = 3; break; #endif default: /* 8000 Hz case */ CNGpos = 0; /* * The 8 kHz CNG payload type is the one associated with the regular codec DB * should override any other setting. * Overwrite if this isn't the first CNG */ overwriteCNGcodec = !insertCNGcodec; break; } /* insert CNG payload type */ inst->CNGpayloadType[CNGpos] = payloadType; } if ((codec != kDecoderCNG) || (insertCNGcodec == 1) || (overwriteCNGcodec == 1)) { /* Check if we have reached the maximum numbers of simultaneous codecs */ if (inst->nrOfCodecs == NUM_CODECS) return CODEC_DB_FULL; /* Check that codec has not already been initialized to DB => remove it and reinitialize according to new spec */ if ((inst->position[codec] != -1) && (overwriteCNGcodec != 1)) { /* if registering multiple CNG codecs, don't remove, just overwrite */ WebRtcNetEQ_DbRemove(inst, codec); } if (overwriteCNGcodec == 1) { temp = inst->position[codec]; } else { temp = inst->nrOfCodecs; /* Store this codecs position */ inst->position[codec] = temp; inst->nrOfCodecs++; } inst->payloadType[temp] = payloadType; /* Copy to database */ inst->codec_state[temp] = codec_state; inst->funcDecode[temp] = funcDecode; inst->funcDecodeRCU[temp] = funcDecodeRCU; inst->funcAddLatePkt[temp] = funcAddLatePkt; inst->funcDecodeInit[temp] = funcDecodeInit; inst->funcDecodePLC[temp] = funcDecodePLC; inst->funcGetMDinfo[temp] = funcGetMDinfo; inst->funcGetPitch[temp] = funcGetPitch; inst->funcUpdBWEst[temp] = funcUpdBWEst; inst->funcGetErrorCode[temp] = funcGetErrorCode; inst->codec_fs[temp] = codec_fs; } return 0; }
int WebRtcNetEQ_RecInInternal(MCUInst_t *MCU_inst, RTPPacket_t *RTPpacketInput, WebRtc_UWord32 uw32_timeRec) { RTPPacket_t RTPpacket[2]; int i_k; int i_ok = 0, i_No_Of_Payloads = 1; WebRtc_Word16 flushed = 0; WebRtc_Word16 codecPos; int curr_Codec; WebRtc_Word16 isREDPayload = 0; WebRtc_Word32 temp_bufsize = MCU_inst->PacketBuffer_inst.numPacketsInBuffer; #ifdef NETEQ_RED_CODEC RTPPacket_t* RTPpacketPtr[2]; /* Support for redundancy up to 2 payloads */ RTPpacketPtr[0] = &RTPpacket[0]; RTPpacketPtr[1] = &RTPpacket[1]; #endif /* * Copy from input RTP packet to local copy * (mainly to enable multiple payloads using RED) */ WEBRTC_SPL_MEMCPY_W8(&RTPpacket[0], RTPpacketInput, sizeof(RTPPacket_t)); /* Reinitialize NetEq if it's needed (changed SSRC or first call) */ if ((RTPpacket[0].ssrc != MCU_inst->ssrc) || (MCU_inst->first_packet == 1)) { WebRtcNetEQ_RTCPInit(&MCU_inst->RTCP_inst, RTPpacket[0].seqNumber); MCU_inst->first_packet = 0; /* Flush the buffer */ WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst); /* Store new SSRC */ MCU_inst->ssrc = RTPpacket[0].ssrc; /* Update codecs */ MCU_inst->timeStamp = RTPpacket[0].timeStamp; MCU_inst->current_Payload = RTPpacket[0].payloadType; /*Set MCU to update codec on next SignalMCU call */ MCU_inst->new_codec = 1; /* Reset timestamp scaling */ MCU_inst->TSscalingInitialized = 0; } /* Call RTCP statistics */ i_ok |= WebRtcNetEQ_RTCPUpdate(&(MCU_inst->RTCP_inst), RTPpacket[0].seqNumber, RTPpacket[0].timeStamp, uw32_timeRec); /* If Redundancy is supported and this is the redundancy payload, separate the payloads */ #ifdef NETEQ_RED_CODEC if (RTPpacket[0].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst, kDecoderRED)) { /* Split the payload into a main and a redundancy payloads */ i_ok = WebRtcNetEQ_RedundancySplit(RTPpacketPtr, 2, &i_No_Of_Payloads); if (i_ok < 0) { /* error returned */ return i_ok; } /* * Only accept a few redundancies of the same type as the main data, * AVT events and CNG. */ if ((i_No_Of_Payloads > 1) && (RTPpacket[0].payloadType != RTPpacket[1].payloadType) && (RTPpacket[0].payloadType != WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst, kDecoderAVT)) && (RTPpacket[1].payloadType != WebRtcNetEQ_DbGetPayload( &MCU_inst->codec_DB_inst, kDecoderAVT)) && (!WebRtcNetEQ_DbIsCNGPayload( &MCU_inst->codec_DB_inst, RTPpacket[0].payloadType)) && (!WebRtcNetEQ_DbIsCNGPayload(&MCU_inst->codec_DB_inst, RTPpacket[1].payloadType))) { i_No_Of_Payloads = 1; } isREDPayload = 1; } #endif /* loop over the number of payloads */ for (i_k = 0; i_k < i_No_Of_Payloads; i_k++) { if (isREDPayload == 1) { RTPpacket[i_k].rcuPlCntr = i_k; } else { RTPpacket[i_k].rcuPlCntr = 0; } /* Force update of SplitInfo if it's iLBC because of potential change between 20/30ms */ if (RTPpacket[i_k].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst, kDecoderILBC)) { i_ok = WebRtcNetEQ_DbGetSplitInfo( &MCU_inst->PayloadSplit_inst, (enum WebRtcNetEQDecoder) WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst, RTPpacket[i_k].payloadType), RTPpacket[i_k].payloadLen); if (i_ok < 0) { /* error returned */ return i_ok; } } /* Get information about timestamp scaling for this payload type */ i_ok = WebRtcNetEQ_GetTimestampScaling(MCU_inst, RTPpacket[i_k].payloadType); if (i_ok < 0) { /* error returned */ return i_ok; } if (MCU_inst->TSscalingInitialized == 0 && MCU_inst->scalingFactor != kTSnoScaling) { /* Must initialize scaling with current timestamps */ MCU_inst->externalTS = RTPpacket[i_k].timeStamp; MCU_inst->internalTS = RTPpacket[i_k].timeStamp; MCU_inst->TSscalingInitialized = 1; } /* Adjust timestamp if timestamp scaling is needed (e.g. SILK or G.722) */ if (MCU_inst->TSscalingInitialized == 1) { WebRtc_UWord32 newTS = WebRtcNetEQ_ScaleTimestampExternalToInternal(MCU_inst, RTPpacket[i_k].timeStamp); /* save the incoming timestamp for next time */ MCU_inst->externalTS = RTPpacket[i_k].timeStamp; /* add the scaled difference to last scaled timestamp and save ... */ MCU_inst->internalTS = newTS; RTPpacket[i_k].timeStamp = newTS; } /* Is this a DTMF packet?*/ if (RTPpacket[i_k].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst, kDecoderAVT)) { #ifdef NETEQ_ATEVENT_DECODE if (MCU_inst->AVT_PlayoutOn) { i_ok = WebRtcNetEQ_DtmfInsertEvent(&MCU_inst->DTMF_inst, RTPpacket[i_k].payload, RTPpacket[i_k].payloadLen, RTPpacket[i_k].timeStamp); if (i_ok != 0) { return i_ok; } } #endif #ifdef NETEQ_STEREO if (MCU_inst->usingStereo == 0) { /* do not set this for DTMF packets when using stereo mode */ MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1; } #else MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1; #endif } else if (WebRtcNetEQ_DbIsCNGPayload(&MCU_inst->codec_DB_inst, RTPpacket[i_k].payloadType)) { /* Is this a CNG packet? how should we handle this?*/ #ifdef NETEQ_CNG_CODEC /* Get CNG sample rate */ WebRtc_UWord16 fsCng = WebRtcNetEQ_DbGetSampleRate(&MCU_inst->codec_DB_inst, RTPpacket[i_k].payloadType); /* Force sampling frequency to 32000 Hz CNG 48000 Hz. */ /* TODO(tlegrand): remove limitation once ACM has full 48 kHz * support. */ if (fsCng > 32000) { fsCng = 32000; } if ((fsCng != MCU_inst->fs) && (fsCng > 8000)) { /* * We have received CNG with a different sample rate from what we are using * now (must be > 8000, since we may use only one CNG type (default) for all * frequencies). Flush buffer and signal new codec. */ WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst); MCU_inst->new_codec = 1; MCU_inst->current_Codec = -1; } i_ok = WebRtcNetEQ_PacketBufferInsert(&MCU_inst->PacketBuffer_inst, &RTPpacket[i_k], &flushed); if (i_ok < 0) { return RECIN_CNG_ERROR; } MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1; #else /* NETEQ_CNG_CODEC not defined */ return RECIN_UNKNOWNPAYLOAD; #endif /* NETEQ_CNG_CODEC */ } else { /* Reinitialize the splitting if the payload and/or the payload length has changed */ curr_Codec = WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst, RTPpacket[i_k].payloadType); if (curr_Codec != MCU_inst->current_Codec) { if (curr_Codec < 0) { return RECIN_UNKNOWNPAYLOAD; } MCU_inst->current_Codec = curr_Codec; MCU_inst->current_Payload = RTPpacket[i_k].payloadType; i_ok = WebRtcNetEQ_DbGetSplitInfo(&MCU_inst->PayloadSplit_inst, (enum WebRtcNetEQDecoder) MCU_inst->current_Codec, RTPpacket[i_k].payloadLen); if (i_ok < 0) { /* error returned */ return i_ok; } WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst); MCU_inst->new_codec = 1; } /* Parse the payload and insert it into the buffer */ i_ok = WebRtcNetEQ_SplitAndInsertPayload(&RTPpacket[i_k], &MCU_inst->PacketBuffer_inst, &MCU_inst->PayloadSplit_inst, &flushed); if (i_ok < 0) { return i_ok; } if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF != 0) { /* first normal packet after CNG or DTMF */ MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = -1; } } /* Reset DSP timestamp etc. if packet buffer flushed */ if (flushed) { MCU_inst->new_codec = 1; } } /* * Update Bandwidth Estimate * Only send the main payload to BWE */ if ((curr_Codec = WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst, RTPpacket[0].payloadType)) >= 0) { codecPos = MCU_inst->codec_DB_inst.position[curr_Codec]; if (MCU_inst->codec_DB_inst.funcUpdBWEst[codecPos] != NULL) /* codec has BWE function */ { if (RTPpacket[0].starts_byte1) /* check for shifted byte alignment */ { /* re-align to 16-bit alignment */ for (i_k = 0; i_k < RTPpacket[0].payloadLen; i_k++) { WEBRTC_SPL_SET_BYTE(RTPpacket[0].payload, WEBRTC_SPL_GET_BYTE(RTPpacket[0].payload, i_k+1), i_k); } RTPpacket[0].starts_byte1 = 0; } MCU_inst->codec_DB_inst.funcUpdBWEst[codecPos]( MCU_inst->codec_DB_inst.codec_state[codecPos], (G_CONST WebRtc_UWord16 *) RTPpacket[0].payload, (WebRtc_Word32) RTPpacket[0].payloadLen, RTPpacket[0].seqNumber, (WebRtc_UWord32) RTPpacket[0].timeStamp, (WebRtc_UWord32) uw32_timeRec); } } if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF == 0) { /* Calculate the total speech length carried in each packet */ temp_bufsize = MCU_inst->PacketBuffer_inst.numPacketsInBuffer - temp_bufsize; temp_bufsize *= MCU_inst->PacketBuffer_inst.packSizeSamples; if ((temp_bufsize > 0) && (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF == 0) && (temp_bufsize != MCU_inst->BufferStat_inst.Automode_inst.packetSpeechLenSamp)) { /* Change the auto-mode parameters if packet length has changed */ WebRtcNetEQ_SetPacketSpeechLen(&(MCU_inst->BufferStat_inst.Automode_inst), (WebRtc_Word16) temp_bufsize, MCU_inst->fs); } /* update statistics */ if ((WebRtc_Word32) (RTPpacket[0].timeStamp - MCU_inst->timeStamp) >= 0 && !MCU_inst->new_codec) { /* * Only update statistics if incoming packet is not older than last played out * packet, and if new codec flag is not set. */ WebRtcNetEQ_UpdateIatStatistics(&MCU_inst->BufferStat_inst.Automode_inst, MCU_inst->PacketBuffer_inst.maxInsertPositions, RTPpacket[0].seqNumber, RTPpacket[0].timeStamp, MCU_inst->fs, WebRtcNetEQ_DbIsMDCodec((enum WebRtcNetEQDecoder) MCU_inst->current_Codec), (MCU_inst->NetEqPlayoutMode == kPlayoutStreaming)); } } else if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF == -1) { /* * This is first "normal" packet after CNG or DTMF. * Reset packet time counter and measure time until next packet, * but don't update statistics. */ MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 0; MCU_inst->BufferStat_inst.Automode_inst.packetIatCountSamp = 0; } return 0; }
int WebRtcNetEQ_RecInInternal(MCUInst_t *MCU_inst, RTPPacket_t *RTPpacketInput, WebRtc_UWord32 uw32_timeRec) { RTPPacket_t RTPpacket[2]; int i_k; int i_ok = 0, i_No_Of_Payloads = 1; WebRtc_Word16 flushed = 0; WebRtc_Word16 codecPos; WebRtc_UWord32 diffTS, uw32_tmp; int curr_Codec; WebRtc_Word16 isREDPayload = 0; WebRtc_Word32 temp_bufsize = MCU_inst->PacketBuffer_inst.numPacketsInBuffer; #ifdef NETEQ_RED_CODEC RTPPacket_t* RTPpacketPtr[2]; /* Support for redundancy up to 2 payloads */ RTPpacketPtr[0] = &RTPpacket[0]; RTPpacketPtr[1] = &RTPpacket[1]; #endif /* * Copy from input RTP packet to local copy * (mainly to enable multiple payloads using RED) */ WEBRTC_SPL_MEMCPY_W8(&RTPpacket[0], RTPpacketInput, sizeof(RTPPacket_t)); /* Reinitialize NetEq if it's needed (changed SSRC or first call) */ if ((RTPpacket[0].ssrc != MCU_inst->ssrc) || (MCU_inst->first_packet == 1)) { WebRtcNetEQ_RTCPInit(&MCU_inst->RTCP_inst, RTPpacket[0].seqNumber); MCU_inst->first_packet = 0; /* Flush the buffer */ WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst); /* Store new SSRC */ MCU_inst->ssrc = RTPpacket[0].ssrc; /* Update codecs */ MCU_inst->timeStamp = RTPpacket[0].timeStamp; MCU_inst->current_Payload = RTPpacket[0].payloadType; /*Set MCU to update codec on next SignalMCU call */ MCU_inst->new_codec = 1; /* Reset timestamp scaling */ MCU_inst->TSscalingInitialized = 0; } /* Call RTCP statistics */ i_ok |= WebRtcNetEQ_RTCPUpdate(&(MCU_inst->RTCP_inst), RTPpacket[0].seqNumber, RTPpacket[0].timeStamp, uw32_timeRec); /* If Redundancy is supported and this is the redundancy payload, separate the payloads */ #ifdef NETEQ_RED_CODEC if (RTPpacket[0].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst, kDecoderRED)) { /* Split the payload into a main and a redundancy payloads */ i_ok = WebRtcNetEQ_RedundancySplit(RTPpacketPtr, 2, &i_No_Of_Payloads); if (i_ok < 0) { /* error returned */ return i_ok; } /* * Only accept a few redundancies of the same type as the main data, * AVT events and CNG. */ if ((i_No_Of_Payloads > 1) && (RTPpacket[0].payloadType != RTPpacket[1].payloadType) && (RTPpacket[0].payloadType != WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst, kDecoderAVT)) && (RTPpacket[1].payloadType != WebRtcNetEQ_DbGetPayload( &MCU_inst->codec_DB_inst, kDecoderAVT)) && (!WebRtcNetEQ_DbIsCNGPayload( &MCU_inst->codec_DB_inst, RTPpacket[0].payloadType)) && (!WebRtcNetEQ_DbIsCNGPayload(&MCU_inst->codec_DB_inst, RTPpacket[1].payloadType))) { i_No_Of_Payloads = 1; } isREDPayload = 1; } #endif /* loop over the number of payloads */ for (i_k = 0; i_k < i_No_Of_Payloads; i_k++) { if (isREDPayload == 1) { RTPpacket[i_k].rcuPlCntr = i_k; } else { RTPpacket[i_k].rcuPlCntr = 0; } /* Force update of SplitInfo if it's iLBC because of potential change between 20/30ms */ if (RTPpacket[i_k].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst, kDecoderILBC)) { i_ok = WebRtcNetEQ_DbGetSplitInfo( &MCU_inst->PayloadSplit_inst, (enum WebRtcNetEQDecoder) WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst, RTPpacket[i_k].payloadType), RTPpacket[i_k].payloadLen); if (i_ok < 0) { /* error returned */ return i_ok; } } /* Get information about timestamp scaling for this payload type */ i_ok = WebRtcNetEQ_GetTimestampScaling(MCU_inst, RTPpacket[i_k].payloadType); if (i_ok < 0) { /* error returned */ return i_ok; } if (MCU_inst->TSscalingInitialized == 0 && MCU_inst->scalingFactor != kTSnoScaling) { /* Must initialize scaling with current timestamps */ MCU_inst->externalTS = RTPpacket[i_k].timeStamp; MCU_inst->internalTS = RTPpacket[i_k].timeStamp; MCU_inst->TSscalingInitialized = 1; } /* Adjust timestamp if timestamp scaling is needed (e.g. SILK or G.722) */ if (MCU_inst->TSscalingInitialized == 1) { WebRtc_UWord32 newTS = WebRtcNetEQ_ScaleTimestampExternalToInternal(MCU_inst, RTPpacket[i_k].timeStamp); /* save the incoming timestamp for next time */ MCU_inst->externalTS = RTPpacket[i_k].timeStamp; /* add the scaled difference to last scaled timestamp and save ... */ MCU_inst->internalTS = newTS; RTPpacket[i_k].timeStamp = newTS; } /* Is this a DTMF packet?*/ if (RTPpacket[i_k].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst, kDecoderAVT)) { #ifdef NETEQ_ATEVENT_DECODE if (MCU_inst->AVT_PlayoutOn) { i_ok = WebRtcNetEQ_DtmfInsertEvent(&MCU_inst->DTMF_inst, RTPpacket[i_k].payload, RTPpacket[i_k].payloadLen, RTPpacket[i_k].timeStamp); if (i_ok != 0) { return i_ok; } } #endif #ifdef NETEQ_STEREO if (MCU_inst->usingStereo == 0) { /* do not set this for DTMF packets when using stereo mode */ MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1; } #else MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1; #endif } else if (WebRtcNetEQ_DbIsCNGPayload(&MCU_inst->codec_DB_inst, RTPpacket[i_k].payloadType)) { /* Is this a CNG packet? how should we handle this?*/ #ifdef NETEQ_CNG_CODEC /* Get CNG sample rate */ WebRtc_UWord16 fsCng = WebRtcNetEQ_DbGetSampleRate(&MCU_inst->codec_DB_inst, RTPpacket[i_k].payloadType); if ((fsCng != MCU_inst->fs) && (fsCng > 8000)) { /* * We have received CNG with a different sample rate from what we are using * now (must be > 8000, since we may use only one CNG type (default) for all * frequencies). Flush buffer and signal new codec. */ WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst); MCU_inst->new_codec = 1; MCU_inst->current_Codec = -1; } i_ok = WebRtcNetEQ_PacketBufferInsert(&MCU_inst->PacketBuffer_inst, &RTPpacket[i_k], &flushed); if (i_ok < 0) { return RECIN_CNG_ERROR; } MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1; #else /* NETEQ_CNG_CODEC not defined */ return RECIN_UNKNOWNPAYLOAD; #endif /* NETEQ_CNG_CODEC */ } else { /* Reinitialize the splitting if the payload and/or the payload length has changed */ curr_Codec = WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst, RTPpacket[i_k].payloadType); if (curr_Codec != MCU_inst->current_Codec) { if (curr_Codec < 0) { return RECIN_UNKNOWNPAYLOAD; } MCU_inst->current_Codec = curr_Codec; MCU_inst->current_Payload = RTPpacket[i_k].payloadType; i_ok = WebRtcNetEQ_DbGetSplitInfo(&MCU_inst->PayloadSplit_inst, (enum WebRtcNetEQDecoder) MCU_inst->current_Codec, RTPpacket[i_k].payloadLen); if (i_ok < 0) { /* error returned */ return i_ok; } WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst); MCU_inst->new_codec = 1; } /* update post-call statistics */ if (MCU_inst->new_codec != 1) /* not if in codec change */ { diffTS = RTPpacket[i_k].timeStamp - MCU_inst->timeStamp; /* waiting time */ if (diffTS < 0x0FFFFFFF) /* guard against re-ordering */ { /* waiting time in ms */ diffTS = WEBRTC_SPL_UDIV(diffTS, WEBRTC_SPL_UDIV((WebRtc_UWord32) MCU_inst->fs, 1000) ); if (diffTS < MCU_inst->statInst.minPacketDelayMs) { /* new all-time low */ MCU_inst->statInst.minPacketDelayMs = diffTS; } if (diffTS > MCU_inst->statInst.maxPacketDelayMs) { /* new all-time high */ MCU_inst->statInst.maxPacketDelayMs = diffTS; } /* Update avg waiting time: * avgPacketDelayMs = * (avgPacketCount * avgPacketDelayMs + diffTS)/(avgPacketCount+1) * with proper rounding. */ uw32_tmp = WEBRTC_SPL_UMUL((WebRtc_UWord32) MCU_inst->statInst.avgPacketCount, (WebRtc_UWord32) MCU_inst->statInst.avgPacketDelayMs); uw32_tmp = WEBRTC_SPL_ADD_SAT_W32(uw32_tmp, (diffTS + (MCU_inst->statInst.avgPacketCount>>1))); uw32_tmp = WebRtcSpl_DivU32U16(uw32_tmp, (WebRtc_UWord16) (MCU_inst->statInst.avgPacketCount + 1)); MCU_inst->statInst.avgPacketDelayMs = (WebRtc_UWord16) WEBRTC_SPL_MIN(uw32_tmp, (WebRtc_UWord32) 65535); /* increase counter, but not to more than 65534 */ if (MCU_inst->statInst.avgPacketCount < (0xFFFF - 1)) { MCU_inst->statInst.avgPacketCount++; } } } /* Parse the payload and insert it into the buffer */ i_ok = WebRtcNetEQ_SplitAndInsertPayload(&RTPpacket[i_k], &MCU_inst->PacketBuffer_inst, &MCU_inst->PayloadSplit_inst, &flushed); if (i_ok < 0) { return i_ok; } if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF != 0) { /* first normal packet after CNG or DTMF */ MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = -1; } }
/* * Signals the MCU that DSP status data is available. */ int WebRtcNetEQ_SignalMcu(MCUInst_t *inst) { int i_bufferpos, i_res; WebRtc_UWord16 uw16_instr; DSP2MCU_info_t dspInfo; WebRtc_Word16 *blockPtr, blockLen; WebRtc_UWord32 uw32_availableTS; RTPPacket_t temp_pkt; WebRtc_Word32 w32_bufsize, w32_tmp; WebRtc_Word16 payloadType = -1; WebRtc_Word16 wantedNoOfTimeStamps; WebRtc_Word32 totalTS; WebRtc_Word16 oldPT, latePacketExist = 0; WebRtc_UWord32 oldTS, prevTS, uw32_tmp; WebRtc_UWord16 prevSeqNo; WebRtc_Word16 nextSeqNoAvail; WebRtc_Word16 fs_mult, w16_tmp; WebRtc_Word16 lastModeBGNonly = 0; #ifdef NETEQ_DELAY_LOGGING int temp_var; #endif int playDtmf = 0; fs_mult = WebRtcSpl_DivW32W16ResW16(inst->fs, 8000); /* Increment counter since last statistics report */ inst->lastReportTS += inst->timestampsPerCall; /* Increment waiting time for all packets. */ WebRtcNetEQ_IncrementWaitingTimes(&inst->PacketBuffer_inst); /* Read info from DSP so we now current status */ WEBRTC_SPL_MEMCPY_W8(&dspInfo,inst->pw16_readAddress,sizeof(DSP2MCU_info_t)); /* Set blockPtr to first payload block */ blockPtr = &inst->pw16_writeAddress[3]; /* Clear instruction word and number of lost samples (2*WebRtc_Word16) */ inst->pw16_writeAddress[0] = 0; inst->pw16_writeAddress[1] = 0; inst->pw16_writeAddress[2] = 0; if ((dspInfo.lastMode & MODE_AWAITING_CODEC_PTR) != 0) { /* * Make sure state is adjusted so that a codec update is * performed when first packet arrives. */ if (inst->new_codec != 1) { inst->current_Codec = -1; } dspInfo.lastMode = (dspInfo.lastMode ^ MODE_AWAITING_CODEC_PTR); } #ifdef NETEQ_STEREO if ((dspInfo.lastMode & MODE_MASTER_DTMF_SIGNAL) != 0) { playDtmf = 1; /* force DTMF decision */ dspInfo.lastMode = (dspInfo.lastMode ^ MODE_MASTER_DTMF_SIGNAL); } if ((dspInfo.lastMode & MODE_USING_STEREO) != 0) { if (inst->usingStereo == 0) { /* stereo mode changed; reset automode instance to re-synchronize statistics */ WebRtcNetEQ_ResetAutomode(&(inst->BufferStat_inst.Automode_inst), inst->PacketBuffer_inst.maxInsertPositions); } inst->usingStereo = 1; dspInfo.lastMode = (dspInfo.lastMode ^ MODE_USING_STEREO); } else { inst->usingStereo = 0; } #endif /* detect if BGN_ONLY flag is set in lastMode */ if ((dspInfo.lastMode & MODE_BGN_ONLY) != 0) { lastModeBGNonly = 1; /* remember flag */ dspInfo.lastMode ^= MODE_BGN_ONLY; /* clear the flag */ } if ((dspInfo.lastMode == MODE_RFC3389CNG) || (dspInfo.lastMode == MODE_CODEC_INTERNAL_CNG) || (dspInfo.lastMode == MODE_EXPAND)) { /* * If last mode was CNG (or Expand, since this could be covering up for a lost CNG * packet), increase the CNGplayedTS counter. */ inst->BufferStat_inst.uw32_CNGplayedTS += inst->timestampsPerCall; if (dspInfo.lastMode == MODE_RFC3389CNG) { /* remember that RFC3389CNG is on (needed if CNG is interrupted by DTMF) */ inst->BufferStat_inst.w16_cngOn = CNG_RFC3389_ON; } else if (dspInfo.lastMode == MODE_CODEC_INTERNAL_CNG) { /* remember that internal CNG is on (needed if CNG is interrupted by DTMF) */ inst->BufferStat_inst.w16_cngOn = CNG_INTERNAL_ON; } } /* Update packet size from previously decoded packet */ if (dspInfo.frameLen > 0) { inst->PacketBuffer_inst.packSizeSamples = dspInfo.frameLen; } /* Look for late packet (unless codec has changed) */ if (inst->new_codec != 1) { if (WebRtcNetEQ_DbIsMDCodec((enum WebRtcNetEQDecoder) inst->current_Codec)) { WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst, inst->timeStamp, &uw32_availableTS, &i_bufferpos, 1, &payloadType); if ((inst->new_codec != 1) && (inst->timeStamp == uw32_availableTS) && (inst->timeStamp < dspInfo.playedOutTS) && (i_bufferpos != -1) && (WebRtcNetEQ_DbGetPayload(&(inst->codec_DB_inst), (enum WebRtcNetEQDecoder) inst->current_Codec) == payloadType)) { int waitingTime; temp_pkt.payload = blockPtr + 1; i_res = WebRtcNetEQ_PacketBufferExtract(&inst->PacketBuffer_inst, &temp_pkt, i_bufferpos, &waitingTime); if (i_res < 0) { /* error returned */ return i_res; } WebRtcNetEQ_StoreWaitingTime(inst, waitingTime); *blockPtr = temp_pkt.payloadLen; /* set the flag if this is a redundant payload */ if (temp_pkt.rcuPlCntr > 0) { *blockPtr = (*blockPtr) | (DSP_CODEC_RED_FLAG); } blockPtr += ((temp_pkt.payloadLen + 1) >> 1) + 1; /* * Close the data with a zero size block, in case we will not write any * more data. */ *blockPtr = 0; inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0xf0ff) | DSP_CODEC_ADD_LATE_PKT; latePacketExist = 1; } }