PlaySound(0, 0, 0) doesn't stop previous PlaySound

PlaySound(0, 0, 0) doesn't stop previous PlaySound

Post by p_almon » Sat, 22 Nov 2003 00:32:19


I need to play a sound file, but stop it when a key is pressed. I
thought that doing
PlaySound(filename, NULL, SND_FILENAME);
in a thread, and doing a WaitForMultipleObjects on the thread and
stdin, and if stdin sends a keyboard event, terminating the earlier
PlaySound with
PlaySound(0, 0, 0);

But what actually happens when I press a key is that PlaySound(0, 0,
0) doesn't return until the sound has finished playing, not what I
wanted.

I also tried PlaySound(0, 0, SND_PURGE) but got the same result.

My waveout device is a generic soundcard. I'm running W2K, compiling
a console app with MSVC 6.0 (all service packs applied to both), added
winmm.lib to input libraries.

Here's all of my code:

#include "stdafx.h"
#include <conio.h>
#include <process.h>
#include <Mmsystem.h>

void Speak(const char* filename);

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) {
AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0);
Speak("menu.wav");
// this is the end of the test, but of course in my real app I want
to go
// on and do something else after aborting the PlaySound
return 0;
}

unsigned int __stdcall play_thread(void *n) {
char* filename = (char*) n;
PlaySound(filename, NULL, SND_FILENAME);
return 0;
}

void MyErrorExit(char* s) {
puts(s);
exit(1);
}

void Speak(const char* filename) {
// play file in a thread
unsigned int thread_id;
HANDLE thread = (HANDLE) _beginthreadex(NULL, 0, play_thread,
(void*) filename, 0, &thread_id);

HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
if (hStdin == INVALID_HANDLE_VALUE)
MyErrorExit("GetStdHandle");

HANDLE h[2];
h[0] = hStdin;
h[1] = thread;

for (;;) {
// wait for stdin event or play_thread to end
int i = WaitForMultipleObjects(2, h, FALSE, INFINITE);
if (i == WAIT_OBJECT_0) {
// a stdin event, make sure it is a keypress
DWORD cNumRead;
INPUT_RECORD in;
if ( !ReadConsoleInput(hStdin, &in, 1, &cNumRead))
MyErrorExit("ReadConsoleInput");

if (in.EventType == KEY_EVENT && in.Event.KeyEvent.bKeyDown) {
printf("key %x\n", in.Event.KeyEvent.uChar.AsciiChar);
// (try to) stop the PlaySound in the thread
i = PlaySound(0, 0, 0);
printf("PlaySound(0, 0, 0) returned %d\n", i);
}
} else if (i == WAIT_OBJECT_0 + 1) {
printf("play_thread exited\n");
break;
} else
printf("Wait returned %d\n", i);
}
}

Here is the output if I hit a key while the file is playing

[wave file starts playing]
[I hit space and the next line appears immediately]
key 20
[wave file goes on playing to the end and then the next two lines
appear immediately]
PlaySound(0, 0, 0) returned 1
play_thread exited
 
 
 

PlaySound(0, 0, 0) doesn't stop previous PlaySound

Post by Damian Dri » Sat, 22 Nov 2003 18:10:01


<(unread) code snipped>

PlaySound(0,0,0) will only stop the previous sound if it is running in the
same thread.

HTH
Damian

 
 
 

PlaySound(0, 0, 0) doesn't stop previous PlaySound

Post by p_almon » Fri, 05 Dec 2003 07:19:22


Thanks, that explains why my code didn't work.

Is there

a) a different way to stop a PlaySound in a different thread?

b) a way to get WaitForMultipleObjects to detect that PlaySound
finished? That way I could wait for keyboard input or an asynchronous
PlaySound finishing, whichever happens first.

c) any other way in a console app to play a sound, abort it when a key
is pressed, but stop waiting for input when the sound finishes?

thanks.
 
 
 

PlaySound(0, 0, 0) doesn't stop previous PlaySound

Post by Damian Dri » Fri, 05 Dec 2003 20:34:54


a) (just a suggestion, haven't tried it myself) try playing the sound
asynchronously in a separate thread and then hang around doing nothing
until an event is signalled, at which point do a PlaySound with SND_PURGE.
You might also try doing a PlaySound with SND_NOSTOP every once in a while
to check whether the current sound has finished or not, and if it has, let
the thread finish normally.

b) don't think so. I think you would have to play the sound the harder way
using the waveout* functions and handle the events yourself.

c) see b)

Damian
 
 
 

PlaySound(0, 0, 0) doesn't stop previous PlaySound

Post by alain_au_t » Sat, 06 Dec 2003 23:33:36

> a) (just a suggestion, haven't tried it myself) try playing the sound

I tried the solution mentionned above:

- PlaySound( a wav file , 0, SND_ASYNC | SND_FILENAME )
in a loop:
WaitForSingleObject( myEventToAbortSound, 500 msec timeout )
On timeout, check if sound is completed by calling
PlaySound( 0, 0, SND_NOSTOP ) : it (usually...) returns FALSE when
sound is playing, TRUE when completed.
end loop.

However, it does not seem to be 100% reliable: once in a while,
PlaySound( 0, 0, SND_NOSTOP ) returns TRUE on first loop iteration
(500 ms after PlaySound( a wav file , 0, SND_ASYNC ) ) ...

Anyone knows a bullet proof method to know when the audio file is done
playing ?