/// <summary>
        /// Creates a new basic RTP session that captures and renders audio to/from the default system devices.
        /// </summary>
        /// <param name="audioEncoder">A 3rd party audio encoder that can be used to encode and decode
        /// specific audio codecs.</param>
        /// <param name="externalSource">Optional. An external source to use in combination with the source
        /// provided by this end point. The application will need to signal which source is active.</param>
        /// <param name="disableSource">Set to true to disable the use of the audio source functionality, i.e.
        /// don't capture input from the microphone.</param>
        /// <param name="disableSink">Set to true to disable the use of the audio sink functionality, i.e.
        /// don't playback audio to the speaker.</param>
        public WindowsAudioEndPoint(IAudioEncoder audioEncoder,
                                    int audioOutDeviceIndex = AUDIO_OUTPUTDEVICE_INDEX,
                                    int audioInDeviceIndex  = AUDIO_INPUTDEVICE_INDEX,
                                    bool disableSource      = false,
                                    bool disableSink        = false)
        {
            logger = SIPSorcery.LogFactory.CreateLogger <WindowsAudioEndPoint>();

            _audioEncoder = audioEncoder;

            _disableSource = disableSource;
            _disableSink   = disableSink;

            if (!_disableSink)
            {
                try
                {
                    // Playback device.
                    _waveOutEvent = new WaveOutEvent();
                    _waveOutEvent.DeviceNumber = audioOutDeviceIndex;
                    _waveProvider = new BufferedWaveProvider(_waveFormat);
                    _waveProvider.DiscardOnBufferOverflow = true;
                    _waveOutEvent.Init(_waveProvider);
                }
                catch (Exception excp)
                {
                    logger.LogWarning(0, excp, "WindowsAudioEndPoint failed to initialise playback device.");
                    OnAudioSinkError?.Invoke($"WindowsAudioEndPoint failed to initialise playback device. {excp.Message}");
                }
            }

            if (!_disableSource)
            {
                if (WaveInEvent.DeviceCount > 0)
                {
                    if (WaveInEvent.DeviceCount > audioInDeviceIndex)
                    {
                        _waveInEvent = new WaveInEvent();
                        _waveInEvent.BufferMilliseconds = AUDIO_SAMPLE_PERIOD_MILLISECONDS;
                        _waveInEvent.NumberOfBuffers    = INPUT_BUFFERS;
                        _waveInEvent.DeviceNumber       = audioInDeviceIndex;
                        _waveInEvent.WaveFormat         = _waveFormat;
                        _waveInEvent.DataAvailable     += LocalAudioSampleAvailable;
                    }
                    else
                    {
                        OnAudioSourceError?.Invoke($"The requested audio input device index {audioInDeviceIndex} exceeds the maximum index of {WaveInEvent.DeviceCount - 1}.");
                    }
                }
                else
                {
                    OnAudioSourceError?.Invoke("No audio capture devices are available.");
                }
            }
        }
        /// <summary>
        /// Creates a new basic RTP session that captures and renders audio to/from the default system devices.
        /// </summary>
        /// <param name="audioEncoder">An audio encoder that can be used to encode and decode
        /// specific audio codecs.</param>
        /// <param name="externalSource">Optional. An external source to use in combination with the source
        /// provided by this end point. The application will need to signal which source is active.</param>
        /// <param name="disableSource">Set to true to disable the use of the audio source functionality, i.e.
        /// don't capture input from the microphone.</param>
        /// <param name="disableSink">Set to true to disable the use of the audio sink functionality, i.e.
        /// don't playback audio to the speaker.</param>
        public WindowsAudioEndPoint(IAudioEncoder audioEncoder,
                                    int audioOutDeviceIndex = AUDIO_OUTPUTDEVICE_INDEX,
                                    int audioInDeviceIndex  = AUDIO_INPUTDEVICE_INDEX,
                                    bool disableSource      = false,
                                    bool disableSink        = false)
        {
            logger = SIPSorcery.LogFactory.CreateLogger <WindowsAudioEndPoint>();

            _audioFormatManager = new MediaFormatManager <AudioFormat>(audioEncoder.SupportedFormats);
            _audioEncoder       = audioEncoder;

            _audioOutDeviceIndex = audioOutDeviceIndex;
            _disableSource       = disableSource;
            _disableSink         = disableSink;

            if (!_disableSink)
            {
                InitPlaybackDevice(_audioOutDeviceIndex, DefaultAudioPlaybackRate.GetHashCode());
            }

            if (!_disableSource)
            {
                if (WaveInEvent.DeviceCount > 0)
                {
                    if (WaveInEvent.DeviceCount > audioInDeviceIndex)
                    {
                        _waveInEvent = new WaveInEvent();
                        _waveInEvent.BufferMilliseconds = AUDIO_SAMPLE_PERIOD_MILLISECONDS;
                        _waveInEvent.NumberOfBuffers    = INPUT_BUFFERS;
                        _waveInEvent.DeviceNumber       = audioInDeviceIndex;
                        _waveInEvent.WaveFormat         = _waveSourceFormat;
                        _waveInEvent.DataAvailable     += LocalAudioSampleAvailable;
                    }
                    else
                    {
                        logger.LogWarning($"The requested audio input device index {audioInDeviceIndex} exceeds the maximum index of {WaveInEvent.DeviceCount - 1}.");
                        OnAudioSourceError?.Invoke($"The requested audio input device index {audioInDeviceIndex} exceeds the maximum index of {WaveInEvent.DeviceCount - 1}.");
                    }
                }
                else
                {
                    logger.LogWarning("No audio capture devices are available.");
                    OnAudioSourceError?.Invoke("No audio capture devices are available.");
                }
            }
        }