public OggStream(Stream stream, int bufferCount = DefaultBufferCount) { 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; Logger = NullLogger.Default; }
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(); if (readSamples == BufferSize) { Logger.Log(LogEvent.NewPacket, stream); } else { Logger.Log(LogEvent.LastPacket, stream); } Logger.Log(LogEventSingle.MemoryUsage, () => GC.GetTotalMemory(false)); return(readSamples != BufferSize); }
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(); } } Logger.Log(LogEvent.Empty, this); }
// --- 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(); Logger.Log(LogEventSingle.MemoryUsage, () => GC.GetTotalMemory(true)); }
public void Resume() { if (AL.GetSourceState(alSourceId) != ALSourceState.Paused) { return; } OggStreamer.Instance.AddStream(this); Logger.Log(LogEvent.Resume, this); AL.SourcePlay(alSourceId); ALHelper.Check(); }
public void Pause() { if (AL.GetSourceState(alSourceId) != ALSourceState.Playing) { return; } OggStreamer.Instance.RemoveStream(this); Logger.Log(LogEvent.Pause, this); AL.SourcePause(alSourceId); ALHelper.Check(); }
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(); Logger.Log(LogEvent.Play, this); AL.SourcePlay(alSourceId); ALHelper.Check(); Preparing = false; OggStreamer.Instance.AddStream(this); }
void EnsureBuffersFilled() { while (!cancelled) { Thread.Sleep((int)(1000 / 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.Reader.DecodedTime = TimeSpan.Zero; } else { streams.Remove(stream); i = tempBuffers.Length; } } } AL.SourceQueueBuffers(stream.alSourceId, tempBuffers.Length, tempBuffers); ALHelper.Check(); if (finished && !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) { Logger.Log(LogEvent.BufferUnderrun, stream); AL.SourcePlay(stream.alSourceId); ALHelper.Check(); } } } } }
void StopPlayback() { AL.SourceStop(alSourceId); ALHelper.Check(); }