UtlBoolean MpDecodeBuffer::needsResampling(const MpDecoderBase& rDecoder) const { if (rDecoder.getInfo()->getCodecType() != SdpCodec::SDP_CODEC_TONES && rDecoder.getInfo()->getSamplingRate() != m_samplesPerSec) { return TRUE; } else { return FALSE; } }
UtlBoolean MprDecode::handleSelectCodecs(SdpCodec* pCodecs[], int numCodecs) { int i; SdpCodec* pCodec; int payload; SdpCodec::SdpCodecTypes ourCodec; SdpCodec::SdpCodecTypes oldSdpType = SdpCodec::SDP_CODEC_UNKNOWN; OsStatus ret; MpDecoderBase* pNewDecoder; MpDecoderBase* pOldDecoder; MpCodecFactory* pFactory = MpCodecFactory::getMpCodecFactory(); int allReusable = 1; int canReuse; #if 0 osPrintf("MprDecode::handleSelectCodecs(%d codec%s):\n", numCodecs, ((1 == numCodecs) ? "" : "s")); #endif if (OsSysLog::willLog(FAC_MP, PRI_DEBUG)) { for (i=0; i<numCodecs; i++) { pCodec = pCodecs[i]; OsSysLog::add(FAC_MP, PRI_DEBUG, "MprDecode::handleSelectCodecs " "pCodecs[%d]->getCodecType() = %d, " "pCodecs[%d]->getCodecPayloadFormat() = %d", i, pCodec->getCodecType(), i, pCodec->getCodecPayloadFormat()); } } // Check to see if all codecs in pCodecs can be handled by codecs // in mpCurrentCodecs. for (i=0; i<numCodecs; i++) { pCodec = pCodecs[i]; ourCodec = pCodec->getCodecType(); payload = pCodec->getCodecPayloadFormat(); #if 0 osPrintf(" #%d: New=0x%p/i:%d/x:%d, ", i, ourCodec, payload); #endif pOldDecoder = mpConnection->mapPayloadType(payload); if (NULL != pOldDecoder) { oldSdpType = pOldDecoder->getInfo()->getCodecType(); #if 0 osPrintf(" Old=0x%p/i:%d", oldSdpType); #endif canReuse = (ourCodec == oldSdpType) || ((SdpCodec::SDP_CODEC_G729AB == ourCodec) && (SdpCodec::SDP_CODEC_G729A == oldSdpType)) || ((SdpCodec::SDP_CODEC_G729A == ourCodec) && (SdpCodec::SDP_CODEC_G729AB == oldSdpType)); } else { // osPrintf(" no Old"); canReuse = 0; } allReusable &= canReuse; #if 0 osPrintf(" i:%d/x:%d (%sreusable%s)\n", ourCodec, payload, (canReuse ? "" : "not "), (canReuse && (ourCodec != oldSdpType) ? "[*]" : "")); #endif } // If the new list is not a subset of the old list, we have to copy // pCodecs into mpCurrentCodecs. if (!allReusable) { // Lock the m*Codecs members. OsLock lock(mLock); // Delete the current codecs. handleDeselectCodecs(); mNumCurrentCodecs = numCodecs; mpCurrentCodecs = new MpDecoderBase*[numCodecs]; for (i=0; i<numCodecs; i++) { pCodec = pCodecs[i]; ourCodec = pCodec->getCodecType(); payload = pCodec->getCodecPayloadFormat(); ret = pFactory->createDecoder(ourCodec, payload, pNewDecoder); assert(OS_SUCCESS == ret); assert(NULL != pNewDecoder); pNewDecoder->initDecode(mpConnection); // Set up the DTMF notifier and media recorder, if any. if (pNewDecoder->getInfo()->isSignalingCodec()) { pNewDecoder->handleSetDtmfNotify(mpNotify); pNewDecoder->setDtmfTerm(mpRecorder); } // Add this codec to mpConnection's payload type decoding table. mpConnection->addPayloadType(payload, pNewDecoder); mpCurrentCodecs[i] = pNewDecoder; } // Go back and add any signaling codecs to Jitter Buffer. for (i=0; i<numCodecs; i++) { if (mpCurrentCodecs[i]->getInfo()->isSignalingCodec()) { mpCurrentCodecs[i]->initDecode(mpConnection); } } } // Delete the list pCodecs. for (i=0; i<numCodecs; i++) { delete pCodecs[i]; } delete[] pCodecs; return TRUE; }
int MpDecodeBuffer::pushPacket(MpRtpBufPtr &rtpPacket, JitterBufferResult jbResult) { unsigned int availableBufferSize =0; // number of samples could be written to decoded buffer unsigned producedSamples = 0; // number of samples, returned from decoder uint8_t payloadType = 0; // RTP packet payload type MpDecoderBase* decoder = NULL; // decoder for the packet payloadType = rtpPacket->getRtpPayloadType(); // Ignore illegal payload types if (payloadType >= JbPayloadMapSize) return 0; // Get decoder decoder = m_pDecoderMap[payloadType]; if (decoder == NULL) return 0; // If we can't decode it, we must ignore it? // Calculate space available for decoded samples if (m_decodeBufferIn > m_decodeBufferOut || m_decodeBufferCount == 0) { availableBufferSize = g_decodeBufferSize-m_decodeBufferIn; } else { availableBufferSize = m_decodeBufferOut-m_decodeBufferIn; } MpAudioSample* pTmpDstBuffer = NULL; if (needsResampling(*decoder)) // for 8Khz flowgraph we will never resample { pTmpDstBuffer = m_resampleSrcBuffer; } else { pTmpDstBuffer = m_decodeHelperBuffer; } // decode samples from decoder, and copy them into decode buffer producedSamples = decoder->decode(rtpPacket, g_decodeHelperBufferSize, pTmpDstBuffer, jbResult == MP_JITTER_BUFFER_PLC); if (needsResampling(*decoder) && producedSamples > 0) { // need to resample MpResamplerBase* pResampler = m_pResamplerMap[payloadType]; if (pResampler) { uint32_t inSampleCount = producedSamples; uint32_t inSampleProcessed = 0; OsStatus res = pResampler->resample(pTmpDstBuffer, inSampleCount, inSampleProcessed, m_decodeHelperBuffer, g_decodeHelperBufferSize, producedSamples); assert(res == OS_SUCCESS); if (res != OS_SUCCESS) { OsSysLog::add(FAC_AUDIO, PRI_ERR, "Resampling failure for payload format %d. Status %d.", payloadType, (int)res); return 0; } } else { // we can't resample, and can't decode OsSysLog::add(FAC_AUDIO, PRI_ERR, "Resampling is needed for payload format %d, but no such resampler is available.", payloadType); return 0; } } // don't even think about resampling noise, it still sounds noisy! if (producedSamples == 0 && decoder->getInfo()->getCodecType() != SdpCodec::SDP_CODEC_TONES) { // if decoder didn't produce samples from RTP packet, generate noise according to decoder frame size int decoderSamplesPerFrame = decoder->getInfo()->getNumSamplesPerFrame(); m_pNoiseGenerator->generateComfortNoise(m_decodeHelperBuffer, decoderSamplesPerFrame); producedSamples = decoderSamplesPerFrame; } int addedSamples = 0; // now we have decoded & resampled samples in m_decodeHelperBuffer, with decodedSamples count // copy them into main buffer if (producedSamples > 0) { // count1 is number of samples to copy before wrapping occurs int count1 = min(producedSamples, availableBufferSize); // count 2 is number of samples to copy after wrapping int count2 = producedSamples - count1; memcpy(m_decodeBuffer + m_decodeBufferIn, m_decodeHelperBuffer, count1 * sizeof(MpAudioSample)); addedSamples += count1; if (count2 > 0) { count2 = min(count2, m_decodeBufferOut); // reduce count2 by available space since start of array memcpy(m_decodeBuffer, m_decodeHelperBuffer + count1, count2 * sizeof(MpAudioSample)); // copy to beginning of buffer addedSamples += count2; } } // Update buffer state m_decodeBufferCount += addedSamples; m_decodeBufferIn += addedSamples; // Reset write pointer if we reach end of buffer if (m_decodeBufferIn >= g_decodeBufferSize) m_decodeBufferIn -= g_decodeBufferSize; return 0; }
UtlBoolean MprDecode::doProcessFrame(MpBufPtr inBufs[], MpBufPtr outBufs[], int inBufsSize, int outBufsSize, UtlBoolean isEnabled, int samplesPerFrame, int samplesPerSecond) { #ifdef DEBUG_DECODING /* [ */ static int numFramesForWarnings = 0; static int numWarnings = 0; #endif /* DEBUG_DECODING ] */ MpBufPtr rtp; MpBufPtr out; #ifdef DEBUG_DECODING /* [ */ numFramesForWarnings++; #endif /* DEBUG_DECODING ] */ MpDecoderBase* pCurDec; Sample* pSamples = NULL; mFrameCounter++; if (0 == outBufsSize) return FALSE; if (!isEnabled) { mPreloading = 1; *outBufs = MpBuf_getFgSilence(); return TRUE; } { MprDejitter* pDej = getMyDejitter(); int packetLen; int pt; while (NULL != (rtp = pDej->pullPacket())) { pt = MprDejitter::getPayloadType(rtp); pCurDec = mpConnection->mapPayloadType(pt); if (NULL != pCurDec) { unsigned char* pRtpH; pRtpH = ((unsigned char*) MpBuf_getStorage(rtp)) + 1; if (0x80 == (0x80 & *pRtpH)) { if ((mFrameLastMarkerNotice + MARKER_WAIT_FRAMES) < mFrameCounter) { mNumMarkerNotices = 0; } if (mNumMarkerNotices++ < MAX_MARKER_NOTICES) { // osPrintf("MprDecode: RTP marker bit ON\n"); mFrameLastMarkerNotice = mFrameCounter; } } packetLen = pCurDec->decodeIn(rtp); if (packetLen > 0) { pushIntoJitterBuffer(rtp, packetLen); } } MpBuf_delRef(rtp); } } out = MpBuf_getBuf(MpMisc.UcbPool, samplesPerFrame, 0, MP_FMT_T12); if (out) { pSamples = MpBuf_getSamples(out); memset(pSamples, 0, samplesPerFrame * sizeof(Sample)); MpBuf_setSpeech(out, MP_SPEECH_SILENT); } JB_inst* pJBState = mpConnection->getJBinst(); if (pJBState) { // This should be a JB_something or other. However the only // current choices is a short or long equivalant and this needs // to be a plain old int: int outLen; int res; res = JB_RecOut(pJBState, pSamples, &outLen); MpBuf_setSpeech(out, MP_SPEECH_UNKNOWN); } *outBufs = out; Nprintf("Decode_doPF: returning 0x%p\n", out, 0,0,0,0,0); return TRUE; }