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);
        }
        /// <summary>
        /// Creates a new instance of the AudioContextFactory.
        /// </summary>
        /// <param name="rawAudioFormat">The format in which the audio coming directly from the microphone is recorded</param>
        /// <param name="playedAudioFormat">The format in which the audio will be played back on the far end (typically 16Khz)</param>
        /// <param name="config">The currently active MediaConfig instance</param>
        /// <param name="mediaEnvironment">An IMediaEnvironment instance which can be used to make decisions about which context to return, for instance,
        /// if the CPU is running too hot, or multiple people have joined the conference.</param>
        public AudioContextFactory(AudioFormat rawAudioFormat, AudioFormat playedAudioFormat, MediaConfig config, IMediaEnvironment mediaEnvironment)
        {
            RawAudioFormat    = rawAudioFormat;
            PlayedAudioFormat = playedAudioFormat;
            MediaConfig       = config;
            MediaEnvironment  = mediaEnvironment;

            // What we should use when there's only one other person, and CPU is OK:
            // 16Khz, Speex, WebRtc at full strength
            var directAudioFormat = new AudioFormat();
            var directResampler   = new ResampleFilter(rawAudioFormat, directAudioFormat);

            directResampler.InstanceName = "High Quality Direct Resampler";
            var directEnhancer = new WebRtcFilter(config.ExpectedAudioLatency, config.FilterLength, directAudioFormat, playedAudioFormat, config.EnableAec, config.EnableDenoise, config.EnableAgc);

            directEnhancer.InstanceName = "High";
            var directDtx     = new DtxFilter(directAudioFormat);
            var directEncoder = new SpeexEncoder(directAudioFormat);

            HighQualityDirectCtx             = new AudioContext(directAudioFormat, directResampler, directDtx, directEnhancer, directEncoder);
            HighQualityDirectCtx.Description = "High Quality Direct";

            // What we should use when there are multiple people (and hence the audio will need to be decoded and mixed), but CPU is OK:
            // 8Khz, G711, WebRtc at full strength
            var conferenceAudioFormat = new AudioFormat(AudioConstants.NarrowbandSamplesPerSecond);
            var conferenceResampler   = new ResampleFilter(rawAudioFormat, conferenceAudioFormat);

            conferenceResampler.InstanceName = "High Quality Conference Resampler";
            var conferenceEnhancer = new WebRtcFilter(config.ExpectedAudioLatency, config.FilterLength, conferenceAudioFormat, playedAudioFormat, config.EnableAec, config.EnableDenoise, config.EnableAgc);

            conferenceEnhancer.InstanceName = "Medium";
            var conferenceDtx     = new DtxFilter(conferenceAudioFormat);
            var conferenceEncoder = new G711MuLawEncoder(conferenceAudioFormat);

            HighQualityConferenceCtx             = new AudioContext(conferenceAudioFormat, conferenceResampler, conferenceDtx, conferenceEnhancer, conferenceEncoder);
            HighQualityConferenceCtx.Description = "High Quality Conference";

            // What we should use when one or more remote CPU's isn't keeping up (regardless of how many people are in the room):
            // 8Khz, G711, WebRtc at full-strength
            var remoteFallbackAudioFormat = new AudioFormat(AudioConstants.NarrowbandSamplesPerSecond);
            var remoteFallbackResampler   = new ResampleFilter(rawAudioFormat, remoteFallbackAudioFormat);

            remoteFallbackResampler.InstanceName = "Low Quality Remote CPU Resampler";
            var remoteFallbackEnhancer = new WebRtcFilter(config.ExpectedAudioLatency, config.FilterLength, remoteFallbackAudioFormat, playedAudioFormat, config.EnableAec, config.EnableDenoise, config.EnableAgc);

            remoteFallbackEnhancer.InstanceName = "Medium";
            var remoteFallbackDtx     = new DtxFilter(remoteFallbackAudioFormat);
            var remoteFallbackEncoder = new G711MuLawEncoder(remoteFallbackAudioFormat);

            LowQualityForRemoteCpuCtx             = new AudioContext(remoteFallbackAudioFormat, remoteFallbackResampler, remoteFallbackDtx, remoteFallbackEnhancer, remoteFallbackEncoder);
            LowQualityForRemoteCpuCtx.Description = "Fallback for remote high CPU";

            // What we should use when the local CPU isn't keeping up (regardless of how many people are in the room):
            // 8Khz, G711, WebRtc at half-strength
            var fallbackAudioFormat = new AudioFormat(AudioConstants.NarrowbandSamplesPerSecond);
            var fallbackResampler   = new ResampleFilter(rawAudioFormat, fallbackAudioFormat);

            fallbackResampler.InstanceName = "Low Quality Local CPU Resampler";
            var fallbackEnhancer = new WebRtcFilter(config.ExpectedAudioLatencyFallback, config.FilterLengthFallback, fallbackAudioFormat, playedAudioFormat, config.EnableAec, false, false);

            fallbackEnhancer.InstanceName = "Low";
            var fallbackDtx     = new DtxFilter(fallbackAudioFormat);
            var fallbackEncoder = new G711MuLawEncoder(fallbackAudioFormat);

            LowQualityForLocalCpuCtx             = new AudioContext(fallbackAudioFormat, fallbackResampler, fallbackDtx, fallbackEnhancer, fallbackEncoder);
            LowQualityForLocalCpuCtx.Description = "Fallback for local high CPU";

            _audioContextAdapter = new EnvironmentAdapter <AudioContext>(mediaEnvironment,
                                                                         HighQualityDirectCtx,
                                                                         HighQualityConferenceCtx,
                                                                         LowQualityForRemoteCpuCtx,
                                                                         LowQualityForLocalCpuCtx);
        }
        public void CreateAudioContexts()
        {
            _captureSource.VideoCaptureDevice = null;
            if (_captureSource.AudioCaptureDevice == null)
            {
                _captureSource.AudioCaptureDevice = CaptureDeviceConfiguration.GetDefaultAudioCaptureDevice();
                if (_captureSource.AudioCaptureDevice == null)
                {
                    throw new InvalidOperationException("No suitable audio capture device was found");
                }
            }
            MediaDeviceConfig.SelectBestAudioFormat(_captureSource.AudioCaptureDevice);
            _captureSource.AudioCaptureDevice.AudioFrameSize = AudioFormat.Default.MillisecondsPerFrame;             // 20 milliseconds
            var desiredFormat  = _captureSource.AudioCaptureDevice.DesiredFormat;
            var rawAudioFormat = new AudioFormat(desiredFormat.SamplesPerSecond, AudioFormat.Default.MillisecondsPerFrame, desiredFormat.Channels, desiredFormat.BitsPerSample);

            var playedAudioFormat = new AudioFormat();
            var config            = MediaConfig.Default;

            // Absolutely bare minimum processing - doesn't process sound at all.
            var nullAudioFormat = new AudioFormat();
            var nullResampler   = new ResampleFilter(rawAudioFormat, nullAudioFormat);

            nullResampler.InstanceName = "Null resample filter";
            var nullEnhancer = new NullEchoCancelFilter(config.ExpectedAudioLatency, config.FilterLength, nullAudioFormat, playedAudioFormat);

            nullEnhancer.InstanceName = "Null";
            var nullDtx          = new NullAudioInplaceFilter();
            var nullEncoder      = new NullAudioEncoder();
            var nullAudioContext = new AudioContext(nullAudioFormat, nullResampler, nullDtx, nullEnhancer, nullEncoder);

            nullAudioContext.Description = "Null";

            // What we should use when there's only one other person, and CPU is OK:
            // 16Khz, Speex, WebRtc at full strength
            var directAudioFormat = new AudioFormat();
            var directResampler   = new ResampleFilter(rawAudioFormat, directAudioFormat);

            directResampler.InstanceName = "Direct high quality resample filter";
            var directEnhancer = new WebRtcFilter(config.ExpectedAudioLatency, config.FilterLength, directAudioFormat, playedAudioFormat, config.EnableAec, config.EnableDenoise, config.EnableAgc);

            directEnhancer.InstanceName = "High";
            var directDtx          = new DtxFilter(directAudioFormat);
            var directEncoder      = new SpeexEncoder(directAudioFormat);
            var directAudioContext = new AudioContext(directAudioFormat, directResampler, directDtx, directEnhancer, directEncoder);

            directAudioContext.Description = "High Quality Direct";

            // What we should use when there are multiple people (and hence the audio will need to be decoded and mixed), but CPU is OK:
            // 8Khz, G711, WebRtc at full strength
            var conferenceAudioFormat = new AudioFormat(AudioConstants.NarrowbandSamplesPerSecond);
            var conferenceResampler   = new ResampleFilter(rawAudioFormat, conferenceAudioFormat);

            conferenceResampler.InstanceName = "Conference high quality resample filter";
            var conferenceEnhancer = new WebRtcFilter(config.ExpectedAudioLatency, config.FilterLength, conferenceAudioFormat, playedAudioFormat, config.EnableAec, config.EnableDenoise, config.EnableAgc);

            conferenceEnhancer.InstanceName = "Medium";
            var conferenceDtx          = new DtxFilter(conferenceAudioFormat);
            var conferenceEncoder      = new G711MuLawEncoder(conferenceAudioFormat);
            var conferenceAudioContext = new AudioContext(conferenceAudioFormat, conferenceResampler, conferenceDtx, conferenceEnhancer, conferenceEncoder);

            conferenceAudioContext.Description = "High Quality Conference";

            // What we should use when one or more remote CPU's isn't keeping up (regardless of how many people are in the room):
            // 8Khz, G711, WebRtc at full-strength
            var remoteFallbackAudioFormat = new AudioFormat(AudioConstants.NarrowbandSamplesPerSecond);
            var remoteFallbackResampler   = new ResampleFilter(rawAudioFormat, remoteFallbackAudioFormat);

            remoteFallbackResampler.InstanceName = "Fallback remote high cpu resample filter";
            var remoteFallbackEnhancer = new WebRtcFilter(config.ExpectedAudioLatency, config.FilterLength, remoteFallbackAudioFormat, playedAudioFormat, config.EnableAec, config.EnableDenoise, config.EnableAgc);

            remoteFallbackEnhancer.InstanceName = "Medium";
            var remoteFallbackDtx          = new DtxFilter(remoteFallbackAudioFormat);
            var remoteFallbackEncoder      = new G711MuLawEncoder(remoteFallbackAudioFormat);
            var remoteFallbackAudioContext = new AudioContext(remoteFallbackAudioFormat, remoteFallbackResampler, remoteFallbackDtx, remoteFallbackEnhancer, remoteFallbackEncoder);

            remoteFallbackAudioContext.Description = "Fallback for remote high CPU";

            // What we should use when the local CPU isn't keeping up (regardless of how many people are in the room):
            // 8Khz, G711, WebRtc at half-strength
            var fallbackAudioFormat = new AudioFormat(AudioConstants.NarrowbandSamplesPerSecond);
            var fallbackResampler   = new ResampleFilter(rawAudioFormat, fallbackAudioFormat);

            fallbackResampler.InstanceName = "Fallback resample filter";
            var fallbackEnhancer = new WebRtcFilter(config.ExpectedAudioLatencyFallback, config.FilterLengthFallback, fallbackAudioFormat, playedAudioFormat, config.EnableAec, false, false);

            fallbackEnhancer.InstanceName = "Low";
            var fallbackDtx          = new DtxFilter(fallbackAudioFormat);
            var fallbackEncoder      = new G711MuLawEncoder(fallbackAudioFormat);
            var fallbackAudioContext = new AudioContext(fallbackAudioFormat, fallbackResampler, fallbackDtx, fallbackEnhancer, fallbackEncoder);

            fallbackAudioContext.Description = "Fallback for local high CPU";

            AudioContextCollection.Clear();
            AudioContextCollection.Add(nullAudioContext);
            AudioContextCollection.Add(directAudioContext);
            AudioContextCollection.Add(conferenceAudioContext);
            AudioContextCollection.Add(remoteFallbackAudioContext);
            AudioContextCollection.Add(fallbackAudioContext);

            CurrentAudioContext = nullAudioContext;
        }