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; finished = UpdateAudioTween(audioTween, soundInstance, elapsedSeconds);
var audioTween = AudioTweens[i]; }
if (audioTween.SoundInstanceReference.TryGetTarget(out var soundInstance)) if (finished)
{ {
finished = UpdateAudioTween(audioTween, soundInstance, elapsedSeconds); 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.Duration = duration;
tween.Time = 0; tween.Time = 0;
lock (AudioTweens) lock (StateLock)
{ {
AudioTweens.Add(tween); AudioTweens.Add(tween);
} }
@ -263,19 +260,21 @@ namespace MoonWorks.Audio
WakeSignal.Set(); 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) lock (StateLock)
{ {
resources.Add(resourceReference); resources.Add(resourceReference);
if (resource is StreamingSound streamingSound)
{
AddDynamicSoundInstance(streamingSound);
}
} }
} }

View File

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

View File

@ -15,6 +15,7 @@ namespace MoonWorks.Audio
private int nextBufferIndex = 0; private int nextBufferIndex = 0;
private uint queuedBufferCount = 0; private uint queuedBufferCount = 0;
protected abstract int BUFFER_SIZE { get; } protected abstract int BUFFER_SIZE { get; }
private readonly object StateLock = new object();
public unsafe StreamingSound( public unsafe StreamingSound(
AudioDevice device, AudioDevice device,
@ -25,8 +26,6 @@ namespace MoonWorks.Audio
uint samplesPerSecond uint samplesPerSecond
) : base(device, formatTag, bitsPerSample, blockAlign, channels, samplesPerSecond) ) : base(device, formatTag, bitsPerSample, blockAlign, channels, samplesPerSecond)
{ {
device.AddDynamicSoundInstance(this);
buffers = new IntPtr[BUFFER_COUNT]; buffers = new IntPtr[BUFFER_COUNT];
for (int i = 0; i < BUFFER_COUNT; i += 1) for (int i = 0; i < BUFFER_COUNT; i += 1)
{ {
@ -46,23 +45,29 @@ namespace MoonWorks.Audio
private void PlayUsingOperationSet(uint operationSet) 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() public override void Pause()
{ {
if (State == SoundState.Playing) lock (StateLock)
{ {
FAudio.FAudioSourceVoice_Stop(Voice, 0, 0); if (State == SoundState.Playing)
State = SoundState.Paused; {
FAudio.FAudioSourceVoice_Stop(Voice, 0, 0);
State = SoundState.Paused;
}
} }
} }
@ -73,20 +78,31 @@ namespace MoonWorks.Audio
public override void StopImmediate() public override void StopImmediate()
{ {
FAudio.FAudioSourceVoice_Stop(Voice, 0, 0); lock (StateLock)
FAudio.FAudioSourceVoice_FlushSourceBuffers(Voice); {
ClearBuffers(); FAudio.FAudioSourceVoice_Stop(Voice, 0, 0);
FAudio.FAudioSourceVoice_FlushSourceBuffers(Voice);
ClearBuffers();
State = SoundState.Stopped; State = SoundState.Stopped;
}
} }
internal unsafe void Update() internal unsafe void Update()
{ {
if (State != SoundState.Playing) lock (StateLock)
{ {
return; if (State != SoundState.Playing)
} {
return;
}
QueueBuffers();
}
}
protected void QueueBuffers()
{
FAudio.FAudioSourceVoice_GetState( FAudio.FAudioSourceVoice_GetState(
Voice, Voice,
out var state, out var state,
@ -95,11 +111,6 @@ namespace MoonWorks.Audio
queuedBufferCount = state.BuffersQueued; queuedBufferCount = state.BuffersQueued;
QueueBuffers();
}
protected void QueueBuffers()
{
for (int i = 0; i < BUFFER_COUNT - queuedBufferCount; i += 1) for (int i = 0; i < BUFFER_COUNT - queuedBufferCount; i += 1)
{ {
AddBuffer(); AddBuffer();
@ -124,37 +135,40 @@ namespace MoonWorks.Audio
out bool reachedEnd out bool reachedEnd
); );
FAudio.FAudioBuffer buf = new FAudio.FAudioBuffer if (filledLengthInBytes > 0)
{ {
AudioBytes = (uint) filledLengthInBytes, FAudio.FAudioBuffer buf = new FAudio.FAudioBuffer
pAudioData = (IntPtr) buffer, {
PlayLength = ( AudioBytes = (uint) filledLengthInBytes,
(uint) (filledLengthInBytes / pAudioData = (IntPtr) buffer,
Format.nChannels / PlayLength = (
(uint) (Format.wBitsPerSample / 8)) (uint) (filledLengthInBytes /
) Format.nChannels /
}; (uint) (Format.wBitsPerSample / 8))
)
};
FAudio.FAudioSourceVoice_SubmitSourceBuffer( FAudio.FAudioSourceVoice_SubmitSourceBuffer(
Voice, Voice,
ref buf, ref buf,
IntPtr.Zero 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) if (reachedEnd)
{ {
/* We have reached the end of the data, what do we do? */
OnReachedEnd(); OnReachedEnd();
} }
} }
protected virtual void OnReachedEnd()
{
Stop();
}
protected unsafe abstract void FillBuffer( protected unsafe abstract void FillBuffer(
void* buffer, void* buffer,
int bufferLengthInBytes, /* in bytes */ int bufferLengthInBytes, /* in bytes */
@ -162,13 +176,18 @@ namespace MoonWorks.Audio
out bool reachedEnd out bool reachedEnd
); );
protected abstract void OnReachedEnd();
protected unsafe override void Destroy() protected unsafe override void Destroy()
{ {
StopImmediate(); lock (StateLock)
for (int i = 0; i < BUFFER_COUNT; i += 1)
{ {
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, AudioDevice device,
IntPtr fileDataPtr, // MUST BE A NATIVE MEMORY HANDLE!! IntPtr fileDataPtr, // MUST BE A NATIVE MEMORY HANDLE!!
IntPtr vorbisHandle, IntPtr vorbisHandle,
@ -47,8 +47,7 @@ namespace MoonWorks.Audio
(ushort) (4 * info.channels), (ushort) (4 * info.channels),
(ushort) info.channels, (ushort) info.channels,
info.sample_rate info.sample_rate
) ) {
{
FileDataPtr = fileDataPtr; FileDataPtr = fileDataPtr;
VorbisHandle = vorbisHandle; VorbisHandle = vorbisHandle;
Info = info; Info = info;
@ -64,8 +63,7 @@ namespace MoonWorks.Audio
int bufferLengthInBytes, int bufferLengthInBytes,
out int filledLengthInBytes, out int filledLengthInBytes,
out bool reachedEnd out bool reachedEnd
) ) {
{
var lengthInFloats = bufferLengthInBytes / sizeof(float); var lengthInFloats = bufferLengthInBytes / sizeof(float);
/* NOTE: this function returns samples per channel, not total samples */ /* NOTE: this function returns samples per channel, not total samples */
@ -81,6 +79,14 @@ namespace MoonWorks.Audio
filledLengthInBytes = sampleCount * sizeof(float); filledLengthInBytes = sampleCount * sizeof(float);
} }
protected override void OnReachedEnd()
{
if (Loop)
{
Seek(0);
}
}
protected unsafe override void Destroy() protected unsafe override void Destroy()
{ {
FAudio.stb_vorbis_close(VorbisHandle); FAudio.stb_vorbis_close(VorbisHandle);

View File

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

View File

@ -130,6 +130,8 @@ namespace MoonWorks.Video
public void Play() public void Play()
{ {
if (Video == null) { return; }
if (State == VideoState.Playing) if (State == VideoState.Playing)
{ {
return; return;
@ -147,6 +149,8 @@ namespace MoonWorks.Video
public void Pause() public void Pause()
{ {
if (Video == null) { return; }
if (State != VideoState.Playing) if (State != VideoState.Playing)
{ {
return; return;
@ -164,6 +168,8 @@ namespace MoonWorks.Video
public void Stop() public void Stop()
{ {
if (Video == null) { return; }
if (State == VideoState.Stopped) if (State == VideoState.Stopped)
{ {
return; return;
@ -172,7 +178,6 @@ namespace MoonWorks.Video
timer.Stop(); timer.Stop();
timer.Reset(); timer.Reset();
Theorafile.tf_reset(Video.Handle);
lastTimestamp = 0; lastTimestamp = 0;
timeElapsed = 0; timeElapsed = 0;
@ -183,6 +188,8 @@ namespace MoonWorks.Video
audioStream = null; audioStream = null;
} }
Theorafile.tf_reset(Video.Handle);
State = VideoState.Stopped; State = VideoState.Stopped;
} }