public void UpdateStream() { try { if (!IsStream) { throw new Exception("Called UpdateStream on a non-streamed sound channel!"); } Monitor.Enter(mutex); if (!reachedEndSample) { uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex); int state; Al.GetSourcei(alSource, Al.SourceState, out state); bool playing = state == Al.Playing; int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to determine playing state from streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } int unqueuedBufferCount; Al.GetSourcei(alSource, Al.BuffersProcessed, out unqueuedBufferCount); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to determine processed buffers from streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } Al.SourceUnqueueBuffers(alSource, unqueuedBufferCount, unqueuedBuffers); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to unqueue buffers from streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } buffersToRequeue += unqueuedBufferCount; int iterCount = buffersToRequeue; for (int k = 0; k < iterCount; k++) { int index = queueStartIndex; short[] buffer = streamShortBuffer; int readSamples = Sound.FillStreamBuffer(streamSeekPos, buffer); float readAmplitude = 0.0f; for (int i = 0; i < Math.Min(readSamples, buffer.Length); i++) { float sampleF = ((float)buffer[i]) / ((float)short.MaxValue); readAmplitude = Math.Max(readAmplitude, Math.Abs(sampleF)); } if (FilledByNetwork) { if (Sound is VoipSound voipSound) { voipSound.ApplyFilters(buffer, readSamples); } if (readSamples <= 0) { streamAmplitude *= 0.5f; decayTimer++; if (decayTimer > 120) //TODO: replace magic number { reachedEndSample = true; } } else { decayTimer = 0; } } else if (Sound.StreamsReliably) { streamSeekPos += readSamples; if (readSamples < STREAM_BUFFER_SIZE) { if (looping) { streamSeekPos = 0; } else { reachedEndSample = true; } } } if (readSamples > 0) { streamBufferAmplitudes[index] = readAmplitude; Al.BufferData <short>(streamBuffers[index], Sound.ALFormat, buffer, readSamples, Sound.SampleRate); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to assign data to stream buffer: " + Al.GetErrorString(alError) + ": " + streamBuffers[index].ToString() + "/" + streamBuffers.Length + ", readSamples: " + readSamples + ", " + debugName); } Al.SourceQueueBuffer(alSource, streamBuffers[index]); queueStartIndex = (queueStartIndex + 1) % 4; alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to queue streamBuffer[" + index.ToString() + "] to stream: " + debugName + ", " + Al.GetErrorString(alError)); } } else { if (readSamples < 0) { reachedEndSample = true; } break; } buffersToRequeue--; } streamAmplitude = streamBufferAmplitudes[queueStartIndex]; Al.GetSourcei(alSource, Al.SourceState, out state); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to retrieve stream source state: " + debugName + ", " + Al.GetErrorString(alError)); } if (state != Al.Playing) { Al.SourcePlay(alSource); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to start stream playback: " + debugName + ", " + Al.GetErrorString(alError)); } } } if (reachedEndSample) { streamAmplitude = 0.0f; } } catch (Exception e) { DebugConsole.ThrowError($"An exception was thrown when updating a sound stream ({debugName})", e); } finally { Monitor.Exit(mutex); } }
public void Dispose() { try { if (mutex != null) { Monitor.Enter(mutex); } if (ALSourceIndex >= 0) { Al.SourceStop(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex)); int alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to stop source: " + debugName + ", " + Al.GetErrorString(alError)); } if (IsStream) { uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex); Al.SourceStop(alSource); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to stop streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } int buffersToRequeue = 0; buffersToRequeue = 0; Al.GetSourcei(alSource, Al.BuffersProcessed, out buffersToRequeue); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to determine processed buffers from streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } Al.SourceUnqueueBuffers(alSource, buffersToRequeue, unqueuedBuffers); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to unqueue buffers from streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } Al.Sourcei(alSource, Al.Buffer, 0); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to reset buffer for streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } for (int i = 0; i < 4; i++) { Al.DeleteBuffer(streamBuffers[i]); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to delete streamBuffers[" + i.ToString() + "] (" + streamBuffers[i].ToString() + "): " + debugName + ", " + Al.GetErrorString(alError)); } } reachedEndSample = true; } else { Al.Sourcei(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, 0); alError = Al.GetError(); if (alError != Al.NoError) { throw new Exception("Failed to unbind buffer to non-streamed source: " + debugName + ", " + Al.GetErrorString(alError)); } } ALSourceIndex = -1; debugName += " [DISPOSED]"; } } finally { if (mutex != null) { Monitor.Exit(mutex); } } }