Rewrote lots of the DirectSound audio code, hopefully it's more stable now.
Originally committed to SVN as r1098.
This commit is contained in:
parent
877c4bf1b1
commit
813a487b23
3 changed files with 67 additions and 95 deletions
|
@ -98,9 +98,7 @@ void AudioPlayer::SetDisplayTimer(wxTimer *timer) {
|
||||||
void AudioPlayer::RequestStop() {
|
void AudioPlayer::RequestStop() {
|
||||||
wxCommandEvent event(wxEVT_STOP_AUDIO, 1000);
|
wxCommandEvent event(wxEVT_STOP_AUDIO, 1000);
|
||||||
event.SetEventObject(this);
|
event.SetEventObject(this);
|
||||||
wxMutexGuiEnter();
|
AddPendingEvent(event); // thread safe
|
||||||
AddPendingEvent(event);
|
|
||||||
wxMutexGuiLeave();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,6 @@ DirectSoundPlayer::DirectSoundPlayer() {
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
directSound = NULL;
|
directSound = NULL;
|
||||||
thread = NULL;
|
thread = NULL;
|
||||||
threadRunning = false;
|
|
||||||
notificationEvent = NULL;
|
notificationEvent = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,12 +81,12 @@ void DirectSoundPlayer::OpenStream() {
|
||||||
|
|
||||||
// Initialize the DirectSound object
|
// Initialize the DirectSound object
|
||||||
HRESULT res;
|
HRESULT res;
|
||||||
res = DirectSoundCreate8(NULL,&directSound,NULL);
|
res = DirectSoundCreate8(&DSDEVID_DefaultPlayback,&directSound,NULL); // TODO: support selecting audio device
|
||||||
if (res != DS_OK) throw _T("Failed initializing DirectSound");
|
if (res != DS_OK) throw _T("Failed initializing DirectSound");
|
||||||
|
|
||||||
// Set DirectSound parameters
|
// Set DirectSound parameters
|
||||||
AegisubApp *app = (AegisubApp*) wxTheApp;
|
AegisubApp *app = (AegisubApp*) wxTheApp;
|
||||||
directSound->SetCooperativeLevel((HWND)app->frame->GetHandle(),DSSCL_NORMAL);
|
directSound->SetCooperativeLevel((HWND)app->frame->GetHandle(),DSSCL_PRIORITY);
|
||||||
|
|
||||||
// Create the wave format structure
|
// Create the wave format structure
|
||||||
WAVEFORMATEX waveFormat;
|
WAVEFORMATEX waveFormat;
|
||||||
|
@ -132,19 +131,25 @@ void DirectSoundPlayer::CloseStream() {
|
||||||
// Stop it
|
// Stop it
|
||||||
Stop();
|
Stop();
|
||||||
|
|
||||||
// Delete the DirectSound buffer
|
// Unref the DirectSound buffer
|
||||||
// delete buffer;
|
if (buffer) {
|
||||||
|
buffer->Release();
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Delete the DirectSound object
|
// Unref the DirectSound object
|
||||||
// delete directSound;
|
if (directSound) {
|
||||||
|
directSound->Release();
|
||||||
directSound = NULL;
|
directSound = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////
|
///////////////
|
||||||
// Fill buffer
|
// Fill buffer
|
||||||
void DirectSoundPlayer::FillBuffer(bool fill) {
|
bool DirectSoundPlayer::FillBuffer() {
|
||||||
|
if (playPos >= endPos) return false;
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
void *ptr1, *ptr2;
|
void *ptr1, *ptr2;
|
||||||
unsigned long int size1, size2;
|
unsigned long int size1, size2;
|
||||||
|
@ -168,7 +173,7 @@ void DirectSoundPlayer::FillBuffer(bool fill) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error
|
// Error
|
||||||
if (!SUCCEEDED(res)) return;
|
if (FAILED(res)) return false;
|
||||||
|
|
||||||
// Set offset
|
// Set offset
|
||||||
offset = (offset + toWrite) % bufSize;
|
offset = (offset + toWrite) % bufSize;
|
||||||
|
@ -206,6 +211,8 @@ void DirectSoundPlayer::FillBuffer(bool fill) {
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
buffer->Unlock(ptr1,size1,ptr2,size2);
|
buffer->Unlock(ptr1,size1,ptr2,size2);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -214,24 +221,20 @@ void DirectSoundPlayer::FillBuffer(bool fill) {
|
||||||
void DirectSoundPlayer::Play(__int64 start,__int64 count) {
|
void DirectSoundPlayer::Play(__int64 start,__int64 count) {
|
||||||
// Make sure that it's stopped
|
// Make sure that it's stopped
|
||||||
Stop();
|
Stop();
|
||||||
|
// The thread is now guaranteed dead
|
||||||
|
|
||||||
// Lock
|
// We sure better have a buffer
|
||||||
wxMutexLocker locker(DSMutex);
|
assert(buffer);
|
||||||
|
|
||||||
// Check if buffer is loaded
|
// Create a new notification event
|
||||||
if (!buffer) return;
|
// It was already destroyed by Stop
|
||||||
buffer->Stop();
|
|
||||||
|
|
||||||
// Create notification event
|
|
||||||
if (notificationEvent)
|
|
||||||
CloseHandle(notificationEvent);
|
|
||||||
notificationEvent = CreateEvent(NULL,false,false,NULL);
|
notificationEvent = CreateEvent(NULL,false,false,NULL);
|
||||||
|
|
||||||
// Create notification interface
|
// Create notification interface
|
||||||
IDirectSoundNotify8 *notify;
|
IDirectSoundNotify8 *notify;
|
||||||
HRESULT res;
|
HRESULT res;
|
||||||
res = buffer->QueryInterface(IID_IDirectSoundNotify8,(LPVOID*)¬ify);
|
res = buffer->QueryInterface(IID_IDirectSoundNotify8,(LPVOID*)¬ify);
|
||||||
if (!SUCCEEDED(res)) return;
|
if (FAILED(res)) return;
|
||||||
|
|
||||||
// Set notification
|
// Set notification
|
||||||
DSBPOSITIONNOTIFY positionNotify[4];
|
DSBPOSITIONNOTIFY positionNotify[4];
|
||||||
|
@ -253,20 +256,18 @@ void DirectSoundPlayer::Play(__int64 start,__int64 count) {
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
// Fill buffer
|
// Fill buffer
|
||||||
FillBuffer(false);
|
FillBuffer();
|
||||||
|
|
||||||
|
// Start thread
|
||||||
|
thread = new DirectSoundPlayerThread(this);
|
||||||
|
thread->Create();
|
||||||
|
thread->Run();
|
||||||
|
|
||||||
// Play
|
// Play
|
||||||
buffer->SetCurrentPosition(0);
|
buffer->SetCurrentPosition(0);
|
||||||
res = buffer->Play(0,0,DSBPLAY_LOOPING);
|
res = buffer->Play(0,0,DSBPLAY_LOOPING);
|
||||||
if (SUCCEEDED(res)) playing = true;
|
if (SUCCEEDED(res)) playing = true;
|
||||||
|
|
||||||
// Start thread
|
|
||||||
if (!thread) {
|
|
||||||
thread = new DirectSoundPlayerThread(this);
|
|
||||||
thread->Create();
|
|
||||||
thread->Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update timer
|
// Update timer
|
||||||
if (displayTimer && !displayTimer->IsRunning()) displayTimer->Start(15);
|
if (displayTimer && !displayTimer->IsRunning()) displayTimer->Start(15);
|
||||||
}
|
}
|
||||||
|
@ -275,14 +276,13 @@ void DirectSoundPlayer::Play(__int64 start,__int64 count) {
|
||||||
////////
|
////////
|
||||||
// Stop
|
// Stop
|
||||||
void DirectSoundPlayer::Stop(bool timerToo) {
|
void DirectSoundPlayer::Stop(bool timerToo) {
|
||||||
// Lock
|
|
||||||
wxMutexLocker locker(DSMutex);
|
|
||||||
|
|
||||||
// Stop the thread
|
// Stop the thread
|
||||||
if (thread) {
|
if (thread) {
|
||||||
thread->alive = false;
|
thread->Stop();
|
||||||
|
thread->Wait();
|
||||||
thread = NULL;
|
thread = NULL;
|
||||||
}
|
}
|
||||||
|
// The thread is now guaranteed dead and there are no concurrency problems to worry about
|
||||||
|
|
||||||
// Stop
|
// Stop
|
||||||
if (buffer) buffer->Stop();
|
if (buffer) buffer->Stop();
|
||||||
|
@ -295,10 +295,8 @@ void DirectSoundPlayer::Stop(bool timerToo) {
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
// Close event handle
|
// Close event handle
|
||||||
if (notificationEvent) {
|
|
||||||
CloseHandle(notificationEvent);
|
CloseHandle(notificationEvent);
|
||||||
notificationEvent = 0;
|
notificationEvent = 0;
|
||||||
}
|
|
||||||
|
|
||||||
// Stop timer
|
// Stop timer
|
||||||
if (timerToo && displayTimer) {
|
if (timerToo && displayTimer) {
|
||||||
|
@ -346,72 +344,50 @@ __int64 DirectSoundPlayer::GetCurrentPosition() {
|
||||||
// Thread constructor
|
// Thread constructor
|
||||||
DirectSoundPlayerThread::DirectSoundPlayerThread(DirectSoundPlayer *par) : wxThread(wxTHREAD_JOINABLE) {
|
DirectSoundPlayerThread::DirectSoundPlayerThread(DirectSoundPlayer *par) : wxThread(wxTHREAD_JOINABLE) {
|
||||||
parent = par;
|
parent = par;
|
||||||
alive = true;
|
stopnotify = CreateSemaphore(NULL, 0, 1, NULL);
|
||||||
parent->threadRunning = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// Thread destructor
|
// Thread destructor
|
||||||
DirectSoundPlayerThread::~DirectSoundPlayerThread() {
|
DirectSoundPlayerThread::~DirectSoundPlayerThread() {
|
||||||
|
CloseHandle(stopnotify);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
// Thread entry point
|
// Thread entry point
|
||||||
wxThread::ExitCode DirectSoundPlayerThread::Entry() {
|
wxThread::ExitCode DirectSoundPlayerThread::Entry() {
|
||||||
// Variables
|
// Objects to wait for
|
||||||
unsigned long int playPos=0,endPos=0,bufSize=0;
|
HANDLE notifies[2] = {stopnotify, parent->notificationEvent};
|
||||||
bool playing;
|
|
||||||
|
|
||||||
// Wait for notification
|
while (true) {
|
||||||
while (alive) {
|
// Wait for something to happen
|
||||||
// Get variables
|
DWORD cause = WaitForMultipleObjects(2, notifies, false, INFINITE);
|
||||||
bool booga = true;
|
|
||||||
if (booga) {
|
|
||||||
if (!alive) break;
|
|
||||||
wxMutexLocker locker(parent->DSMutex);
|
|
||||||
if (!alive) break;
|
|
||||||
playPos = parent->GetCurrentPosition();
|
|
||||||
endPos = parent->endPos;
|
|
||||||
bufSize = parent->bufSize;
|
|
||||||
playing = parent->playing;
|
|
||||||
if (!alive) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flag as stopped playing, but don't actually stop yet
|
if (cause == WAIT_OBJECT_0) {
|
||||||
if (playPos > endPos) {
|
// stopnotify
|
||||||
if (!alive) break;
|
|
||||||
wxMutexLocker locker(parent->DSMutex);
|
|
||||||
if (!alive) break;
|
|
||||||
parent->playing = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Still playing?
|
|
||||||
if (playPos < endPos + bufSize/8) {
|
|
||||||
// Wait for signal
|
|
||||||
if (!alive) break;
|
|
||||||
WaitForSingleObject(parent->notificationEvent,1000);
|
|
||||||
if (!alive) break;
|
|
||||||
|
|
||||||
// Fill buffer
|
|
||||||
wxMutexLocker locker(parent->DSMutex);
|
|
||||||
if (!alive) break;
|
|
||||||
parent->FillBuffer(false);
|
|
||||||
if (!alive) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Over, stop it
|
|
||||||
else {
|
|
||||||
if (alive) parent->Stop();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if (cause == WAIT_OBJECT_0 + 1) {
|
||||||
|
// dsound notification event
|
||||||
|
// fill the buffer
|
||||||
|
if (!parent->FillBuffer())
|
||||||
|
break; // end of stream
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//wxMutexLocker locker(parent->DSMutex);
|
parent->playing = false;
|
||||||
parent->threadRunning = false;
|
parent->buffer->Stop();
|
||||||
Delete();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////
|
||||||
|
// Stop playback thread
|
||||||
|
void DirectSoundPlayerThread::Stop() {
|
||||||
|
// Increase the stopnotify by one, causing a wait for it to succeed
|
||||||
|
ReleaseSemaphore(stopnotify, 1, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -56,9 +56,10 @@ class DirectSoundPlayer;
|
||||||
class DirectSoundPlayerThread : public wxThread {
|
class DirectSoundPlayerThread : public wxThread {
|
||||||
private:
|
private:
|
||||||
DirectSoundPlayer *parent;
|
DirectSoundPlayer *parent;
|
||||||
|
HANDLE stopnotify;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool alive;
|
void Stop(); // Notify thread to stop audio playback. Thread safe.
|
||||||
DirectSoundPlayerThread(DirectSoundPlayer *parent);
|
DirectSoundPlayerThread(DirectSoundPlayer *parent);
|
||||||
~DirectSoundPlayerThread();
|
~DirectSoundPlayerThread();
|
||||||
|
|
||||||
|
@ -72,9 +73,7 @@ class DirectSoundPlayer : public AudioPlayer {
|
||||||
friend class DirectSoundPlayerThread;
|
friend class DirectSoundPlayerThread;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wxMutex DSMutex;
|
volatile bool playing;
|
||||||
|
|
||||||
bool playing;
|
|
||||||
float volume;
|
float volume;
|
||||||
int offset;
|
int offset;
|
||||||
int bufSize;
|
int bufSize;
|
||||||
|
@ -87,10 +86,9 @@ private:
|
||||||
IDirectSoundBuffer8 *buffer;
|
IDirectSoundBuffer8 *buffer;
|
||||||
HANDLE notificationEvent;
|
HANDLE notificationEvent;
|
||||||
|
|
||||||
void FillBuffer(bool fill);
|
bool FillBuffer();
|
||||||
|
|
||||||
DirectSoundPlayerThread *thread;
|
DirectSoundPlayerThread *thread;
|
||||||
bool threadRunning;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DirectSoundPlayer();
|
DirectSoundPlayer();
|
||||||
|
@ -112,7 +110,7 @@ public:
|
||||||
void SetVolume(double vol) { volume = vol; }
|
void SetVolume(double vol) { volume = vol; }
|
||||||
double GetVolume() { return volume; }
|
double GetVolume() { return volume; }
|
||||||
|
|
||||||
wxMutex *GetMutex() { return &DSMutex; }
|
//wxMutex *GetMutex() { return &DSMutex; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue