forked from mia/Aegisub
Fix race conditions in the dsound2 player that occasionally resulted in audio playback stopping instantly
Originally committed to SVN as r5856.
This commit is contained in:
parent
b16f1a0698
commit
672f420d6c
1 changed files with 45 additions and 45 deletions
|
@ -46,8 +46,8 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "audio_player_dsound2.h"
|
#include "audio_player_dsound2.h"
|
||||||
|
|
||||||
#include "include/aegisub/audio_provider.h"
|
#include "include/aegisub/audio_provider.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -279,7 +279,13 @@ unsigned int __stdcall DirectSoundPlayer2Thread::ThreadProc(void *parameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Macro used to set error_message, error_happened and end the thread
|
/// Macro used to set error_message, error_happened and end the thread
|
||||||
#define REPORT_ERROR(msg) { error_message = "DirectSoundPlayer2Thread: " msg; SetEvent(error_happened); return; }
|
#define REPORT_ERROR(msg) \
|
||||||
|
{ \
|
||||||
|
ResetEvent(is_playing); \
|
||||||
|
error_message = "DirectSoundPlayer2Thread: " msg; \
|
||||||
|
SetEvent(error_happened); \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
|
||||||
void DirectSoundPlayer2Thread::Run()
|
void DirectSoundPlayer2Thread::Run()
|
||||||
{
|
{
|
||||||
|
@ -364,7 +370,6 @@ void DirectSoundPlayer2Thread::Run()
|
||||||
{
|
{
|
||||||
// Start or restart playback
|
// Start or restart playback
|
||||||
bfr->Stop();
|
bfr->Stop();
|
||||||
ResetEvent(is_playing);
|
|
||||||
|
|
||||||
next_input_frame = start_frame;
|
next_input_frame = start_frame;
|
||||||
|
|
||||||
|
@ -425,57 +430,41 @@ void DirectSoundPlayer2Thread::Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
case WAIT_OBJECT_0+1:
|
case WAIT_OBJECT_0+1:
|
||||||
{
|
stop_playback:
|
||||||
// Stop playing
|
// Stop playing
|
||||||
bfr->Stop();
|
bfr->Stop();
|
||||||
ResetEvent(is_playing);
|
ResetEvent(is_playing);
|
||||||
playback_should_be_running = false;
|
playback_should_be_running = false;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case WAIT_OBJECT_0+2:
|
case WAIT_OBJECT_0+2:
|
||||||
|
// Set end frame
|
||||||
|
if (end_frame <= next_input_frame)
|
||||||
{
|
{
|
||||||
// Set end frame
|
goto stop_playback;
|
||||||
if (end_frame <= next_input_frame)
|
|
||||||
{
|
|
||||||
bfr->Stop();
|
|
||||||
ResetEvent(is_playing);
|
|
||||||
playback_should_be_running = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If the user is dragging the start or end point in the audio display
|
|
||||||
// the set end frame events might come in faster than the timeouts happen
|
|
||||||
// and then new data never get filled into the buffer. See bug #915.
|
|
||||||
goto do_fill_buffer;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the user is dragging the start or end point in the audio display
|
||||||
|
// the set end frame events might come in faster than the timeouts happen
|
||||||
|
// and then new data never get filled into the buffer. See bug #915.
|
||||||
|
goto do_fill_buffer;
|
||||||
|
|
||||||
case WAIT_OBJECT_0+3:
|
case WAIT_OBJECT_0+3:
|
||||||
{
|
// Change volume
|
||||||
// Change volume
|
// We aren't thread safe right now, filling the buffers grabs volume directly
|
||||||
// We aren't thread safe right now, filling the buffers grabs volume directly
|
// from the field set by the controlling thread, but it shouldn't be a major
|
||||||
// from the field set by the controlling thread, but it shouldn't be a major
|
// problem if race conditions do occur, just some momentary distortion.
|
||||||
// problem if race conditions do occur, just some momentary distortion.
|
goto do_fill_buffer;
|
||||||
goto do_fill_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WAIT_OBJECT_0+4:
|
case WAIT_OBJECT_0+4:
|
||||||
{
|
// Perform suicide
|
||||||
// Perform suicide
|
running = false;
|
||||||
bfr->Stop();
|
goto stop_playback;
|
||||||
ResetEvent(is_playing);
|
|
||||||
playback_should_be_running = false;
|
|
||||||
running = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WAIT_TIMEOUT:
|
case WAIT_TIMEOUT:
|
||||||
do_fill_buffer:
|
do_fill_buffer:
|
||||||
{
|
{
|
||||||
// Time to fill more into buffer
|
// Time to fill more into buffer
|
||||||
|
|
||||||
if (!playback_should_be_running)
|
if (!playback_should_be_running)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -487,10 +476,7 @@ do_fill_buffer:
|
||||||
{
|
{
|
||||||
// Not looping playback...
|
// Not looping playback...
|
||||||
// hopefully we only triggered timeout after being done with the buffer
|
// hopefully we only triggered timeout after being done with the buffer
|
||||||
bfr->Stop();
|
goto stop_playback;
|
||||||
ResetEvent(is_playing);
|
|
||||||
playback_should_be_running = false;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD play_cursor;
|
DWORD play_cursor;
|
||||||
|
@ -716,6 +702,20 @@ void DirectSoundPlayer2Thread::Play(int64_t start, int64_t count)
|
||||||
SetEvent(event_start_playback);
|
SetEvent(event_start_playback);
|
||||||
|
|
||||||
last_playback_restart = GetTickCount();
|
last_playback_restart = GetTickCount();
|
||||||
|
|
||||||
|
// Block until playback actually begins to avoid race conditions with
|
||||||
|
// checking if playback is in progress
|
||||||
|
HANDLE events_to_wait[] = { is_playing, error_happened };
|
||||||
|
switch (WaitForMultipleObjects(2, events_to_wait, FALSE, INFINITE))
|
||||||
|
{
|
||||||
|
case WAIT_OBJECT_0+0: // Playing
|
||||||
|
LOG_D("audio/player/dsound") << "Playback begun";
|
||||||
|
break;
|
||||||
|
case WAIT_OBJECT_0+1: // Error
|
||||||
|
throw error_message;
|
||||||
|
default:
|
||||||
|
throw "Unexpected result from WaitForMultipleObjects in DirectSoundPlayer2Thread::Play";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectSoundPlayer2Thread::Stop()
|
void DirectSoundPlayer2Thread::Stop()
|
||||||
|
|
Loading…
Reference in a new issue