Better behavior of PlaySound (error handling, synchronization).

Removed some unnecessary tests about windows handles.
This commit is contained in:
Eric Pouech 2002-05-12 03:10:26 +00:00 committed by Alexandre Julliard
parent 67371bcc8d
commit b93f1114de
2 changed files with 195 additions and 207 deletions

View File

@ -218,50 +218,39 @@ void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16)
memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u));
}
static HANDLE PlaySound_hThread = 0;
static HANDLE PlaySound_hPlayEvent = 0;
static HANDLE PlaySound_hReadyEvent = 0;
static HANDLE PlaySound_hMiddleEvent = 0;
static BOOL PlaySound_Result = FALSE;
static int PlaySound_Stop = FALSE;
static int PlaySound_Playing = FALSE;
static LPCSTR PlaySound_pszSound = NULL;
static HMODULE PlaySound_hmod = 0;
static DWORD PlaySound_fdwSound = 0;
static int PlaySound_Loop = FALSE;
static int PlaySound_SearchMode = 0; /* 1 - sndPlaySound search order
2 - PlaySound order */
static HMMIO get_mmioFromFile(LPCSTR lpszName)
static HMMIO get_mmioFromFile(LPCWSTR lpszName)
{
return mmioOpenA((LPSTR)lpszName, NULL,
return mmioOpenW((LPWSTR)lpszName, NULL,
MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
}
static HMMIO get_mmioFromProfile(UINT uFlags, LPCSTR lpszName)
static HMMIO get_mmioFromProfile(UINT uFlags, LPCWSTR lpszName)
{
char str[128];
LPSTR ptr;
WCHAR str[128];
LPWSTR ptr;
HMMIO hmmio;
static WCHAR wszSounds[] = {'S','o','u','n','d','s',0};
static WCHAR wszDefault[] = {'D','e','f','a','u','l','t',0};
static WCHAR wszNull[] = {0};
TRACE("searching in SystemSound List !\n");
GetProfileStringA("Sounds", (LPSTR)lpszName, "", str, sizeof(str));
if (strlen(str) == 0) {
GetProfileStringW(wszSounds, (LPWSTR)lpszName, wszNull, str, sizeof(str)/sizeof(str[0]));
if (lstrlenW(str) == 0) {
if (uFlags & SND_NODEFAULT) return 0;
GetProfileStringA("Sounds", "Default", "", str, sizeof(str));
if (strlen(str) == 0) return 0;
GetProfileStringW(wszSounds, wszDefault, wszNull, str, sizeof(str)/sizeof(str[0]));
if (lstrlenW(str) == 0) return 0;
}
if ((ptr = (LPSTR)strchr(str, ',')) != NULL) *ptr = '\0';
hmmio = get_mmioFromFile(str);
for (ptr = str; *ptr && *ptr != ','; ptr++);
if (*ptr) *ptr = 0;
hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
if (hmmio == 0) {
WARN("can't find SystemSound='%s' !\n", str);
WARN("can't find SystemSound='%s' !\n", debugstr_w(str));
return 0;
}
return hmmio;
}
struct playsound_data {
struct playsound_data
{
HANDLE hEvent;
DWORD dwEventCount;
};
@ -290,17 +279,17 @@ static void PlaySound_WaitDone(struct playsound_data* s)
{
for (;;) {
ResetEvent(s->hEvent);
if (InterlockedDecrement(&s->dwEventCount) >= 0) {
break;
}
if (InterlockedDecrement(&s->dwEventCount) >= 0) break;
InterlockedIncrement(&s->dwEventCount);
WaitForSingleObject(s->hEvent, INFINITE);
}
}
static BOOL WINAPI proc_PlaySound(LPCSTR lpszSoundName, UINT uFlags)
static DWORD WINAPI proc_PlaySound(LPVOID arg)
{
WINE_PLAYSOUND* wps = (WINE_PLAYSOUND*)arg;
LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
BOOL bRet = FALSE;
HMMIO hmmio = 0;
MMCKINFO ckMainRIFF;
@ -310,42 +299,59 @@ static BOOL WINAPI proc_PlaySound(LPCSTR lpszSoundName, UINT uFlags)
LPWAVEHDR waveHdr = NULL;
INT count, bufsize, left, index;
struct playsound_data s;
void* data;
s.hEvent = 0;
TRACE("SoundName='%s' uFlags=%04X !\n", lpszSoundName, uFlags);
if (lpszSoundName == NULL) {
TRACE("Stop !\n");
TRACE("SoundName='%s' !\n", debugstr_w(wps->pszSound));
/* if resource, grab it */
if ((wps->fdwSound & SND_RESOURCE) == SND_RESOURCE) {
static WCHAR wszWave[] = {'W','A','V','E',0};
HRSRC hRes;
HGLOBAL hGlob;
if ((hRes = FindResourceW(wps->hMod, wps->pszSound, wszWave)) == 0 ||
(hGlob = LoadResource(wps->hMod, hRes)) == 0) {
return FALSE;
}
if (uFlags & SND_MEMORY) {
if ((data = LockResource(hGlob)) == NULL) {
FreeResource(hGlob);
return FALSE;
}
FreeResource(hGlob);
} else
data = (void*)wps->pszSound;
/* construct an MMIO stream (either in memory, or from a file */
if (wps->fdwSound & SND_MEMORY) { /* NOTE: SND_RESOURCE has the SND_MEMORY bit set */
MMIOINFO mminfo;
memset(&mminfo, 0, sizeof(mminfo));
mminfo.fccIOProc = FOURCC_MEM;
mminfo.pchBuffer = (LPSTR)lpszSoundName;
mminfo.cchBuffer = -1;
TRACE("Memory sound %p\n", lpszSoundName);
hmmio = mmioOpenA(NULL, &mminfo, MMIO_READ);
mminfo.pchBuffer = (LPSTR)data;
mminfo.cchBuffer = -1; /* FIXME: when a resource, could grab real size */
TRACE("Memory sound %p\n", data);
hmmio = mmioOpenW(NULL, &mminfo, MMIO_READ);
} else {
hmmio = 0;
if (uFlags & SND_ALIAS)
if ((hmmio = get_mmioFromProfile(uFlags, lpszSoundName)) == 0)
if (wps->fdwSound & SND_ALIAS)
if ((hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound)) == 0)
return FALSE;
if (uFlags & SND_FILENAME)
if ((hmmio=get_mmioFromFile(lpszSoundName)) == 0) return FALSE;
if (wps->fdwSound & SND_FILENAME)
if ((hmmio = get_mmioFromFile(wps->pszSound)) == 0) return FALSE;
if (PlaySound_SearchMode == 1) {
PlaySound_SearchMode = 0;
if ((hmmio = get_mmioFromFile(lpszSoundName)) == 0)
hmmio = get_mmioFromProfile(uFlags, lpszSoundName);
}
if (PlaySound_SearchMode == 2) {
PlaySound_SearchMode = 0;
if ((hmmio = get_mmioFromProfile(uFlags | SND_NODEFAULT, lpszSoundName)) == 0)
if ((hmmio = get_mmioFromFile(lpszSoundName)) == 0)
hmmio = get_mmioFromProfile(uFlags, lpszSoundName);
switch (wps->searchMode) {
case 1:
if ((hmmio = get_mmioFromFile(wps->pszSound)) == 0)
hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound);
break;
case 2:
if ((hmmio = get_mmioFromProfile(wps->fdwSound | SND_NODEFAULT, wps->pszSound)) == 0)
if ((hmmio = get_mmioFromFile(wps->pszSound)) == 0)
hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound);
break;
}
}
if (hmmio == 0) return FALSE;
@ -416,8 +422,8 @@ static BOOL WINAPI proc_PlaySound(LPCSTR lpszSoundName, UINT uFlags)
mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET);
while (left) {
if (PlaySound_Stop) {
PlaySound_Stop = PlaySound_Loop = FALSE;
if (wps->bStop) {
wps->bStop = wps->bLoop = FALSE;
break;
}
count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left));
@ -425,14 +431,16 @@ static BOOL WINAPI proc_PlaySound(LPCSTR lpszSoundName, UINT uFlags)
left -= count;
waveHdr[index].dwBufferLength = count;
waveHdr[index].dwFlags &= ~WHDR_DONE;
waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR));
if (waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR)) == MMSYSERR_NOERROR) {
index ^= 1;
PlaySound_WaitDone(&s);
}
else FIXME("Couldn't play header\n");
}
bRet = TRUE;
} while (PlaySound_Loop);
} while (wps->bLoop);
PlaySound_WaitDone(&s);
PlaySound_WaitDone(&s); /* for last buffer */
waveOutReset(hWave);
waveOutUnprepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR));
@ -445,123 +453,105 @@ errCleanUp:
if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100);
if (hmmio) mmioClose(hmmio, 0);
SetEvent(wps->hReadyEvent);
iData->lpPlaySound = NULL;
/* when filename: HeapFree(GetProcessHeap(), 0, wps->pszSound); */
CloseHandle(wps->hReadyEvent);
HeapFree(GetProcessHeap(), 0, wps);
return bRet;
}
static DWORD WINAPI PlaySound_Thread(LPVOID arg)
static BOOL MULTIMEDIA_PlaySound(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound, DWORD search)
{
DWORD res;
for (;;) {
PlaySound_Playing = FALSE;
SetEvent(PlaySound_hReadyEvent);
res = WaitForSingleObject(PlaySound_hPlayEvent, INFINITE);
ResetEvent(PlaySound_hReadyEvent);
SetEvent(PlaySound_hMiddleEvent);
if (res == WAIT_FAILED) ExitThread(2);
if (res != WAIT_OBJECT_0) continue;
PlaySound_Playing = TRUE;
if ((PlaySound_fdwSound & SND_RESOURCE) == SND_RESOURCE) {
HRSRC hRES;
HGLOBAL hGLOB;
void* ptr;
if ((hRES = FindResourceA(PlaySound_hmod, PlaySound_pszSound, "WAVE")) == 0) {
PlaySound_Result = FALSE;
continue;
}
if ((hGLOB = LoadResource(PlaySound_hmod, hRES)) == 0) {
PlaySound_Result = FALSE;
continue;
}
if ((ptr = LockResource(hGLOB)) == NULL) {
FreeResource(hGLOB);
PlaySound_Result = FALSE;
continue;
}
PlaySound_Result = proc_PlaySound(ptr,
((UINT16)PlaySound_fdwSound ^ SND_RESOURCE) | SND_MEMORY);
FreeResource(hGLOB);
continue;
}
PlaySound_Result = proc_PlaySound(PlaySound_pszSound, (UINT16)PlaySound_fdwSound);
}
}
/**************************************************************************
* @ [WINMM.1]
* PlaySound [WINMM.@]
* PlaySoundA [WINMM.@]
*/
BOOL WINAPI PlaySoundA(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound)
{
static LPSTR StrDup = NULL;
WINE_PLAYSOUND* wps = NULL;
DWORD id;
LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
BOOL bRet = FALSE;
TRACE("pszSound='%p' hmod=%04X fdwSound=%08lX\n",
pszSound, hmod, fdwSound);
if (PlaySound_hThread == 0) { /* This is the first time they called us */
DWORD id;
if ((PlaySound_hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0)
/* FIXME? I see no difference between SND_NOWAIT and SND_NOSTOP !
* there could be one if several sounds can be played at once...
*/
if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && iData->lpPlaySound)
return FALSE;
if ((PlaySound_hMiddleEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
return FALSE;
if ((PlaySound_hPlayEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == 0)
return FALSE;
if ((PlaySound_hThread = CreateThread(NULL, 0, PlaySound_Thread, 0, 0, &id)) == 0)
return FALSE;
}
/* FIXME? I see no difference between SND_WAIT and SND_NOSTOP ! */
if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && PlaySound_Playing)
return FALSE;
do {
HANDLE hEvt = 0;
/* Trying to stop if playing */
if (PlaySound_Playing) PlaySound_Stop = TRUE;
EnterCriticalSection(&iData->cs);
if (iData->lpPlaySound) {
LPWINE_PLAYSOUND ps2stop = iData->lpPlaySound;
/* Waiting playing thread to get ready. I think 10 secs is ok & if not then leave*/
if (WaitForSingleObject(PlaySound_hReadyEvent, 1000*10) != WAIT_OBJECT_0)
return FALSE;
hEvt = ps2stop->hReadyEvent;
ps2stop->bStop = TRUE;
}
LeaveCriticalSection(&iData->cs);
/* Waiting playing thread to get ready. I think 10 secs is ok & if not then leave
* FIXME: race here (if hEvt is destroyed and reallocated - as a handle - to
* another object)... unlikely but possible
*/
if (hEvt) WaitForSingleObject(hEvt, 1000*10);
if (!pszSound || (fdwSound & SND_PURGE))
return TRUE; /* We stopped playing so leaving */
if (PlaySound_SearchMode != 1) PlaySound_SearchMode = 2;
if (!(fdwSound & SND_ASYNC)) {
if (fdwSound & SND_LOOP)
return FALSE;
PlaySound_pszSound = pszSound;
PlaySound_hmod = hmod;
PlaySound_fdwSound = fdwSound;
PlaySound_Result = FALSE;
SetEvent(PlaySound_hPlayEvent);
if (WaitForSingleObject(PlaySound_hMiddleEvent, INFINITE) != WAIT_OBJECT_0)
return FALSE;
if (WaitForSingleObject(PlaySound_hReadyEvent, INFINITE) != WAIT_OBJECT_0)
return FALSE;
return PlaySound_Result;
} else {
PlaySound_hmod = hmod;
PlaySound_fdwSound = fdwSound;
PlaySound_Result = FALSE;
if (StrDup) {
HeapFree(GetProcessHeap(), 0, StrDup);
StrDup = NULL;
}
if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
!((DWORD)pszSound >> 16)) || !pszSound))
if (wps == NULL)
{
StrDup = HeapAlloc(GetProcessHeap(), 0, strlen(pszSound)+1 );
strcpy( StrDup, pszSound );
PlaySound_pszSound = StrDup;
} else PlaySound_pszSound = pszSound;
PlaySound_Loop = fdwSound & SND_LOOP;
SetEvent(PlaySound_hPlayEvent);
ResetEvent(PlaySound_hMiddleEvent);
wps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wps));
if (!wps) return FALSE;
wps->searchMode = search;
wps->hMod = hmod;
wps->fdwSound = fdwSound;
wps->pszSound = pszSound;
if ((wps->hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0)
goto cleanup;
}
} while (InterlockedCompareExchangePointer((void**)&iData->lpPlaySound, wps, NULL) != NULL);
if (fdwSound & SND_ASYNC) {
if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
!((DWORD)pszSound >> 16)) ||
!pszSound)) {
wps->pszSound = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pszSound)+1) * sizeof(WCHAR) );
lstrcpyW((LPWSTR)wps->pszSound, pszSound);
}
wps->bLoop = fdwSound & SND_LOOP;
/* FIXME: memory leak in case of error & cs is still lock */
if ((wps->hThread = CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id)) == 0)
return FALSE;
return TRUE;
}
return FALSE;
bRet = proc_PlaySound(wps);
cleanup:
return bRet;
}
/**************************************************************************
* PlaySoundA [WINMM.@]
*/
BOOL WINAPI PlaySoundA(LPCSTR pszSoundA, HMODULE hmod, DWORD fdwSound)
{
LPWSTR pszSoundW;
BOOL bSound;
if (!((fdwSound & SND_MEMORY) ||
((fdwSound & SND_RESOURCE) && !((DWORD)pszSoundA >> 16)) ||
!pszSoundA)) {
pszSoundW = HEAP_strdupAtoW(GetProcessHeap(), 0, pszSoundA);
bSound = PlaySoundW(pszSoundW, hmod, fdwSound);
HeapFree(GetProcessHeap(), 0, pszSoundW);
} else
bSound = PlaySoundW((LPWSTR)pszSoundA, hmod, fdwSound);
return bSound;
}
/**************************************************************************
@ -569,18 +559,7 @@ BOOL WINAPI PlaySoundA(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound)
*/
BOOL WINAPI PlaySoundW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound)
{
LPSTR pszSoundA;
BOOL bSound;
if (!((fdwSound & SND_MEMORY) || ((fdwSound & SND_RESOURCE) &&
!((DWORD)pszSound >> 16)) || !pszSound)) {
pszSoundA = HEAP_strdupWtoA(GetProcessHeap(), 0,pszSound);
bSound = PlaySoundA(pszSoundA, hmod, fdwSound);
HeapFree(GetProcessHeap(), 0, pszSoundA);
} else
bSound = PlaySoundA((LPCSTR)pszSound, hmod, fdwSound);
return bSound;
return MULTIMEDIA_PlaySound(pszSound, hmod, fdwSound, 2);
}
/**************************************************************************
@ -601,19 +580,29 @@ BOOL16 WINAPI PlaySound16(LPCSTR pszSound, HMODULE16 hmod, DWORD fdwSound)
/**************************************************************************
* sndPlaySoundA [WINMM.@]
*/
BOOL WINAPI sndPlaySoundA(LPCSTR lpszSoundName, UINT uFlags)
BOOL WINAPI sndPlaySoundA(LPCSTR pszSoundA, UINT uFlags)
{
PlaySound_SearchMode = 1;
return PlaySoundA(lpszSoundName, 0, uFlags);
LPWSTR pszSoundW;
BOOL bSound;
if (!((uFlags & SND_MEMORY) ||
((uFlags & SND_RESOURCE) && !((DWORD)pszSoundA >> 16)) ||
!pszSoundA)) {
pszSoundW = HEAP_strdupAtoW(GetProcessHeap(), 0, pszSoundA);
bSound = sndPlaySoundW(pszSoundW, uFlags);
HeapFree(GetProcessHeap(), 0, pszSoundW);
} else
bSound = sndPlaySoundW((LPWSTR)pszSoundA, uFlags);
return bSound;
}
/**************************************************************************
* sndPlaySoundW [WINMM.@]
*/
BOOL WINAPI sndPlaySoundW(LPCWSTR lpszSoundName, UINT uFlags)
BOOL WINAPI sndPlaySoundW(LPCWSTR pszSound, UINT uFlags)
{
PlaySound_SearchMode = 1;
return PlaySoundW(lpszSoundName, 0, uFlags);
return MULTIMEDIA_PlaySound(pszSound, 0, uFlags, 1);
}
/**************************************************************************
@ -625,13 +614,12 @@ BOOL16 WINAPI sndPlaySound16(LPCSTR lpszSoundName, UINT16 uFlags)
DWORD lc;
ReleaseThunkLock(&lc);
retv = sndPlaySoundA( lpszSoundName, uFlags );
retv = sndPlaySoundA(lpszSoundName, uFlags);
RestoreThunkLock(lc);
return retv;
}
/**************************************************************************
* mmsystemGetVersion [MMSYSTEM.5]
* return value borrowed from Win95 winmm.dll ;)
@ -668,9 +656,7 @@ BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev,
break;
case DCB_WINDOW:
TRACE("Window(%04lX) handle=%04X!\n", dwCallBack, hDev);
if (!IsWindow(dwCallBack))
return FALSE;
PostMessageA((HWND16)dwCallBack, wMsg, hDev, dwParam1);
PostMessageA((HWND)dwCallBack, wMsg, hDev, dwParam1);
break;
case DCB_TASK: /* aka DCB_THREAD */
TRACE("Task(%04lx) !\n", dwCallBack);
@ -1584,13 +1570,7 @@ BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStat
{
TRACE("(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
if (!IsWindow(hWndCallBack)) {
WARN("bad hWnd for call back (0x%04x)\n", hWndCallBack);
return FALSE;
}
TRACE("before PostMessage\n");
PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
return TRUE;
return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
}
/**************************************************************************
@ -1601,13 +1581,7 @@ BOOL WINAPI mciDriverNotify(HWND hWndCallBack, UINT wDevID, UINT wStatus)
TRACE("(%08X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus);
if (!IsWindow(hWndCallBack)) {
WARN("bad hWnd for call back (0x%04x)\n", hWndCallBack);
return FALSE;
}
TRACE("before PostMessage\n");
PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
return TRUE;
return PostMessageA(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID);
}
/**************************************************************************

View File

@ -155,6 +155,18 @@ typedef struct tagWINE_MMIO {
DWORD dwFileSize;
} WINE_MMIO, *LPWINE_MMIO;
typedef struct tagWINE_PLAYSOUND {
HANDLE hThread;
HANDLE hReadyEvent;
BOOL bStop;
LPCWSTR pszSound;
HMODULE hMod;
DWORD fdwSound;
int bLoop;
int searchMode; /* 1 - sndPlaySound search order
2 - PlaySound order */
} WINE_PLAYSOUND, *LPWINE_PLAYSOUND;
typedef struct tagWINE_MM_IDATA {
/* iData reference */
DWORD dwThisProcess;
@ -178,6 +190,8 @@ typedef struct tagWINE_MM_IDATA {
/* LPWINE_MIXER lpMixer; */
/* mmio part */
LPWINE_MMIO lpMMIO;
/* playsound and sndPlaySound */
LPWINE_PLAYSOUND lpPlaySound;
} WINE_MM_IDATA, *LPWINE_MM_IDATA;
/* function prototypes */