From 5330c541ca7e6c158b96267dd7a7ba1e99a76268 Mon Sep 17 00:00:00 2001 From: Niels Martin Hansen Date: Sat, 21 Jun 2008 21:13:00 +0000 Subject: [PATCH] Possible fix for #719 Originally committed to SVN as r2210. --- aegisub/audio_player_dsound.cpp | 45 +++++++++++++++++++++------------ aegisub/audio_player_dsound.h | 3 +-- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/aegisub/audio_player_dsound.cpp b/aegisub/audio_player_dsound.cpp index 21fe1647a..96f658631 100644 --- a/aegisub/audio_player_dsound.cpp +++ b/aegisub/audio_player_dsound.cpp @@ -48,7 +48,6 @@ /////////////// // Constructor DirectSoundPlayer::DirectSoundPlayer() { - playing = false; volume = 1.0f; playPos = 0; startPos = 0; @@ -261,7 +260,6 @@ void DirectSoundPlayer::Play(int64_t start,int64_t count) { // Play buffer->SetCurrentPosition(0); res = buffer->Play(0,0,play_flag); - if (SUCCEEDED(res)) playing = true; startTime = GetTickCount(); // Update timer @@ -276,18 +274,15 @@ void DirectSoundPlayer::Stop(bool timerToo) { if (thread) { if (thread->IsAlive()) { thread->Stop(); - // The thread is detached so it kills/deletes itself after being stopped - //thread->Wait(); } thread = NULL; } - // The thread is now guaranteed dead and there are no concurrency problems to worry about + // The thread should now stop filling the buffer soon enough that we can safely stop the buffer + // and possibly start having soomething else filling it soon. - // Stop - if (buffer) buffer->Stop(); // the thread should have done this already + if (buffer) buffer->Stop(); // Reset variables - playing = false; playPos = 0; startPos = 0; endPos = 0; @@ -303,7 +298,7 @@ void DirectSoundPlayer::Stop(bool timerToo) { /////////// // Set end void DirectSoundPlayer::SetEndPosition(int64_t pos) { - if (playing) endPos = pos; + if (IsPlaying()) endPos = pos; } @@ -318,8 +313,8 @@ void DirectSoundPlayer::SetCurrentPosition(int64_t pos) { //////////////////////// // Get current position int64_t DirectSoundPlayer::GetCurrentPosition() { - // Check if buffer is loaded - if (!buffer || !playing) return 0; + // Assume position 0 if we aren't playing currently + if (!IsPlaying()) return 0; // FIXME: this should be based on not duration played but actual sample being heard // (during vidoeo playback, cur_frame might get changed to resync) @@ -329,6 +324,20 @@ int64_t DirectSoundPlayer::GetCurrentPosition() { } +/////////////////////////////////////// +// Check whether the buffer is playing +bool DirectSoundPlayer::IsPlaying() { + if (!buffer) return false; + + DWORD status = 0; + if (SUCCEEDED(buffer->GetStatus(&status))) { + return !!(status & DSBSTATUS_PLAYING); + } else { + return false; + } +} + + ////////////////////// // Thread constructor DirectSoundPlayerThread::DirectSoundPlayerThread(DirectSoundPlayer *par) : wxThread(wxTHREAD_DETACHED) { @@ -350,6 +359,10 @@ wxThread::ExitCode DirectSoundPlayerThread::Entry() { // Every thread that uses COM must initialise it CoInitialize(0); + // Make sure we have the buffer available as long as we're alive + parent->buffer->AddRef(); + IDirectSoundBuffer8 *buffer = parent->buffer; + // Wake up thread every half second to fill buffer as needed // This more or less assumes the buffer is at least one second long while (WaitForSingleObject(stopnotify, 50) == WAIT_TIMEOUT) { @@ -367,18 +380,18 @@ wxThread::ExitCode DirectSoundPlayerThread::Entry() { DWORD size1, size2; DWORD playpos; HRESULT res; - res = parent->buffer->GetCurrentPosition(&playpos, NULL); + res = buffer->GetCurrentPosition(&playpos, NULL); if (FAILED(res)) break; int toWrite = playpos - parent->offset; while (toWrite < 0) toWrite += parent->bufSize; - res = parent->buffer->Lock(parent->offset, toWrite, &buf1, &size1, &buf2, &size2, 0); + res = buffer->Lock(parent->offset, toWrite, &buf1, &size1, &buf2, &size2, 0); if (FAILED(res)) break; if (size1) memset(buf1, 0, size1); if (size2) memset(buf2, 0, size2); if (size1) wxLogDebug(_T("DS blnk: %05ld -> %05ld"), (unsigned long)parent->playPos+bytesFilled, (unsigned long)parent->playPos+bytesFilled+size1); if (size2) wxLogDebug(_T("DS blnk: %05ld => %05ld"), (unsigned long)parent->playPos+bytesFilled+size1, (unsigned long)parent->playPos+bytesFilled+size1+size2); bytesFilled += size1 + size2; - parent->buffer->Unlock(buf1, size1, buf2, size2); + buffer->Unlock(buf1, size1, buf2, size2); if (bytesFilled > parent->bufSize) break; parent->offset = (parent->offset + size1 + size2) % parent->bufSize; } @@ -387,8 +400,8 @@ wxThread::ExitCode DirectSoundPlayerThread::Entry() { wxLogDebug(_T("DS thread dead")); - parent->playing = false; - parent->buffer->Stop(); + // Our owner is responsible for stopping the buffer + buffer->Release(); // And un-init COM since we inited it CoUninitialize(); diff --git a/aegisub/audio_player_dsound.h b/aegisub/audio_player_dsound.h index 9b96bcb88..1af89c735 100644 --- a/aegisub/audio_player_dsound.h +++ b/aegisub/audio_player_dsound.h @@ -90,7 +90,6 @@ class DirectSoundPlayer : public AudioPlayer { friend class DirectSoundPlayerThread; private: - volatile bool playing; float volume; int offset; DWORD bufSize; @@ -116,7 +115,7 @@ public: void Play(int64_t start,int64_t count); void Stop(bool timerToo=true); - bool IsPlaying() { return playing; } + bool IsPlaying(); int64_t GetStartPosition() { return startPos; } int64_t GetEndPosition() { return endPos; }