public AudioContext(AudioFormat audioFormat, IAudioFilter resampler, IDtxFilter dtxFilter, IAudioTwoWayFilter speechEnhancer, IAudioEncoder encoder) { AudioFormat = audioFormat; Resampler = resampler; SpeechEnhancementStack = speechEnhancer; Encoder = encoder; DtxFilter = dtxFilter; ResampleBuffer = new byte[audioFormat.BytesPerFrame]; CancelBuffer = new short[audioFormat.SamplesPerFrame]; EncodeBuffer = new short[audioFormat.SamplesPerFrame]; SendBuffer = new short[audioFormat.SamplesPerFrame]; }
private void TransmitAudio() { while (_audioEncodeResetEvent.WaitOne() && _isActive) { _audioEncodeResetEvent.Reset(); while (_audioFrames.Count > 0) { AudioFrame audioFrame; lock (_audioFrames) { audioFrame = _audioFrames.Dequeue(); } if (audioFrame == null) { continue; } // Cancel any echo onto the audioCancelBuffer. var audioContext = audioFrame.AudioContext; var frame = audioFrame.Samples; _lastSpeechEnhancementStack = audioContext.SpeechEnhancementStack; LastSpeechEnhancementName = _lastSpeechEnhancementStack.InstanceName; _lastSpeechEnhancementStack.Write(frame); bool moreFrames; do { if (_lastSpeechEnhancementStack.Read(audioContext.CancelBuffer, out moreFrames)) { if (!MediaConfig.PlayEchoCancelledSound) { Buffer.BlockCopy(frame, 0, audioContext.CancelBuffer, 0, frame.Length); } _cancelledStatistics.LatestFrame = audioContext.CancelBuffer; if (OtherMembersInRoom) { PrepareAndSendAudioPacket(audioContext, audioContext.CancelBuffer); } } } while (moreFrames); } } }
public AudioContext GetAudioContext() { var resampler = new ResampleFilter(rawAudioFormat, transmittedAudioFormat); var conferenceDtx = new DtxFilter(transmittedAudioFormat); IAudioTwoWayFilter enhancer = null; switch (enhancementStack) { case SpeechEnhancementStack.None: enhancer = new NullEchoCancelFilter(mediaConfig.ExpectedAudioLatency, mediaConfig.FilterLength, transmittedAudioFormat, AudioFormat.Default); break; case SpeechEnhancementStack.Speex: enhancer = new SpeexEchoCanceller2(mediaConfig, transmittedAudioFormat, AudioFormat.Default); break; case SpeechEnhancementStack.WebRtc: enhancer = new WebRtcFilter(mediaConfig.ExpectedAudioLatency, mediaConfig.FilterLength, transmittedAudioFormat, AudioFormat.Default, mediaConfig.EnableAec, mediaConfig.EnableDenoise, mediaConfig.EnableAgc); break; } IAudioEncoder encoder = null; switch (codecType) { case AudioCodecType.G711M: encoder = new G711MuLawEncoder(transmittedAudioFormat); break; case AudioCodecType.Speex: encoder = new SpeexEncoder(transmittedAudioFormat); break; } var ctx = new AudioContext(transmittedAudioFormat, resampler, conferenceDtx, enhancer, encoder); return(ctx); }
public SpeexPreprocessFilter(int samplesPerFrame, int samplesPerSecond, MediaConfig config, IAudioTwoWayFilter echoCancelFilter, string instanceName = "") { this.samplesPerSecond = samplesPerSecond; #if SILVERLIGHT st = this; InstanceName = instanceName; st.config = config; speex_preprocess_state_init(samplesPerFrame, samplesPerSecond); AgcLevel = 8000; DereverbEnabled = false; // ks 3/14/11 - VAD is supposedly a "kludge" right now, i.e., it's based on the overall power of the frame, // and that's it. See http://lists.xiph.org/pipermail/speex-dev/2006-March/004271.html for the "fix" that eventually // made its way into Speex as the "kludge". But turning it on seems to help, especially with AGC. VadEnabled = true; // ks 3/14/11 - Adjusted these, because the defaults amplify background noise too much. // See http://lists.xiph.org/pipermail/speex-dev/2007-May/005696.html AgcMaxGain = 15; // Default is 30 // NoiseSuppression = -30; // Default is -15. Recommended is -30, but that sounds awful in my environment. EchoState = echoCancelFilter as SpeexEchoCanceller2; // Will store null if the provided echo canceller isn't a Speex echo canceller, which is what we want. #endif }