Module: wine
Branch: master
Commit: bdbe803cb632f8f12f621eb60e966cf55b2c4ea9
URL: http://source.winehq.org/git/wine.git/?a=commit;h=bdbe803cb632f8f12f621eb60…
Author: Ken Thomases <ken(a)codeweavers.com>
Date: Thu Dec 21 03:48:59 2006 -0600
winecoreaudio: Leave audio unit running, except when waveout device paused.
---
dlls/winmm/winecoreaudio/audio.c | 89 +++++++++++++++++++++----------------
1 files changed, 50 insertions(+), 39 deletions(-)
diff --git a/dlls/winmm/winecoreaudio/audio.c b/dlls/winmm/winecoreaudio/audio.c
index 265b9af..d38fe9b 100644
--- a/dlls/winmm/winecoreaudio/audio.c
+++ b/dlls/winmm/winecoreaudio/audio.c
@@ -722,6 +722,17 @@ static DWORD wodOpen(WORD wDevID, LPWAVE
return WAVERR_BADFORMAT; /* FIXME return an error based on the OSStatus */
}
wwo->streamDescription = streamFormat;
+
+ ret = AudioOutputUnitStart(wwo->audioUnit);
+ if (ret)
+ {
+ ERR("AudioOutputUnitStart failed: %08x\n", ret);
+ AudioUnitUninitialize(wwo->audioUnit);
+ AudioUnit_CloseAudioUnit(wwo->audioUnit);
+ pthread_mutex_unlock(&wwo->lock);
+ return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
+ }
+
wwo->state = WINE_WS_STOPPED;
wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
@@ -915,14 +926,7 @@ static void wodHelper_PlayPtrNext(WINE_W
wwo->lpPlayPtr = wwo->lpPlayPtr->lpNext;
if (!wwo->lpPlayPtr)
- {
- OSStatus status;
wwo->state = WINE_WS_STOPPED;
- status = AudioOutputUnitStop(wwo->audioUnit);
- if (status && wwo->err_on)
- fprintf(stderr, "err:winecoreaudio:wodHelper_PlayPtrNext AudioOutputUnitStop return %c%c%c%c\n",
- (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
- }
else
wodHelper_CheckForLoopBegin(wwo);
}
@@ -1022,12 +1026,12 @@ static DWORD wodHelper_Reset(WINE_WAVE
wwo->state = WINE_WS_PAUSED;
}
- status = AudioOutputUnitStop(wwo->audioUnit);
-
pthread_mutex_unlock(&wwo->lock);
+ status = AudioOutputUnitStart(wwo->audioUnit);
+
if (status) {
- ERR( "AudioOutputUnitStop return %c%c%c%c\n",
+ ERR( "AudioOutputUnitStart return %c%c%c%c\n",
(char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
}
@@ -1083,13 +1087,7 @@ static DWORD wodWrite(WORD wDevID, LPWAV
wwo->lpPlayPtr = lpWaveHdr;
if (wwo->state == WINE_WS_STOPPED)
- {
- OSStatus status = AudioOutputUnitStart(wwo->audioUnit);
- if (status) {
- ERR("AudioOutputUnitStart return %c%c%c%c\n", (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
- }
- else wwo->state = WINE_WS_PLAYING;
- }
+ wwo->state = WINE_WS_PLAYING;
wodHelper_CheckForLoopBegin(wwo);
@@ -1114,21 +1112,26 @@ static DWORD wodPause(WORD wDevID)
WARN("bad device ID !\n");
return MMSYSERR_BADDEVICEID;
}
-
+
+ /* The order of the following operations is important since we can't hold
+ * the mutex while we make an Audio Unit call. Stop the Audio Unit before
+ * setting the PAUSED state. In wodRestart, the order is reversed. This
+ * guarantees that we can't get into a situation where the state is
+ * PLAYING or STOPPED but the Audio Unit isn't running. Although we can
+ * be in PAUSED state with the Audio Unit still running, that's harmless
+ * because the render callback will just produce silence.
+ */
+ status = AudioOutputUnitStop(WOutDev[wDevID].audioUnit);
+ if (status) {
+ WARN("AudioOutputUnitStop return %c%c%c%c\n",
+ (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
+ }
+
pthread_mutex_lock(&WOutDev[wDevID].lock);
if (WOutDev[wDevID].state == WINE_WS_PLAYING || WOutDev[wDevID].state == WINE_WS_STOPPED)
- {
WOutDev[wDevID].state = WINE_WS_PAUSED;
- status = AudioOutputUnitStop(WOutDev[wDevID].audioUnit);
- if (status) {
- ERR( "AudioOutputUnitStop return %c%c%c%c\n",
- (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
- pthread_mutex_unlock(&WOutDev[wDevID].lock);
- return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
- }
- }
pthread_mutex_unlock(&WOutDev[wDevID].lock);
-
+
return MMSYSERR_NOERROR;
}
@@ -1137,6 +1140,8 @@ static DWORD wodPause(WORD wDevID)
*/
static DWORD wodRestart(WORD wDevID)
{
+ OSStatus status;
+
TRACE("(%u);\n", wDevID);
if (wDevID >= MAX_WAVEOUTDRV )
@@ -1144,26 +1149,32 @@ static DWORD wodRestart(WORD wDevID)
WARN("bad device ID !\n");
return MMSYSERR_BADDEVICEID;
}
-
+
+ /* The order of the following operations is important since we can't hold
+ * the mutex while we make an Audio Unit call. Set the PLAYING/STOPPED
+ * state before starting the Audio Unit. In wodPause, the order is
+ * reversed. This guarantees that we can't get into a situation where
+ * the state is PLAYING or STOPPED but the Audio Unit isn't running.
+ * Although we can be in PAUSED state with the Audio Unit still running,
+ * that's harmless because the render callback will just produce silence.
+ */
pthread_mutex_lock(&WOutDev[wDevID].lock);
if (WOutDev[wDevID].state == WINE_WS_PAUSED)
{
if (WOutDev[wDevID].lpPlayPtr)
- {
- OSStatus status = AudioOutputUnitStart(WOutDev[wDevID].audioUnit);
- if (status) {
- ERR("AudioOutputUnitStart return %c%c%c%c\n",
- (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
- pthread_mutex_unlock(&WOutDev[wDevID].lock);
- return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
- }
WOutDev[wDevID].state = WINE_WS_PLAYING;
- }
else
WOutDev[wDevID].state = WINE_WS_STOPPED;
}
pthread_mutex_unlock(&WOutDev[wDevID].lock);
-
+
+ status = AudioOutputUnitStart(WOutDev[wDevID].audioUnit);
+ if (status) {
+ ERR("AudioOutputUnitStart return %c%c%c%c\n",
+ (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
+ return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
+ }
+
return MMSYSERR_NOERROR;
}