diff --git a/Vocaluxe/Base/CSound.cs b/Vocaluxe/Base/CSound.cs index a09ba20a..d5fbd50d 100644 --- a/Vocaluxe/Base/CSound.cs +++ b/Vocaluxe/Base/CSound.cs @@ -83,7 +83,8 @@ namespace Vocaluxe.Base public static void Close() { - CloseAllStreams(); + if (_Playback != null) + _Playback.Close(); _Playback = null; } diff --git a/Vocaluxe/Lib/Sound/Playback/Gstreamer/CGstreamerAudio.cs b/Vocaluxe/Lib/Sound/Playback/Gstreamer/CGstreamerAudio.cs index 66a30301..2b6a663a 100644 --- a/Vocaluxe/Lib/Sound/Playback/Gstreamer/CGstreamerAudio.cs +++ b/Vocaluxe/Lib/Sound/Playback/Gstreamer/CGstreamerAudio.cs @@ -45,6 +45,11 @@ namespace Vocaluxe.Lib.Sound.Playback.Gstreamer return CGstreamerAudioWrapper.Init(); } + public void Close() + { + CloseAll(); + } + public void SetGlobalVolume(float volume) { CGstreamerAudioWrapper.SetGlobalVolume(volume); diff --git a/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudio.cs b/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudio.cs index 640b0c8d..f95c2c91 100644 --- a/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudio.cs +++ b/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudio.cs @@ -27,6 +27,8 @@ namespace Vocaluxe.Lib.Sound.Playback.GstreamerSharp public bool Init() { + if (Application.IsInitialized) + return false; #if ARCH_X86 const string path = ".\\x86\\gstreamer"; #endif @@ -41,6 +43,14 @@ namespace Vocaluxe.Lib.Sound.Playback.GstreamerSharp return Application.IsInitialized; } + public void Close() + { + if (!Application.IsInitialized) + return; + CloseAll(); + Application.Deinit(); + } + public void SetGlobalVolume(float volume) { foreach (CGstreamerSharpAudioStream stream in _Streams.Values) diff --git a/Vocaluxe/Lib/Sound/Playback/IPlayback.cs b/Vocaluxe/Lib/Sound/Playback/IPlayback.cs index 13ce9857..47fd10a9 100644 --- a/Vocaluxe/Lib/Sound/Playback/IPlayback.cs +++ b/Vocaluxe/Lib/Sound/Playback/IPlayback.cs @@ -40,6 +40,7 @@ namespace Vocaluxe.Lib.Sound.Playback interface IPlayback { bool Init(); + void Close(); void SetGlobalVolume(float volume); int GetStreamCount(); void CloseAll(); diff --git a/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenALPlay.cs b/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenALPlay.cs index ac7b533b..558ab7ee 100644 --- a/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenALPlay.cs +++ b/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenALPlay.cs @@ -16,6 +16,7 @@ #endregion using System.Linq; +using System.Threading; using OpenTK.Audio; using System; using System.Collections.Generic; @@ -34,10 +35,15 @@ namespace Vocaluxe.Lib.Sound.Playback.OpenAL private List _Streams; + ~COpenALPlay() + { + _Dispose(false); + } + public bool Init() { if (_Initialized) - CloseAll(); + return false; _Context = new AudioContext(); @@ -51,6 +57,11 @@ namespace Vocaluxe.Lib.Sound.Playback.OpenAL return true; } + public void Close() + { + Dispose(); + } + public void CloseAll() { lock (_MutexDecoder) @@ -321,24 +332,37 @@ namespace Vocaluxe.Lib.Sound.Playback.OpenAL private void _CloseProc(int streamID) { - if (_Initialized) + if (!_Initialized) + return; + lock (_MutexDecoder) { - lock (_MutexDecoder) + if (_AlreadyAdded(streamID)) { - if (_AlreadyAdded(streamID)) - { - int index = _GetStreamIndex(streamID); - _Decoder.RemoveAt(index); - _Streams.RemoveAt(index); - } + int index = _GetStreamIndex(streamID); + _Decoder.RemoveAt(index); + _Streams.RemoveAt(index); } } } public void Dispose() { - _Context.Dispose(); - _Context = null; + _Dispose(true); + } + + private void _Dispose(bool disposing) + { + CloseAll(); + if (disposing) + { + while (_Decoder.Count > 0) + Thread.Sleep(5); + } + if (_Context != null) + { + _Context.Dispose(); + _Context = null; + } } public void FadeAndStop(int stream, float targetVolume, float seconds) diff --git a/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenAlStream.cs b/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenAlStream.cs index f3742b7d..ca76bd3d 100644 --- a/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenAlStream.cs +++ b/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenAlStream.cs @@ -9,7 +9,7 @@ using VocaluxeLib; namespace Vocaluxe.Lib.Sound.Playback.OpenAL { - class COpenAlStream : IDisposable + class COpenAlStream { private const int _BufferSize = 2048; private const int _BufferCount = 5; @@ -70,6 +70,7 @@ namespace Vocaluxe.Lib.Sound.Playback.OpenAL _StreamID = streamID; _Terminated = true; _CloseMutex = closeMutex; + _EventDecode.Set(); } public float Length @@ -372,6 +373,11 @@ namespace Vocaluxe.Lib.Sound.Playback.OpenAL } _Closeproc(_StreamID); + if (_EventDecode != null) + { + _EventDecode.Dispose(); + _EventDecode = null; + } } #endregion Threading @@ -464,11 +470,5 @@ namespace Vocaluxe.Lib.Sound.Playback.OpenAL _CurrentTime = _TimeCode - _Data.BytesNotRead / _BytesPerSecond - 0.1f; _Timer.Restart(); } - - public void Dispose() - { - _EventDecode.Close(); - _EventDecode = null; - } } } \ No newline at end of file diff --git a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioPlay.cs b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioPlay.cs index 86f62f4d..ce029c63 100644 --- a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioPlay.cs +++ b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioPlay.cs @@ -21,29 +21,43 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio { class CPortAudioPlay : IPlayback { - private bool _Initialized; + private volatile bool _Initialized; private readonly List _Streams = new List(); private int _NextID; public bool Init() { if (_Initialized) - CloseAll(); + return false; _Initialized = true; return true; } + public void Close() + { + _Initialized = false; //Set this first, so threads don't call closeproc anymore + List streams = new List(); + //Get all streams but do not modify list without holding the lock + //Calling dispose from within the lock may deadlock in closeproc (if a thread is already there) + lock (_Streams) + { + streams.AddRange(_Streams); + _Streams.Clear(); + } + foreach (CPortAudioStream stream in streams) + stream.Dispose(); + } + public void CloseAll() { lock (_Streams) { foreach (CPortAudioStream stream in _Streams) - stream.Free(); + stream.Close(); _Streams.Clear(); } - _Initialized = false; } public void SetGlobalVolume(float volume) @@ -99,7 +113,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio int index = _GetStreamIndex(stream); if (index >= 0) { - _Streams[index].Free(); + _Streams[index].Close(); _Streams.RemoveAt(index); } } diff --git a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs index 6d372560..9701e59f 100644 --- a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs +++ b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPortAudioStream.cs @@ -68,12 +68,15 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio ~CPortAudioStream() { - Dispose(); + _Dispose(false); + if (_DecoderThread != null) + _DecoderThread.Join(); } - public void Free() + public void Close() { _Terminated = true; + _EventDecode.Set(); } public float Length @@ -512,11 +515,25 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio public void Dispose() { - if (_EventDecode != null) + _Dispose(true); + GC.SuppressFinalize(this); + } + + private void _Dispose(bool disposing) + { + Close(); + if (disposing) { - _EventDecode.Close(); - _EventDecode = null; - GC.SuppressFinalize(this); + if (_DecoderThread != null) + { + _DecoderThread.Join(); + _DecoderThread = null; + } + if (_EventDecode != null) + { + _EventDecode.Close(); + _EventDecode = null; + } } } } diff --git a/Vocaluxe/Program.cs b/Vocaluxe/Program.cs index 74464be9..5ee3826e 100644 --- a/Vocaluxe/Program.cs +++ b/Vocaluxe/Program.cs @@ -268,6 +268,7 @@ namespace Vocaluxe CDraw.Unload(); CDataBase.Close(); CWebcam.Close(); + GC.Collect(); // Do a GC run here before we close logs to have finalizers run CLog.CloseAll(); } catch (Exception) {}