From 52c4fa26c7d4415964091de9548e43ccf2f92b36 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Fri, 3 Mar 2023 18:12:50 -0800 Subject: [PATCH] working on thread safety --- src/Audio/AudioDevice.cs | 41 +++++------ src/Audio/AudioResource.cs | 2 +- src/Audio/StreamingSound.cs | 117 +++++++++++++++++------------- src/Audio/StreamingSoundOgg.cs | 16 ++-- src/Video/StreamingSoundTheora.cs | 2 + src/Video/VideoPlayer.cs | 9 ++- 6 files changed, 110 insertions(+), 77 deletions(-) diff --git a/src/Audio/AudioDevice.cs b/src/Audio/AudioDevice.cs index b0bd155..f4512d6 100644 --- a/src/Audio/AudioDevice.cs +++ b/src/Audio/AudioDevice.cs @@ -163,23 +163,20 @@ namespace MoonWorks.Audio } } - lock (AudioTweens) + for (var i = AudioTweens.Count - 1; i >= 0; i--) { - for (var i = AudioTweens.Count - 1; i >= 0; i--) + bool finished = true; + var audioTween = AudioTweens[i]; + + if (audioTween.SoundInstanceReference.TryGetTarget(out var soundInstance)) { - bool finished = true; - var audioTween = AudioTweens[i]; + finished = UpdateAudioTween(audioTween, soundInstance, elapsedSeconds); + } - if (audioTween.SoundInstanceReference.TryGetTarget(out var soundInstance)) - { - finished = UpdateAudioTween(audioTween, soundInstance, elapsedSeconds); - } - - if (finished) - { - AudioTweenPool.Free(audioTween); - AudioTweens.RemoveAt(i); - } + if (finished) + { + AudioTweenPool.Free(audioTween); + AudioTweens.RemoveAt(i); } } } @@ -206,7 +203,7 @@ namespace MoonWorks.Audio tween.Duration = duration; tween.Time = 0; - lock (AudioTweens) + lock (StateLock) { AudioTweens.Add(tween); } @@ -263,19 +260,21 @@ namespace MoonWorks.Audio WakeSignal.Set(); } - internal void AddDynamicSoundInstance(StreamingSound instance) + private void AddDynamicSoundInstance(StreamingSound instance) { - lock (StateLock) - { - streamingSounds.Add(new WeakReference(instance)); - } + streamingSounds.Add(new WeakReference(instance)); } - internal void AddResourceReference(WeakReference resourceReference) + internal void AddResourceReference(AudioResource resource, WeakReference resourceReference) { lock (StateLock) { resources.Add(resourceReference); + + if (resource is StreamingSound streamingSound) + { + AddDynamicSoundInstance(streamingSound); + } } } diff --git a/src/Audio/AudioResource.cs b/src/Audio/AudioResource.cs index edf8b49..aa83763 100644 --- a/src/Audio/AudioResource.cs +++ b/src/Audio/AudioResource.cs @@ -15,7 +15,7 @@ namespace MoonWorks.Audio Device = device; selfReference = new WeakReference(this); - Device.AddResourceReference(selfReference); + Device.AddResourceReference(this, selfReference); } protected abstract void Destroy(); diff --git a/src/Audio/StreamingSound.cs b/src/Audio/StreamingSound.cs index 6d88f68..059a2c9 100644 --- a/src/Audio/StreamingSound.cs +++ b/src/Audio/StreamingSound.cs @@ -15,6 +15,7 @@ namespace MoonWorks.Audio private int nextBufferIndex = 0; private uint queuedBufferCount = 0; protected abstract int BUFFER_SIZE { get; } + private readonly object StateLock = new object(); public unsafe StreamingSound( AudioDevice device, @@ -25,8 +26,6 @@ namespace MoonWorks.Audio uint samplesPerSecond ) : base(device, formatTag, bitsPerSample, blockAlign, channels, samplesPerSecond) { - device.AddDynamicSoundInstance(this); - buffers = new IntPtr[BUFFER_COUNT]; for (int i = 0; i < BUFFER_COUNT; i += 1) { @@ -46,23 +45,29 @@ namespace MoonWorks.Audio private void PlayUsingOperationSet(uint operationSet) { - if (State == SoundState.Playing) + lock (StateLock) { - return; + if (State == SoundState.Playing) + { + return; + } + + State = SoundState.Playing; + + QueueBuffers(); + FAudio.FAudioSourceVoice_Start(Voice, 0, operationSet); } - - State = SoundState.Playing; - - Update(); - FAudio.FAudioSourceVoice_Start(Voice, 0, operationSet); } public override void Pause() { - if (State == SoundState.Playing) + lock (StateLock) { - FAudio.FAudioSourceVoice_Stop(Voice, 0, 0); - State = SoundState.Paused; + if (State == SoundState.Playing) + { + FAudio.FAudioSourceVoice_Stop(Voice, 0, 0); + State = SoundState.Paused; + } } } @@ -73,20 +78,31 @@ namespace MoonWorks.Audio public override void StopImmediate() { - FAudio.FAudioSourceVoice_Stop(Voice, 0, 0); - FAudio.FAudioSourceVoice_FlushSourceBuffers(Voice); - ClearBuffers(); + lock (StateLock) + { + FAudio.FAudioSourceVoice_Stop(Voice, 0, 0); + FAudio.FAudioSourceVoice_FlushSourceBuffers(Voice); + ClearBuffers(); - State = SoundState.Stopped; + State = SoundState.Stopped; + } } internal unsafe void Update() { - if (State != SoundState.Playing) + lock (StateLock) { - return; - } + if (State != SoundState.Playing) + { + return; + } + QueueBuffers(); + } + } + + protected void QueueBuffers() + { FAudio.FAudioSourceVoice_GetState( Voice, out var state, @@ -95,11 +111,6 @@ namespace MoonWorks.Audio queuedBufferCount = state.BuffersQueued; - QueueBuffers(); - } - - protected void QueueBuffers() - { for (int i = 0; i < BUFFER_COUNT - queuedBufferCount; i += 1) { AddBuffer(); @@ -124,37 +135,40 @@ namespace MoonWorks.Audio out bool reachedEnd ); - FAudio.FAudioBuffer buf = new FAudio.FAudioBuffer + if (filledLengthInBytes > 0) { - AudioBytes = (uint) filledLengthInBytes, - pAudioData = (IntPtr) buffer, - PlayLength = ( - (uint) (filledLengthInBytes / - Format.nChannels / - (uint) (Format.wBitsPerSample / 8)) - ) - }; + FAudio.FAudioBuffer buf = new FAudio.FAudioBuffer + { + AudioBytes = (uint) filledLengthInBytes, + pAudioData = (IntPtr) buffer, + PlayLength = ( + (uint) (filledLengthInBytes / + Format.nChannels / + (uint) (Format.wBitsPerSample / 8)) + ) + }; - FAudio.FAudioSourceVoice_SubmitSourceBuffer( - Voice, - ref buf, - IntPtr.Zero - ); + FAudio.FAudioSourceVoice_SubmitSourceBuffer( + Voice, + ref buf, + IntPtr.Zero + ); - queuedBufferCount += 1; + queuedBufferCount += 1; + } + else if (queuedBufferCount == 0) + { + // no more data, nothing queued, we're done + Stop(); + } - /* We have reached the end of the file, what do we do? */ if (reachedEnd) { + /* We have reached the end of the data, what do we do? */ OnReachedEnd(); } } - protected virtual void OnReachedEnd() - { - Stop(); - } - protected unsafe abstract void FillBuffer( void* buffer, int bufferLengthInBytes, /* in bytes */ @@ -162,13 +176,18 @@ namespace MoonWorks.Audio out bool reachedEnd ); + protected abstract void OnReachedEnd(); + protected unsafe override void Destroy() { - StopImmediate(); - - for (int i = 0; i < BUFFER_COUNT; i += 1) + lock (StateLock) { - NativeMemory.Free((void*) buffers[i]); + StopImmediate(); + + for (int i = 0; i < BUFFER_COUNT; i += 1) + { + NativeMemory.Free((void*) buffers[i]); + } } } } diff --git a/src/Audio/StreamingSoundOgg.cs b/src/Audio/StreamingSoundOgg.cs index 1d37c09..e258ec1 100644 --- a/src/Audio/StreamingSoundOgg.cs +++ b/src/Audio/StreamingSoundOgg.cs @@ -35,7 +35,7 @@ namespace MoonWorks.Audio ); } - internal StreamingSoundOgg( + internal unsafe StreamingSoundOgg( AudioDevice device, IntPtr fileDataPtr, // MUST BE A NATIVE MEMORY HANDLE!! IntPtr vorbisHandle, @@ -47,8 +47,7 @@ namespace MoonWorks.Audio (ushort) (4 * info.channels), (ushort) info.channels, info.sample_rate - ) - { + ) { FileDataPtr = fileDataPtr; VorbisHandle = vorbisHandle; Info = info; @@ -64,8 +63,7 @@ namespace MoonWorks.Audio int bufferLengthInBytes, out int filledLengthInBytes, out bool reachedEnd - ) - { + ) { var lengthInFloats = bufferLengthInBytes / sizeof(float); /* NOTE: this function returns samples per channel, not total samples */ @@ -81,6 +79,14 @@ namespace MoonWorks.Audio filledLengthInBytes = sampleCount * sizeof(float); } + protected override void OnReachedEnd() + { + if (Loop) + { + Seek(0); + } + } + protected unsafe override void Destroy() { FAudio.stb_vorbis_close(VorbisHandle); diff --git a/src/Video/StreamingSoundTheora.cs b/src/Video/StreamingSoundTheora.cs index a49c939..41ddca3 100644 --- a/src/Video/StreamingSoundTheora.cs +++ b/src/Video/StreamingSoundTheora.cs @@ -41,5 +41,7 @@ namespace MoonWorks.Video filledLengthInBytes = samples * sizeof(float); reachedEnd = Theorafile.tf_eos(VideoHandle) == 1; } + + protected override void OnReachedEnd() { } } } diff --git a/src/Video/VideoPlayer.cs b/src/Video/VideoPlayer.cs index b040542..9269153 100644 --- a/src/Video/VideoPlayer.cs +++ b/src/Video/VideoPlayer.cs @@ -130,6 +130,8 @@ namespace MoonWorks.Video public void Play() { + if (Video == null) { return; } + if (State == VideoState.Playing) { return; @@ -147,6 +149,8 @@ namespace MoonWorks.Video public void Pause() { + if (Video == null) { return; } + if (State != VideoState.Playing) { return; @@ -164,6 +168,8 @@ namespace MoonWorks.Video public void Stop() { + if (Video == null) { return; } + if (State == VideoState.Stopped) { return; @@ -172,7 +178,6 @@ namespace MoonWorks.Video timer.Stop(); timer.Reset(); - Theorafile.tf_reset(Video.Handle); lastTimestamp = 0; timeElapsed = 0; @@ -183,6 +188,8 @@ namespace MoonWorks.Video audioStream = null; } + Theorafile.tf_reset(Video.Handle); + State = VideoState.Stopped; }