Beispiel #1
0
        protected override void PerformEchoCancellation(short[] recorded, short[] played, short[] outFrame)
        {
            // ks 11/2/11 - This seems to be more-or-less the order in which things are processed in the WebRtc audio_processing_impl.cc file.
            _highPassFilter.Filter(recorded);

            if (_enableAgc)
            {
                _agc.WebRtcAgc_AddFarend(played, (short)played.Length);
                gain_control_AnalyzeCaptureAudio(recorded);
            }

            if (_enableAec)
            {
                _aec.ProcessFrame(recorded, played, outFrame, 0);
            }
            else
            {
                Buffer.BlockCopy(recorded, 0, outFrame, 0, SamplesPerFrame * sizeof(short));
            }

            if (_enableDenoise)
            {
                // ks 11/14/11 - The noise suppressor only supports 10 ms blocks. I might be able to fix that,
                // but this is easier for now.
                _ns.ProcessFrame(outFrame, 0, outFrame, 0);
                _ns.ProcessFrame(outFrame, _recordedAudioFormat.SamplesPer10Ms, outFrame, _recordedAudioFormat.SamplesPer10Ms);
            }

            if (_enableAgc)
            {
                gain_control_ProcessCaptureAudio(outFrame);
            }
        }
Beispiel #2
0
        public void WebRtcAec_Process(short[] nearend, short streamDelayMs, int skew)
        {
            int   nrOfSamples    = nearend.Length;
            short msInSndCardBuf = streamDelayMs;

            var   farend = new short[aecConfig.SamplesPerFrame];
            short nmbrOfFilledBuffers;

            // number of samples == 160 for SWB input
            if (nrOfSamples != 80 && nrOfSamples != 160)
            {
                throw new ArgumentException();
            }

            // Check for valid pointers based on sampling rate
            if (sampFreq == 32000)
            {
                throw new ArgumentException();
            }

            if (msInSndCardBuf < 0)
            {
                msInSndCardBuf = 0;
                //throw new ArgumentException();//todo:warning
            }
            else if (msInSndCardBuf > 500)
            {
                msInSndCardBuf = 500;
                //todo:warning
            }
            msInSndCardBuf     += 10;
            this.msInSndCardBuf = msInSndCardBuf;

            if (skewMode)
            {
                //if (aecpc->skewFrCtr < 25) {
                //    aecpc->skewFrCtr++;
                //}
                //else {
                //    retVal = WebRtcAec_GetSkew(aecpc->resampler, skew, &aecpc->skew);
                //    if (retVal == -1) {
                //        aecpc->skew = 0;
                //        aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
                //    }

                //    aecpc->skew /= aecpc->sampFactor*nrOfSamples;

                //    if (aecpc->skew < 1.0e-3 && aecpc->skew > -1.0e-3) {
                //        aecpc->resample = kAecFalse;
                //    }
                //    else {
                //        aecpc->resample = kAecTrue;
                //    }

                //    if (aecpc->skew < minSkewEst) {
                //        aecpc->skew = minSkewEst;
                //    }
                //    else if (aecpc->skew > maxSkewEst) {
                //        aecpc->skew = maxSkewEst;
                //    }

                //}
            }

            var nFrames     = (short)(nrOfSamples / aecConfig.SamplesPerFrame);
            var nBlocks10Ms = (short)(nFrames / aec.mult);

            WebRtcUtil.WriteDebugMessage(String.Format("(C#) AEC 01               ECstartup = {0}", ECstartup));
            if (ECstartup)
            {
                nmbrOfFilledBuffers = (short)(farendBuf.get_buffer_size() / aecConfig.SamplesPerFrame);

                // The AEC is in the start up mode
                // AEC is disabled until the soundcard buffer and farend buffers are OK

                // Mechanism to ensure that the soundcard buffer is reasonably stable.
                if (checkBuffSize)
                {
                    checkBufSizeCtr++;
                    // Before we fill up the far end buffer we require the amount of data on the
                    // sound card to be stable (+/-8 ms) compared to the first value. This
                    // comparison is made during the following 4 consecutive frames. If it seems
                    // to be stable then we start to fill up the far end buffer.

                    if (counter == 0)
                    {
                        firstVal = this.msInSndCardBuf;
                        sum      = 0;
                    }

                    if (Math.Abs(firstVal - this.msInSndCardBuf) <
                        WebRtcUtil.WEBRTC_SPL_MAX((int)(0.2 * this.msInSndCardBuf), WebRtcConstants.sampMsNb))
                    {
                        sum += this.msInSndCardBuf;
                        counter++;
                    }
                    else
                    {
                        counter = 0;
                    }

                    if (counter * nBlocks10Ms >= 6)
                    {
                        // The farend buffer size is determined in blocks of 80 samples
                        // Use 75% of the average value of the soundcard buffer
                        bufSizeStart = (short)WebRtcUtil.WEBRTC_SPL_MIN((int)(0.75 * (sum * aec.mult) / (counter * 10)), WebRtcConstants.BUF_SIZE_FRAMES);
                        // buffersize has now been determined
                        checkBuffSize = false;
                    }

                    if (checkBufSizeCtr * nBlocks10Ms > 50)
                    {
                        // for really bad sound cards, don't disable echocanceller for more than 0.5 sec
                        bufSizeStart  = (short)WebRtcUtil.WEBRTC_SPL_MIN((int)(0.75 * (this.msInSndCardBuf * aec.mult) / 10), WebRtcConstants.BUF_SIZE_FRAMES);
                        checkBuffSize = false;
                    }
                }

                // if checkBuffSize changed in the if-statement above
                if (!checkBuffSize)
                {
                    // soundcard buffer is now reasonably stable
                    // When the far end buffer is filled with approximately the same amount of
                    // data as the amount on the sound card we end the start up phase and start
                    // to cancel echoes.

                    if (nmbrOfFilledBuffers == bufSizeStart)
                    {
                        ECstartup = false;                         // Enable the AEC
                    }
                    else if (nmbrOfFilledBuffers > bufSizeStart)
                    {
                        farendBuf.Flush(farendBuf.get_buffer_size() - bufSizeStart * aecConfig.SamplesPerFrame);
                        ECstartup = false;
                    }
                }
            }
            else
            {
                // AEC is enabled

                // Note only 1 block supported for nb and 2 blocks for wb
                for (int i = 0; i < nFrames; i++)
                {
                    nmbrOfFilledBuffers = (short)(farendBuf.get_buffer_size() / aecConfig.SamplesPerFrame);

                    // Check that there is data in the far end buffer
                    if (nmbrOfFilledBuffers > 0)
                    {
                        // Get the next 80 samples from the farend buffer
                        farendBuf.Read(farend, aecConfig.SamplesPerFrame);

                        // Always store the last frame for use when we run out of data
                        farendOld[i] = farend;
                    }
                    else
                    {
                        // We have no data so we use the last played frame
                        farend = farendOld[i];
                    }

                    // Call buffer delay estimator when all data is extracted,
                    // i.e. i = 0 for NB and i = 1 for WB or SWB
                    if ((i == 0 && splitSampFreq == 8000) ||
                        (i == 1 && (splitSampFreq == 16000)))
                    {
                        EstBufDelay(this.msInSndCardBuf);
                    }

                    // Call the AEC
                    var nearend80 = new short[aecConfig.SamplesPerFrame];
                    Buffer.BlockCopy(nearend, aecConfig.SamplesPerFrame * i * sizeof(short), nearend80, 0, aecConfig.SamplesPerFrame * sizeof(short));
                    aec.ProcessFrame(nearend80, farend, nearend80, knownDelay);
                    Buffer.BlockCopy(nearend80, 0, nearend, aecConfig.SamplesPerFrame * i * sizeof(short), aecConfig.SamplesPerFrame * sizeof(short));
                }
            }
        }