some other playsound fixes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



this patch fixes another bunch of synchronisation issues in
playsound function family

this should help the evolution of the function to add some unimplemented
features (like several playsound in //, differenciation of SND_NOWAIT
and SND_NOSTOP flags)

PS1: thanks to Chris Rankin for the good bug reports and the testing of
the various solutions
PS2: this should also take care, in a different way, of the issue
reported today by Michael Karcher

A+
Name:          winmm_ps
ChangeLog:     some other synchronisation issues
License:       X11
GenDate:       2002/05/28 19:27:34 UTC
ModifiedFiles: dlls/winmm/mmsystem.c dlls/winmm/winemm.h
AddedFiles:    
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/dlls/winmm/mmsystem.c,v
retrieving revision 1.54
diff -u -u -r1.54 mmsystem.c
--- dlls/winmm/mmsystem.c	22 May 2002 01:52:31 -0000	1.54
+++ dlls/winmm/mmsystem.c	26 May 2002 19:30:03 -0000
@@ -93,6 +93,9 @@
     iData->lpNextIData = lpFirstIData;
     lpFirstIData = iData;
     InitializeCriticalSection(&iData->cs);
+    iData->cs.DebugInfo = (void*)__FILE__ ": WinMM";
+    iData->psStopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+    iData->psLastEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
     TRACE("Created IData (%p) for pid %08lx\n", iData, iData->dwThisProcess);
     return TRUE;
 }
@@ -116,6 +119,9 @@
 	}
 	/* FIXME: should also free content and resources allocated 
 	 * inside iData */
+        CloseHandle(iData->psStopEvent);
+        CloseHandle(iData->psLastEvent);
+        DeleteCriticalSection(&iData->cs);
 	HeapFree(GetProcessHeap(), 0, iData);
     }
 }
@@ -245,17 +251,12 @@
 
     static  WCHAR       wszSounds[] = {'S','o','u','n','d','s',0};
     static  WCHAR       wszDefault[] = {'D','e','f','a','u','l','t',0};
