/// <summary> /// Writes a data event into the adapter. The given event's buffer is not copied, but stored as reference. /// <see cref="Read(byte[], int, int)"/> must be called immediately to consume this event. Otherwise the event's buffer might become invalid. /// </summary> /// <param name="dataEvent"></param> public void Write(StreamAudioSourceDataEvent dataEvent) { this.Data = dataEvent; DataOffset = 0; }
/// <summary> /// Called when <see cref="WrappedAudioSource"/> raises <see cref="IStreamAudioSource.DataAvailable"/>. /// Processing is happening here: checks on the volume of the received samples and passes the event on to <see cref="DataAvailable"/> if appropriate. /// </summary> /// <param name="data"></param> protected void OnSourceDataAvailable(StreamAudioSourceDataEvent data) { var options = this.Options; var samples = data.Samples; bool logStatistics = AnalyticsLoggingEnabled && (!AnalyticsLoggedOnce || SamplesToTime(AnalyticsSampleCount, data.Format) > TimeSpan.FromMinutes(10)); float statisticsMax = float.MinValue, statisticsMin = float.MaxValue; //evaluate the received samples bool overThreshold = false; foreach (var sample in samples) { var amplitude = GetNormalizedSampleValue(sample, data.Format); if (amplitude > options.VolumeThreshold) { overThreshold = true; if (!logStatistics) { break; } } if (amplitude > statisticsMax) { statisticsMax = amplitude; } if (amplitude < statisticsMin) { statisticsMin = amplitude; } } //print analytics every now and then if (logStatistics && samples.Count > 0) { Logger.LogTrace($"NoiseGate min|max levels: {statisticsMin}|{statisticsMax}"); AnalyticsLoggedOnce = true; AnalyticsSampleCount = 0; } AnalyticsSampleCount += samples.Count; //pass through or mute if (overThreshold) { //pass through SamplesUnderThreshold = 0; StopRequested = false; Muted = false; DataAvailable?.Invoke(this, data); } else { SamplesUnderThreshold += samples.Count; bool mute = Muted; if (!mute) { //check on the time since we were above the threshold var thresholdTime = options.Delay; if (StopRequested && options.DelayStopDetection.TotalMilliseconds >= 0) { //reduce our threshold time thresholdTime = options.DelayStopDetection; } if (TimeUnderThreshold >= thresholdTime) { mute = true; } } if (mute) { Muted = true; StopRequested = false; if (!options.ModeCutOff) { //return a zeroed buffer if (ZeroBuffer == null || ZeroBuffer.Length < data.Buffer.Count) { ZeroBuffer = new byte[data.Buffer.Count]; } DataAvailable?.Invoke(this, new StreamAudioSourceDataEvent() { Buffer = new ArraySegment <byte>(ZeroBuffer, 0, data.Buffer.Count), Format = data.Format }); } //else: simply do nothing } else { //pass through DataAvailable?.Invoke(this, data); } } }