public OggStream(Stream stream, Action finishedAction = null, int bufferCount = DefaultBufferCount) { FinishedAction = finishedAction; BufferCount = bufferCount; alBufferIds = AL.GenBuffers(bufferCount); alSourceId = AL.GenSource(); if (ALHelper.XRam.IsInitialized) { ALHelper.XRam.SetBufferMode(BufferCount, ref alBufferIds[0], XRamExtension.XRamStorage.Hardware); ALHelper.Check(); } Volume = 1; if (ALHelper.Efx.IsInitialized) { alFilterId = ALHelper.Efx.GenFilter(); ALHelper.Efx.Filter(alFilterId, EfxFilteri.FilterType, (int)EfxFilterType.Lowpass); ALHelper.Efx.Filter(alFilterId, EfxFilterf.LowpassGain, 1); LowPassHFGain = 1; } underlyingStream = stream; }
void Empty() { int queued; AL.GetSource(alSourceId, ALGetSourcei.BuffersQueued, out queued); if (queued > 0) { try { AL.SourceUnqueueBuffers(alSourceId, queued); ALHelper.Check(); } catch (InvalidOperationException) { // This is a bug in the OpenAL implementation // Salvage what we can int processed; AL.GetSource(alSourceId, ALGetSourcei.BuffersProcessed, out processed); var salvaged = new int[processed]; if (processed > 0) { AL.SourceUnqueueBuffers(alSourceId, processed, salvaged); ALHelper.Check(); } // Try turning it off again? AL.SourceStop(alSourceId); ALHelper.Check(); Empty(); } } }
public void Dispose() { var state = AL.GetSourceState(alSourceId); if (state == ALSourceState.Playing || state == ALSourceState.Paused) StopPlayback(); lock (prepareMutex) { OggStreamer.Instance.RemoveStream(this); if (state != ALSourceState.Initial) Empty(); Close(); underlyingStream.Dispose(); } AL.DeleteSource(alSourceId); AL.DeleteBuffers(alBufferIds); if (ALHelper.Efx.IsInitialized) ALHelper.Efx.DeleteFilter(alFilterId); ALHelper.Check(); }
public void Resume() { if (AL.GetSourceState(alSourceId) != ALSourceState.Paused) return; OggStreamer.Instance.AddStream(this); AL.SourcePlay(alSourceId); ALHelper.Check(); }
public void Pause() { if (AL.GetSourceState(alSourceId) != ALSourceState.Playing) return; OggStreamer.Instance.RemoveStream(this); AL.SourcePause(alSourceId); ALHelper.Check(); }
public bool FillBuffer(OggStream stream, int bufferId) { int readSamples; lock (readMutex) { readSamples = stream.Reader.ReadSamples(readSampleBuffer, 0, BufferSize); CastBuffer(readSampleBuffer, castBuffer, readSamples); } AL.BufferData(bufferId, stream.Reader.Channels == 1 ? ALFormat.Mono16 : ALFormat.Stereo16, castBuffer, readSamples * sizeof (short), stream.Reader.SampleRate); ALHelper.Check(); return readSamples != BufferSize; }
internal void Open(bool precache = false) { underlyingStream.Seek(0, SeekOrigin.Begin); Reader = new VorbisReader(underlyingStream, false); if (precache) { // Fill first buffer synchronously OggStreamer.Instance.FillBuffer(this, alBufferIds[0]); AL.SourceQueueBuffer(alSourceId, alBufferIds[0]); ALHelper.Check(); // Schedule the others asynchronously OggStreamer.Instance.AddStream(this); } Ready = true; }
public void Play() { var state = AL.GetSourceState(alSourceId); switch (state) { case ALSourceState.Playing: return; case ALSourceState.Paused: Resume(); return; } Prepare(); AL.SourcePlay(alSourceId); ALHelper.Check(); Preparing = false; OggStreamer.Instance.AddStream(this); }
void EnsureBuffersFilled() { while (!cancelled) { Thread.Sleep((int) (1000 / ((UpdateRate <= 0) ? 1 : UpdateRate))); if (cancelled) break; threadLocalStreams.Clear(); lock (iterationMutex) threadLocalStreams.AddRange(streams); foreach (var stream in threadLocalStreams) { lock (stream.prepareMutex) { lock (iterationMutex) if (!streams.Contains(stream)) continue; bool finished = false; int queued; AL.GetSource(stream.alSourceId, ALGetSourcei.BuffersQueued, out queued); ALHelper.Check(); int processed; AL.GetSource(stream.alSourceId, ALGetSourcei.BuffersProcessed, out processed); ALHelper.Check(); if (processed == 0 && queued == stream.BufferCount) continue; int[] tempBuffers; if (processed > 0) tempBuffers = AL.SourceUnqueueBuffers(stream.alSourceId, processed); else tempBuffers = stream.alBufferIds.Skip(queued).ToArray(); for (int i = 0; i < tempBuffers.Length; i++) { finished |= FillBuffer(stream, tempBuffers[i]); if (finished) { if (stream.IsLooped) { stream.Close(); stream.Open(); } else { streams.Remove(stream); i = tempBuffers.Length; } if (stream.FinishedAction != null) stream.FinishedAction.Invoke(); } } if (!finished) { AL.SourceQueueBuffers(stream.alSourceId, tempBuffers.Length, tempBuffers); ALHelper.Check(); } else if (!stream.IsLooped) continue; } lock (stream.stopMutex) { if (stream.Preparing) continue; lock (iterationMutex) if (!streams.Contains(stream)) continue; var state = AL.GetSourceState(stream.alSourceId); if (state == ALSourceState.Stopped) { AL.SourcePlay(stream.alSourceId); ALHelper.Check(); } } } } }
void StopPlayback() { AL.SourceStop(alSourceId); ALHelper.Check(); }