Ken Thomases : winecoreaudio:
Push notify of completions from render callback to message thread.
Alexandre Julliard
julliard at wine.codeweavers.com
Thu Dec 21 10:36:34 CST 2006
Module: wine
Branch: master
Commit: d5975872af50aa8c318513961be090c44b1486f2
URL: http://source.winehq.org/git/wine.git/?a=commit;h=d5975872af50aa8c318513961be090c44b1486f2
Author: Ken Thomases <ken at codeweavers.com>
Date: Thu Dec 21 03:49:43 2006 -0600
winecoreaudio: Push notify of completions from render callback to message thread.
Rather than have the Audio Unit render callback traverse the queue of wave
headers looking for complete ones, and sending a message to the message thread
for each one it finds, just send one message to tell the message thread to do
that work itself. The render callback is called in a real-time priority
thread and is expected to return as quickly as possible.
---
dlls/winmm/winecoreaudio/audio.c | 119 ++++++++++++++++++++------------------
1 files changed, 62 insertions(+), 57 deletions(-)
diff --git a/dlls/winmm/winecoreaudio/audio.c b/dlls/winmm/winecoreaudio/audio.c
index 9acbd06..54393df 100644
--- a/dlls/winmm/winecoreaudio/audio.c
+++ b/dlls/winmm/winecoreaudio/audio.c
@@ -185,7 +185,7 @@ static WINE_WAVEOUT WOutDev [MAX_WAVEO
static CFMessagePortRef Port_SendToMessageThread;
static void wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo);
-static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force);
+static void wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force);
extern int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au);
extern int AudioUnit_CloseAudioUnit(AudioUnit au);
@@ -256,26 +256,19 @@ static const char * getMessage(UINT msg)
}
#define kStopLoopMessage 0
-#define kWaveOutCallbackMessage 1
+#define kWaveOutNotifyCompletionsMessage 1
#define kWaveInCallbackMessage 2
/* Mach Message Handling */
static CFDataRef wodMessageHandler(CFMessagePortRef port_ReceiveInMessageThread, SInt32 msgid, CFDataRef data, void *info)
{
UInt32 *buffer = NULL;
- WINE_WAVEOUT* wwo = NULL;
-
+
switch (msgid)
{
- case kWaveOutCallbackMessage:
+ case kWaveOutNotifyCompletionsMessage:
buffer = (UInt32 *) CFDataGetBytePtr(data);
- wwo = &WOutDev[buffer[0]];
-
- pthread_mutex_lock(&wwo->lock);
- DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,
- (HDRVR)wwo->waveDesc.hWave, (WORD)buffer[1], wwo->waveDesc.dwInstance,
- (DWORD)buffer[2], (DWORD)buffer[3]);
- pthread_mutex_unlock(&wwo->lock);
+ wodHelper_NotifyCompletions(&WOutDev[buffer[0]], FALSE);
break;
case kWaveInCallbackMessage:
default:
@@ -303,25 +296,23 @@ static DWORD WINAPI messageThread(LPVOID
return 0;
}
-static DWORD wodSendDriverCallbackMessage(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
+/**************************************************************************
+* wodSendNotifyCompletionsMessage [internal]
+* Call from AudioUnit IO thread can't use Wine debug channels.
+*/
+static void wodSendNotifyCompletionsMessage(WINE_WAVEOUT* wwo)
{
CFDataRef data;
- UInt32 buffer[4];
- SInt32 ret;
-
- buffer[0] = (UInt32) wwo->woID;
- buffer[1] = (UInt32) wMsg;
- buffer[2] = (UInt32) dwParam1;
- buffer[3] = (UInt32) dwParam2;
+ UInt32 buffer;
+
+ buffer = (UInt32) wwo->woID;
- data = CFDataCreate(kCFAllocatorDefault, (UInt8 *)buffer, sizeof(buffer));
+ data = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&buffer, sizeof(buffer));
if (!data)
- return 0;
-
- ret = CFMessagePortSendRequest(Port_SendToMessageThread, kWaveOutCallbackMessage, data, 0.0, 0.0, NULL, NULL);
+ return;
+
+ CFMessagePortSendRequest(Port_SendToMessageThread, kWaveOutNotifyCompletionsMessage, data, 0.0, 0.0, NULL, NULL);
CFRelease(data);
-
- return (ret == kCFMessagePortSuccess)?1:0;
}
static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
@@ -589,13 +580,13 @@ void CoreAudio_WaveRelease(void)
/**************************************************************************
* wodNotifyClient [internal]
-* Call from AudioUnit IO thread can't use Wine debug channels.
*/
static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
{
switch (wMsg) {
case WOM_OPEN:
case WOM_CLOSE:
+ case WOM_DONE:
if (wwo->wFlags != DCB_NULL &&
!DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,
(HDRVR)wwo->waveDesc.hWave, wMsg, wwo->waveDesc.dwInstance,
@@ -604,13 +595,6 @@ static DWORD wodNotifyClient(WINE_WAVEOU
return MMSYSERR_ERROR;
}
break;
- case WOM_DONE:
- if (wwo->wFlags != DCB_NULL &&
- ! wodSendDriverCallbackMessage(wwo, wMsg, dwParam1, dwParam2))
- {
- return MMSYSERR_ERROR;
- }
- break;
default:
return MMSYSERR_INVALPARAM;
}
@@ -936,39 +920,60 @@ static void wodHelper_PlayPtrNext(WINE_W
}
/* if force is TRUE then notify the client that all the headers were completed
- * Call from AudioUnit IO thread can't use Wine debug channels.
*/
-static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force)
+static void wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force)
{
LPWAVEHDR lpWaveHdr;
- DWORD retval;
+ LPWAVEHDR lpFirstDoneWaveHdr = NULL;
pthread_mutex_lock(&wwo->lock);
- /* Start from lpQueuePtr and keep notifying until:
- * - we hit an unwritten wavehdr
- * - we hit the beginning of a running loop
- * - we hit a wavehdr which hasn't finished playing
- */
- while ((lpWaveHdr = wwo->lpQueuePtr) &&
- (force ||
- (lpWaveHdr != wwo->lpPlayPtr &&
- lpWaveHdr != wwo->lpLoopPtr)))
+ /* First, excise all of the done headers from the queue into
+ * a free-standing list. */
+ if (force)
+ {
+ lpFirstDoneWaveHdr = wwo->lpQueuePtr;
+ wwo->lpQueuePtr = NULL;
+ }
+ else
+ {
+ LPWAVEHDR lpLastDoneWaveHdr = NULL;
+
+ /* Start from lpQueuePtr and keep notifying until:
+ * - we hit an unwritten wavehdr
+ * - we hit the beginning of a running loop
+ * - we hit a wavehdr which hasn't finished playing
+ */
+ for (
+ lpWaveHdr = wwo->lpQueuePtr;
+ lpWaveHdr &&
+ lpWaveHdr != wwo->lpPlayPtr &&
+ lpWaveHdr != wwo->lpLoopPtr;
+ lpWaveHdr = lpWaveHdr->lpNext
+ )
+ {
+ if (!lpFirstDoneWaveHdr)
+ lpFirstDoneWaveHdr = lpWaveHdr;
+ lpLastDoneWaveHdr = lpWaveHdr;
+ }
+
+ if (lpLastDoneWaveHdr)
+ {
+ wwo->lpQueuePtr = lpLastDoneWaveHdr->lpNext;
+ lpLastDoneWaveHdr->lpNext = NULL;
+ }
+ }
+
+ pthread_mutex_unlock(&wwo->lock);
+
+ /* Now, send the "done" notification for each header in our list. */
+ for (lpWaveHdr = lpFirstDoneWaveHdr; lpWaveHdr; lpWaveHdr = lpWaveHdr->lpNext)
{
- wwo->lpQueuePtr = lpWaveHdr->lpNext;
-
lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
lpWaveHdr->dwFlags |= WHDR_DONE;
-
+
wodNotifyClient(wwo, WOM_DONE, (DWORD)lpWaveHdr, 0);
}
-
- retval = (lpWaveHdr && lpWaveHdr != wwo->lpPlayPtr && lpWaveHdr !=
- wwo->lpLoopPtr) ? 0 : INFINITE;
-
- pthread_mutex_unlock(&wwo->lock);
-
- return retval;
}
/**************************************************************************
@@ -1453,7 +1458,7 @@ OSStatus CoreAudio_woAudioUnitIOProc(voi
memset(ioData->mBuffers[buffer].mData, 0, ioData->mBuffers[buffer].mDataByteSize);
}
- if (needNotify) wodHelper_NotifyCompletions(wwo, FALSE);
+ if (needNotify) wodSendNotifyCompletionsMessage(wwo);
return noErr;
}
#else
More information about the wine-cvs
mailing list