public bool Read(ArraySegment <float> samples)
        {
            // Start the timer when the first sample is read. All subsequent timing will be based off this.
            if (!_timer.IsRunning)
            {
                _timer.Reset();
                _timer.Start();
            }

            // We always read the amount of requested data, update the count of total data read now
            _totalSamplesRead += samples.Count;

            // If the buffer is too small slighty increase the count of samples read (by 0.1ms) Desync compensation will think it is ahead of
            // where it should be and will slow down playback, which will cause the buffer to grow.
            if (_pipeline.BufferCount < 1)
            {
                _totalSamplesRead += WaveFormat.SampleRate / 10000;
            }

            // Calculate how out of sync playback is (based on actual samples read vs time passed)
            _desync.Update(IdealPlaybackPosition, PlaybackPosition);

            // If playback rate is too fast, slow down immediately (to prevent exhausting the buffer). If playback speed is too slow, ramp up over the next few frames.
            var corrected = _desync.CorrectedPlaybackSpeed;

            PlaybackRate = corrected < PlaybackRate
                         ? corrected
                         : Mathf.LerpUnclamped(PlaybackRate, _desync.CorrectedPlaybackSpeed, 0.25f);

            // Skip audio if necessary to resync the audio stream
            int skippedSamples;
            int skippedMilliseconds;
            var complete = Skip(_desync.DesyncMilliseconds, out skippedSamples, out skippedMilliseconds);

            if (skippedSamples > 0)
            {
                _totalSamplesRead += skippedSamples;
                _desync.Skip(skippedMilliseconds);
            }

            // If skipping completed the session return silence
            if (complete)
            {
                // ReSharper disable once AssignNullToNotNullAttribute
                Array.Clear(samples.Array, samples.Offset, samples.Count);
                return(true);
            }

            // Read from upstream
            return(_upstream.Read(samples));
        }
        public bool Read(ArraySegment <float> samples)
        {
            // If synchroniser is not enabled just pass the request upstream with no playback rate adjustment
            if (!_enabled)
            {
                PlaybackRate = 1;
                return(_upstream.Read(samples));
            }

            // Start the timer when the first sample is read. All subsequent timing will be based off this.
            if (!_timer.IsRunning)
            {
                _timer.Reset();
                _timer.Start();
            }

            // We always read the amount of requested data, update the count of total data read now
            _totalSamplesRead += samples.Count;

            // Calculate how out of sync playback is (based on actual samples read vs time passed)
            _desync.Update(IdealPlaybackPosition, PlaybackPosition);

            // If playback rate is too fast, slow down immediately (to prevent exhausting the buffer). If playback speed is too slow, ramp up over the next few frames.
            var corrected = _desync.CorrectedPlaybackSpeed;

            PlaybackRate = corrected < PlaybackRate
                         ? corrected
                         : Mathf.LerpUnclamped(PlaybackRate, _desync.CorrectedPlaybackSpeed, 0.25f);

            // Skip audio if necessary to resync the audio stream
            int skippedSamples;
            int skippedMilliseconds;
            var complete = Skip(_desync.DesyncMilliseconds, out skippedSamples, out skippedMilliseconds);

            if (skippedSamples > 0)
            {
                _totalSamplesRead += skippedSamples;
                _desync.Skip(skippedMilliseconds);
            }

            // If skipping completed the session return silence
            if (complete)
            {
                // ReSharper disable once AssignNullToNotNullAttribute
                Array.Clear(samples.Array, samples.Offset, samples.Count);
                return(true);
            }

            // Read from upstream
            return(_upstream.Read(samples));
        }
Esempio n. 3
0
        public void OnAudioFilterRead(float[] data, int channels)
        {
            //If there is no session, clear filter and early exit
            var maybeSession = Session;

            if (!maybeSession.HasValue)
            {
                Array.Clear(data, 0, data.Length);
                return;
            }

            _sessionLock.EnterUpgradeableReadLock();
            try
            {
                //Check if there is no session again, this time protected by a lock
                maybeSession = Session;
                if (!maybeSession.HasValue)
                {
                    Array.Clear(data, 0, data.Length);
                    return;
                }

                //Detect if the session has changed since the last call to this method, if so reset
                if (!maybeSession.Value.Context.Equals(_lastPlayedSessionContext))
                {
                    _lastPlayedSessionContext = maybeSession.Value.Context;
                    ApplyReset();
                }

                //Calculate the difference between where we should be and where we are (in samples)
                var session = maybeSession.Value;
                _desync.Update(IdealPlaybackPosition, PlaybackPosition);

                //If necessary skip samples to bring us back in sync
                int deltaDesync, deltaSamples;
                var complete = Skip(session, _desync.DesyncMilliseconds, out deltaSamples, out deltaDesync);
                Interlocked.Add(ref _totalSamplesRead, deltaSamples);
                _desync.Skip(deltaDesync);

                //If the session wasn't completed by the skip, keep playing
                if (!complete)
                {
                    int   samples;
                    float arv;
                    complete = Filter(session, data, channels, _temp, _diagnosticOutput, out arv, out samples, MultiplyBySource);
                    _arv     = arv;
                    Interlocked.Add(ref _totalSamplesRead, samples);
                }

                //Clean up now that this session is complete
                if (complete)
                {
                    Log.Debug("Finished playback of speech session. id={0}", session.Context.Id);

                    //Clear the session
                    _sessionLock.EnterWriteLock();
                    try
                    {
                        Session = null;
                    }
                    finally
                    {
                        _sessionLock.ExitWriteLock();
                    }

                    //Reset the state
                    ApplyReset();

                    //Discard the diagnostic recorder if necessary
                    if (_diagnosticOutput != null)
                    {
                        _diagnosticOutput.Dispose();
                        _diagnosticOutput = null;
                    }
                }
            }
            finally
            {
                _sessionLock.ExitUpgradeableReadLock();
            }
        }