working on thread safety

pull/47/head
cosmonaut 2023-03-03 18:12:50 -08:00
parent f70caa1a42
commit 52c4fa26c7
6 changed files with 110 additions and 77 deletions

View File

@ -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<StreamingSound>(instance));
}
streamingSounds.Add(new WeakReference<StreamingSound>(instance));
}
internal void AddResourceReference(WeakReference<AudioResource> resourceReference)
internal void AddResourceReference(AudioResource resource, WeakReference<AudioResource> resourceReference)
{
lock (StateLock)
{
resources.Add(resourceReference);
if (resource is StreamingSound streamingSound)
{
AddDynamicSoundInstance(streamingSound);
}
}
}

View File

@ -15,7 +15,7 @@ namespace MoonWorks.Audio
Device = device;
selfReference = new WeakReference<AudioResource>(this);
Device.AddResourceReference(selfReference);
Device.AddResourceReference(this, selfReference);
}
protected abstract void Destroy();

View File

@ -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]);
}
}
}
}

View File

@ -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);

View File

@ -41,5 +41,7 @@ namespace MoonWorks.Video
filledLengthInBytes = samples * sizeof(float);
reachedEnd = Theorafile.tf_eos(VideoHandle) == 1;
}
protected override void OnReachedEnd() { }
}
}

View File

@ -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;
}