-    static  WCHAR       wszKey[] = {'A','p','p','E','v','e','n','t','s','\\','\\',
-                                    'S','c','h','e','m','e','s','\\','\\',
+    static  WCHAR       wszKey[] = {'A','p','p','E','v','e','n','t','s','\\',
+                                    'S','c','h','e','m','e','s','\\',
                                     'A','p','p','s',0};
     static  WCHAR       wszDotDefault[] = {'.','D','e','f','a','u','l','t',0};
     static  WCHAR       wszNull[] = {0};
 
-    /* FIXME: we should also look up the registry under
-     *      HKCU\AppEvents\Schemes\Apps\.Default
-     *      HKCU\AppEvents\Schemes\Apps\<AppName>
-     */
-
     TRACE("searching in SystemSound list for %s\n", debugstr_w(lpszName));
     GetProfileStringW(wszSounds, (LPWSTR)lpszName, wszNull, str, sizeof(str)/sizeof(str[0]));
     if (lstrlenW(str) == 0) 
@@ -269,14 +270,16 @@
     hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
     if (hmmio != 0) return hmmio;
  next:
+    /* we look up the registry under
+     *      HKCU\AppEvents\Schemes\Apps\.Default
+     *      HKCU\AppEvents\Schemes\Apps\<AppName>
+     */
     if (RegOpenKeyW(HKEY_CURRENT_USER, wszKey, &hRegSnd) != 0) goto none;
     if (uFlags & SND_APPLICATION)
     {
-        err = 1;
+        err = 1; /* error */
         if (GetModuleFileNameW(0, str, sizeof(str)/sizeof(str[0])))
         {
-            LPWSTR  ptr;
-        
             for (ptr = str + lstrlenW(str) - 1; ptr >= str; ptr--)
             {
                 if (*ptr == '.') *ptr = 0;
@@ -303,7 +306,7 @@
     count = sizeof(str)/sizeof(str[0]);
     err = RegQueryValueExW(hSnd, NULL, 0, &type, (LPBYTE)str, &count);
     RegCloseKey(hSnd);
-    if (err != 0) goto none;
+    if (err != 0 || !*str) goto none;
     hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
     if (hmmio) return hmmio;
  none:
@@ -348,6 +351,77 @@
     }
 }
 
+static BOOL PlaySound_IsString(DWORD fdwSound, const void* psz)
+{
+    /* SND_RESOURCE is 0x40004 while
+     * SND_MEMORY is 0x00004
+     */
+    switch (fdwSound & (SND_RESOURCE|SND_ALIAS|SND_FILENAME))
+    {
+    case SND_RESOURCE:  return HIWORD(psz) != 0; /* by name or by ID ? */
+    case SND_MEMORY:    return FALSE;
+    case SND_ALIAS:     /* what about ALIAS_ID ??? */
+    case SND_FILENAME:
+    case 0:             return TRUE; 
+    default:            FIXME("WTF\n"); return FALSE;
+    }
+}
+
+static void     PlaySound_Free(WINE_PLAYSOUND* wps)
+{
+    LPWINE_MM_IDATA     iData = MULTIMEDIA_GetIData();
+    WINE_PLAYSOUND**    p;
+
+    EnterCriticalSection(&iData->cs);
+    for (p = &iData->lpPlaySound; *p && *p != wps; p = &((*p)->lpNext));
+    if (*p) *p = (*p)->lpNext;
+    if (iData->lpPlaySound == NULL) SetEvent(iData->psLastEvent);
+    LeaveCriticalSection(&iData->cs);
+    if (wps->bAlloc) HeapFree(GetProcessHeap(), 0, (void*)wps->pszSound);
+    HeapFree(GetProcessHeap(), 0, wps);
+}
+
+static WINE_PLAYSOUND*  PlaySound_Alloc(const void* pszSound, HMODULE hmod, 
+                                        DWORD fdwSound, BOOL bUnicode)
+{
+    WINE_PLAYSOUND* wps;
+
+    wps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wps));
+    if (!wps) return NULL;
+
+    wps->hMod = hmod;
+    wps->fdwSound = fdwSound;
+    if (PlaySound_IsString(fdwSound, pszSound))
+    {
+        if (bUnicode)
+        {
+            if (fdwSound & SND_ASYNC)
+            {
+                wps->pszSound = HeapAlloc(GetProcessHeap(), 0, 
+                                          (lstrlenW(pszSound)+1) * sizeof(WCHAR));
+                if (!wps->pszSound) goto oom_error;
+                lstrcpyW((LPWSTR)wps->pszSound, pszSound);
+                wps->bAlloc = TRUE;
+            }
+            else
+                wps->pszSound = pszSound;
+        }
+        else
+        {
+            wps->pszSound = HEAP_strdupAtoW(GetProcessHeap(), 0, pszSound);
+            if (!wps->pszSound) goto oom_error;
+            wps->bAlloc = TRUE;
+        }
+    }
+    else
+        wps->pszSound = pszSound;
+
+    return wps;
+ oom_error:
+    PlaySound_Free(wps);
+    return NULL;
+}
+
 static DWORD WINAPI proc_PlaySound(LPVOID arg)
 {
     WINE_PLAYSOUND*     wps = (WINE_PLAYSOUND*)arg;
@@ -385,7 +459,6 @@
         data = (void*)wps->pszSound;
 
     /* construct an MMIO stream (either in memory, or from a file */
-/*    hmmio = 0; */ /* to catch errors */
     if (wps->fdwSound & SND_MEMORY)
     { /* NOTE: SND_RESOURCE has the SND_MEMORY bit set */
 	MMIOINFO	mminfo;
@@ -482,9 +555,11 @@
 	s.dwEventCount = 1L; /* for first buffer */
 
 	mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET);
-	while (left) {
-	    if (wps->bStop) {
-		wps->bStop = wps->bLoop = FALSE;
+	while (left) 
+        {
+	    if (WaitForSingleObject(iData->psStopEvent, 0) == WAIT_OBJECT_0)
+            {
+		wps->bLoop = FALSE;
 		break;
 	    }
 	    count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left));
@@ -515,38 +590,15 @@
     if (hWave)		while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100);
     if (hmmio) 		mmioClose(hmmio, 0);
 
-    SetEvent(wps->hReadyEvent);
-    iData->lpPlaySound = NULL;
-
-    if (wps->bAlloc) HeapFree(GetProcessHeap(), 0, (void*)wps->pszSound);
-    CloseHandle(wps->hReadyEvent);
-    HeapFree(GetProcessHeap(), 0, wps);
+    PlaySound_Free(wps);
 
     return bRet;
 }
 
-static BOOL MULTIMEDIA_IsString(DWORD fdwSound, const void* psz)
-{
-    /* SND_RESOURCE is 0x40004 while
-     * SND_MEMORY is 0x00004
-     */
-    switch (fdwSound & (SND_RESOURCE|SND_ALIAS|SND_FILENAME))
-    {
-    case SND_RESOURCE:  return HIWORD(psz) != 0; /* by name or by ID ? */
-    case SND_MEMORY:    return FALSE;
-    case SND_ALIAS:     /* what about ALIAS_ID ??? */
-    case SND_FILENAME:
-    case 0:             return TRUE; 
-    default:            FIXME("WTF\n"); return FALSE;
-    }
-}
-
 static BOOL MULTIMEDIA_PlaySound(const void* pszSound, HMODULE hmod, DWORD fdwSound, BOOL bUnicode)
 {
     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);
@@ -554,74 +606,52 @@
     /* 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) 
+    if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && iData->lpPlaySound != NULL) 
 	return FALSE;
+
+    /* alloc internal structure, if we need to play something */
+    if (pszSound && !(fdwSound & SND_PURGE))
+    {
+        if (!(wps = PlaySound_Alloc(pszSound, hmod, fdwSound, bUnicode)))
+            return FALSE;
+    }
     
