Commit d5975872 authored by Ken Thomases's avatar Ken Thomases Committed by Alexandre Julliard

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.
parent e24533cb
...@@ -185,7 +185,7 @@ static WINE_WAVEOUT WOutDev [MAX_WAVEOUTDRV]; ...@@ -185,7 +185,7 @@ static WINE_WAVEOUT WOutDev [MAX_WAVEOUTDRV];
static CFMessagePortRef Port_SendToMessageThread; static CFMessagePortRef Port_SendToMessageThread;
static void wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo); 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_CreateDefaultAudioUnit(void *wwo, AudioUnit *au);
extern int AudioUnit_CloseAudioUnit(AudioUnit au); extern int AudioUnit_CloseAudioUnit(AudioUnit au);
...@@ -256,26 +256,19 @@ static const char * getMessage(UINT msg) ...@@ -256,26 +256,19 @@ static const char * getMessage(UINT msg)
} }
#define kStopLoopMessage 0 #define kStopLoopMessage 0
#define kWaveOutCallbackMessage 1 #define kWaveOutNotifyCompletionsMessage 1
#define kWaveInCallbackMessage 2 #define kWaveInCallbackMessage 2
/* Mach Message Handling */ /* Mach Message Handling */
static CFDataRef wodMessageHandler(CFMessagePortRef port_ReceiveInMessageThread, SInt32 msgid, CFDataRef data, void *info) static CFDataRef wodMessageHandler(CFMessagePortRef port_ReceiveInMessageThread, SInt32 msgid, CFDataRef data, void *info)
{ {
UInt32 *buffer = NULL; UInt32 *buffer = NULL;
WINE_WAVEOUT* wwo = NULL;
switch (msgid) switch (msgid)
{ {
case kWaveOutCallbackMessage: case kWaveOutNotifyCompletionsMessage:
buffer = (UInt32 *) CFDataGetBytePtr(data); buffer = (UInt32 *) CFDataGetBytePtr(data);
wwo = &WOutDev[buffer[0]]; wodHelper_NotifyCompletions(&WOutDev[buffer[0]], FALSE);
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);
break; break;
case kWaveInCallbackMessage: case kWaveInCallbackMessage:
default: default:
...@@ -303,25 +296,23 @@ static DWORD WINAPI messageThread(LPVOID p) ...@@ -303,25 +296,23 @@ static DWORD WINAPI messageThread(LPVOID p)
return 0; 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; CFDataRef data;
UInt32 buffer[4]; UInt32 buffer;
SInt32 ret;
buffer = (UInt32) wwo->woID;
buffer[0] = (UInt32) wwo->woID;
buffer[1] = (UInt32) wMsg;
buffer[2] = (UInt32) dwParam1;
buffer[3] = (UInt32) dwParam2;
data = CFDataCreate(kCFAllocatorDefault, (UInt8 *)buffer, sizeof(buffer)); data = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&buffer, sizeof(buffer));
if (!data) if (!data)
return 0; return;
ret = CFMessagePortSendRequest(Port_SendToMessageThread, kWaveOutCallbackMessage, data, 0.0, 0.0, NULL, NULL); CFMessagePortSendRequest(Port_SendToMessageThread, kWaveOutNotifyCompletionsMessage, data, 0.0, 0.0, NULL, NULL);
CFRelease(data); CFRelease(data);
return (ret == kCFMessagePortSuccess)?1:0;
} }
static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position, static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
...@@ -589,13 +580,13 @@ void CoreAudio_WaveRelease(void) ...@@ -589,13 +580,13 @@ void CoreAudio_WaveRelease(void)
/************************************************************************** /**************************************************************************
* wodNotifyClient [internal] * 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) static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
{ {
switch (wMsg) { switch (wMsg) {
case WOM_OPEN: case WOM_OPEN:
case WOM_CLOSE: case WOM_CLOSE:
case WOM_DONE:
if (wwo->wFlags != DCB_NULL && if (wwo->wFlags != DCB_NULL &&
!DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags, !DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,
(HDRVR)wwo->waveDesc.hWave, wMsg, wwo->waveDesc.dwInstance, (HDRVR)wwo->waveDesc.hWave, wMsg, wwo->waveDesc.dwInstance,
...@@ -604,13 +595,6 @@ static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD ...@@ -604,13 +595,6 @@ static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD
return MMSYSERR_ERROR; return MMSYSERR_ERROR;
} }
break; break;
case WOM_DONE:
if (wwo->wFlags != DCB_NULL &&
! wodSendDriverCallbackMessage(wwo, wMsg, dwParam1, dwParam2))
{
return MMSYSERR_ERROR;
}
break;
default: default:
return MMSYSERR_INVALPARAM; return MMSYSERR_INVALPARAM;
} }
...@@ -936,39 +920,60 @@ static void wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo) ...@@ -936,39 +920,60 @@ static void wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo)
} }
/* if force is TRUE then notify the client that all the headers were completed /* 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; LPWAVEHDR lpWaveHdr;
DWORD retval; LPWAVEHDR lpFirstDoneWaveHdr = NULL;
pthread_mutex_lock(&wwo->lock); pthread_mutex_lock(&wwo->lock);
/* Start from lpQueuePtr and keep notifying until: /* First, excise all of the done headers from the queue into
* - we hit an unwritten wavehdr * a free-standing list. */
* - we hit the beginning of a running loop if (force)
* - we hit a wavehdr which hasn't finished playing {
*/ lpFirstDoneWaveHdr = wwo->lpQueuePtr;
while ((lpWaveHdr = wwo->lpQueuePtr) && wwo->lpQueuePtr = NULL;
(force || }
(lpWaveHdr != wwo->lpPlayPtr && else
lpWaveHdr != wwo->lpLoopPtr))) {
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_INQUEUE;
lpWaveHdr->dwFlags |= WHDR_DONE; lpWaveHdr->dwFlags |= WHDR_DONE;
wodNotifyClient(wwo, WOM_DONE, (DWORD)lpWaveHdr, 0); 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(void *inRefCon, ...@@ -1453,7 +1458,7 @@ OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon,
memset(ioData->mBuffers[buffer].mData, 0, ioData->mBuffers[buffer].mDataByteSize); memset(ioData->mBuffers[buffer].mData, 0, ioData->mBuffers[buffer].mDataByteSize);
} }
if (needNotify) wodHelper_NotifyCompletions(wwo, FALSE); if (needNotify) wodSendNotifyCompletionsMessage(wwo);
return noErr; return noErr;
} }
#else #else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment