diff --git a/GpApp/Music.cpp b/GpApp/Music.cpp index e9be75c..0b167ea 100644 --- a/GpApp/Music.cpp +++ b/GpApp/Music.cpp @@ -354,9 +354,9 @@ void KillMusic (void) if (dontLoadMusic) return; - - theErr = DumpMusicSounds(); + theErr = CloseMusicChannel(); + theErr = DumpMusicSounds(); musicMutex->Destroy(); } diff --git a/GpApp/Sound.cpp b/GpApp/Sound.cpp index e231983..c921d35 100644 --- a/GpApp/Sound.cpp +++ b/GpApp/Sound.cpp @@ -361,8 +361,8 @@ void KillSound (void) if (dontLoadSounds) return; - DumpBufferSounds(); CloseSoundChannels(); + DumpBufferSounds(); } //-------------------------------------------------------------- SoundBytesNeeded diff --git a/PortabilityLayer/PLSound.cpp b/PortabilityLayer/PLSound.cpp index 2da4fdc..64c40f9 100644 --- a/PortabilityLayer/PLSound.cpp +++ b/PortabilityLayer/PLSound.cpp @@ -55,11 +55,14 @@ namespace PortabilityLayer enum WorkingState { + // NOTE: In all cases where the thread event is fired, the event may be fired under a mutex lock. + // Therefore, if the mutex is to be destroyed, it must be locked first even though the thread has transitioned to idle. + State_Idle, // No thread is playing sound, the sound thread is out of work State_PlayingAsync, // Sound thread is playing sound. When it finishes, it will digest queue events under a lock. State_PlayingBlocked, // Sound thread is playing sound. When it finishes, it will transition to Idle and fire the thread event. State_FlushStarting, // Sound thread is aborting. When it aborts, it will transition to Idle and fire the thread event. - State_ShuttingDown, // Sound thread is shutting down. When it finishes, it will transition to idle and fire the thread event. + State_ShuttingDown, // Sound thread is shutting down. When it finishes, it will transition to Idle and fire the thread event. }; static const unsigned int kMaxQueuedCommands = 64; @@ -97,6 +100,7 @@ namespace PortabilityLayer { m_mutex->Destroy(); m_threadEvent->Destroy(); + m_audioChannel->Destroy(); } void AudioChannelImpl::NotifyBufferFinished() @@ -121,8 +125,13 @@ namespace PortabilityLayer { ClearAllCommands(); + bool synchronizeMutex = false; + if (!wait) + { Stop(); + synchronizeMutex = true; + } else { m_mutex->Lock(); @@ -133,6 +142,8 @@ namespace PortabilityLayer m_mutex->Unlock(); m_threadEvent->Wait(); + + synchronizeMutex = true; } else { @@ -141,6 +152,15 @@ namespace PortabilityLayer } } + if (synchronizeMutex) + { + // If we had to stop the audio thread, then the event was fired under a lock. + // We have to wait for the unlock to complete before destroying the mutex. + m_mutex->Lock(); + assert(m_state == State_Idle); + m_mutex->Unlock(); + } + this->~AudioChannelImpl(); PortabilityLayer::MemoryManager::GetInstance()->Release(this); }