-    do {
-        HANDLE  hEvt = 0;
+    EnterCriticalSection(&iData->cs);
+    /* since several threads can enter PlaySound in parallel, we're not
+     * sure, at this point, that another thread didn't start a new playsound
+     */
+    while (iData->lpPlaySound != NULL)
+    {
+        ResetEvent(iData->psLastEvent);
+        /* FIXME: doc says we have to stop all instances of pszSound if it's non
+         * NULL... as of today, we stop all playing instances */
+        SetEvent(iData->psStopEvent);
 
-        /* Trying to stop if playing */
-        EnterCriticalSection(&iData->cs);
-        if (iData->lpPlaySound) {
-            LPWINE_PLAYSOUND        ps2stop = iData->lpPlaySound;
-            
-            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);
+        WaitForSingleObject(iData->psLastEvent, INFINITE);
+        EnterCriticalSection(&iData->cs);
 
-        if (!pszSound || (fdwSound & SND_PURGE)) 
-            return TRUE; /* We stopped playing so leaving */
+        ResetEvent(iData->psStopEvent);
+    }
 
-        if (wps == NULL)
-        {
-            wps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wps));
-            if (!wps) return FALSE;
-            
-            wps->hMod = hmod;
-            wps->fdwSound = fdwSound;
-            wps->bAlloc = FALSE;
-            if (MULTIMEDIA_IsString(fdwSound, pszSound))
-            {
-                if (bUnicode)
-                {
-                    if (fdwSound & SND_ASYNC)
-                    {
-                        wps->pszSound = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pszSound)+1) * sizeof(WCHAR));
-                        lstrcpyW((LPWSTR)wps->pszSound, pszSound);
-                        wps->bAlloc = TRUE;
-                    }
-                    else
-                        wps->pszSound = pszSound;
-                }
-                else
-                {
-                    wps->pszSound = HEAP_strdupAtoW(GetProcessHeap(), 0, pszSound);
-                    wps->bAlloc = TRUE;
-                }
-            }
-            else
-                wps->pszSound = pszSound;
-            if ((wps->hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0)
-                goto cleanup;
-        }
-    } while (InterlockedCompareExchangePointer((void**)&iData->lpPlaySound, wps, NULL) != NULL);
+    wps->lpNext = iData->lpPlaySound;
+    iData->lpPlaySound = wps;
+    LeaveCriticalSection(&iData->cs);
+
+    if (!pszSound || (fdwSound & SND_PURGE)) return TRUE;
 
     if (fdwSound & SND_ASYNC) 
     {
-	wps->bLoop = fdwSound & SND_LOOP;
-        /* FIXME: memory leak in case of error & cs is still locked */
-        return ((wps->hThread = CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id)) != 0);
-    }
-
-    bRet = proc_PlaySound(wps);
- cleanup:
-    return bRet;
+        DWORD       id;
+        wps->bLoop = (fdwSound & SND_LOOP) ? TRUE : FALSE;
+        if (CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id) != 0)
+            return TRUE;
+    }
+    else return proc_PlaySound(wps);
+
+    /* error cases */
+    PlaySound_Free(wps);
+    return FALSE;
 }
 
 /**************************************************************************
Index: dlls/winmm/winemm.h
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/dlls/winmm/winemm.h,v
retrieving revision 1.12
diff -u -u -r1.12 winemm.h
--- dlls/winmm/winemm.h	22 May 2002 01:52:31 -0000	1.12
+++ dlls/winmm/winemm.h	26 May 2002 17:24:37 -0000
@@ -156,14 +156,12 @@
 } WINE_MMIO, *LPWINE_MMIO;
 
 typedef struct tagWINE_PLAYSOUND {
-    HANDLE              hThread;
-    HANDLE		hReadyEvent;
-    BOOL 		bStop;
-    LPCWSTR		pszSound;
-    HMODULE		hMod;
-    DWORD		fdwSound;
-    BOOL	        bLoop;
-    BOOL                bAlloc;
+    volatile BOOL	        bLoop : 1,
+                                bAlloc : 1;
+    LPCWSTR		        pszSound;
+    HMODULE		        hMod;
+    DWORD		        fdwSound;
+    struct tagWINE_PLAYSOUND*   lpNext;
 } WINE_PLAYSOUND, *LPWINE_PLAYSOUND;
 
 typedef struct tagWINE_MM_IDATA {
@@ -190,7 +188,9 @@
     /* mmio part */
     LPWINE_MMIO			lpMMIO;
     /* playsound and sndPlaySound */
-    LPWINE_PLAYSOUND            lpPlaySound;
+    WINE_PLAYSOUND*             lpPlaySound;
+    HANDLE                      psLastEvent;
+    HANDLE                      psStopEvent;
 } WINE_MM_IDATA, *LPWINE_MM_IDATA;
 
 /* function prototypes */

[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux