working on thread safety
parent
f70caa1a42
commit
52c4fa26c7
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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() { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue