Ejemplo n.º 1
0
        private void BeginOgg(bool isLooping, string volumeGroup)
        {
            if (string.IsNullOrEmpty(this.oggFilePath))
            {
                return;
            }

            lock (this.oggQueueLock) { }
            this.oggPlaybackEnded = false;

            this.oggSource = GenSourceWithVolume(volumeGroup);
            var currentSource = this.oggSource;

            int          channels, bits_per_sample;
            VorbisReader vorbis;

            try
            {
                vorbis = new VorbisReader(this.oggFilePath);
            }
            catch (ArgumentException)
            {
                throw new InvalidOperationException("Invalid .ogg file");
            }

            // get the channels & sample rate
            channels           = vorbis.Channels;
            bits_per_sample    = 16;
            this.oggSampleRate = vorbis.SampleRate;

            var soundFormat = GetSoundFormat(channels, bits_per_sample);

            // OPTIONALLY: get a TimeSpan indicating the total length of the Vorbis stream
            var totalTime = vorbis.TotalTime;

            // create a buffer for reading samples
            var valuesPerBuffer = (int)(channels * oggSampleRate * OggBufferSize); // 1s/5 = 200ms
            var readBuffer      = new float[valuesPerBuffer];

            // get the initial position (obviously the start)
            var position = TimeSpan.Zero;

            this.oggTotalSamples = vorbis.TotalSamples;

            var sampleEnd = isLooping ? this.oggLoopEnd : this.oggTotalSamples;

            if (this.oggProgress < 0 || this.oggProgress >= sampleEnd)
            {
                this.OggSeek(0);
            }

            this.UpdateOggProgress(this.oggPausePosition);
            vorbis.SeekTo(this.oggPausePosition);

            var buffersInitialized = false;

            var buffers = new List <int>();

            var playbackStopDetected = false;

            this.WaitOnLock(this.oggQueueLock, () =>
            {
                for (int i = 0; i < OggBufferCount; i++)
                {
                    var currentBuffer = AL.GenBuffer();
                    QueueBuffer(currentSource, currentBuffer, vorbis, soundFormat, oggSampleRate, valuesPerBuffer, sampleEnd);
                    buffers.Add(currentBuffer);
                }

                var allBuffersProcessed = false;
                while (!buffersInitialized || (!playbackStopDetected && !this.oggPlaybackEnded))
                {
                    buffersInitialized = true;

                    AL.GetSource(currentSource, ALGetSourcei.BuffersQueued, out int buffersQueued);
                    AL.GetSource(currentSource, ALGetSourcei.BuffersProcessed, out int buffersProcessed);

                    var newUnqueuedSize = 0;
                    for (int i = 0; i < buffersProcessed; i++)
                    {
                        var currentBuffer = buffers.First();
                        buffers.Remove(currentBuffer);

                        AL.GetBuffer(currentBuffer, ALGetBufferi.Size, out int currentBufferSize);
                        newUnqueuedSize += currentBufferSize;

                        AL.SourceUnqueueBuffers(currentSource, 1, new[] { currentBuffer });
                        QueueBuffer(currentSource, currentBuffer, vorbis, soundFormat, oggSampleRate, valuesPerBuffer, sampleEnd);
                        buffers.Add(currentBuffer);
                    }

                    allBuffersProcessed = vorbis.SamplePosition >= this.oggTotalSamples && (!isLooping);
                    if (allBuffersProcessed && buffersProcessed != 0)
                    {
                        var unqueuedBuffers = new int[buffersProcessed];
                        AL.SourceUnqueueBuffers(currentSource, buffersProcessed, unqueuedBuffers);
                        foreach (var currentBuffer in unqueuedBuffers)
                        {
                            AL.GetBuffer(currentBuffer, ALGetBufferi.Size, out int currentBufferSize);
                            newUnqueuedSize += currentBufferSize;
                        }
                    }

                    var newProgress      = newUnqueuedSize / (channels * (bits_per_sample / 8));
                    var adjustedProgress = this.oggProgress + newProgress;
                    if (AL.GetSourceState(currentSource) == ALSourceState.Playing)
                    {
                        this.UpdateOggProgress(adjustedProgress);
                    }
                    else
                    {
                        AL.SourcePlay(currentSource);
                    }

                    if (isLooping)
                    {
                        var realLoopEnd = Math.Min(this.oggLoopEnd, this.oggTotalSamples);
                        if (vorbis.SamplePosition >= realLoopEnd)
                        {
                            vorbis.SeekTo(this.oggLoopStart);
                        }
                        if (this.oggProgress >= realLoopEnd)
                        {
                            this.UpdateOggProgress(this.oggLoopStart + (this.oggProgress % realLoopEnd));
                        }
                    }
                    else
                    {
                        var realLoopEnd = Math.Min(this.oggLoopEnd, this.oggTotalSamples);
                        if (vorbis.SamplePosition >= realLoopEnd)
                        {
                            this.oggPlaybackEnded = true;
                        }
                    }
                }
                vorbis.Dispose();
            });

            while (!buffersInitialized)
            {
                Thread.Sleep(10);
            }

            this.OggPlayback?.Invoke(this, new OggPlaybackEventArgs {
                StateChange = ALSourceState.Playing
            });
            this.Play(currentSource, () =>
            {
                playbackStopDetected = true;
                this.WaitOnLock(this.oggQueueLock, () =>
                {
                    foreach (var buf in buffers)
                    {
                        AL.DeleteBuffer(buf);
                    }
                    this.OggPlayback?.Invoke(this, new OggPlaybackEventArgs
                    {
                        StateChange = ALSourceState.Stopped
                    });
                    this.oggSource = -1;
                });
            },
                      true);
        }