From 458bdc7341d189841955c810e9953db73a867e6b Mon Sep 17 00:00:00 2001 From: Jan Zerebecki Date: Mon, 11 Jan 2010 07:57:20 +0100 Subject: [PATCH] push 8d752d3bf550021a0e6e1bdc0a627b8571faeda7 --- dlls/winepulse.drv/waveout.c | 142 ++++++++++++++++------------------------- dlls/winepulse.drv/winepulse.h | 2 +- 2 files changed, 57 insertions(+), 87 deletions(-) diff --git a/dlls/winepulse.drv/waveout.c b/dlls/winepulse.drv/waveout.c index 458a33d7e36..e7454fd2d48 100644 --- a/dlls/winepulse.drv/waveout.c +++ b/dlls/winepulse.drv/waveout.c @@ -105,7 +105,7 @@ static void WAVEOUT_SinkInputInfoCallback(pa_context *c, const pa_sink_input_inf * wodPlayer_NotifyClient [internal] */ static DWORD wodPlayer_NotifyClient(WINE_WAVEINST* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2) { - TRACE("wMsg = 0x%04x dwParm1 = %04X dwParam2 = %04X\n", wMsg, dwParam1, dwParam2); + /* TRACE("wMsg = 0x%04x dwParm1 = %04X dwParam2 = %04X\n", wMsg, dwParam1, dwParam2); */ switch (wMsg) { case WOM_OPEN: @@ -193,35 +193,27 @@ static LPWAVEHDR wodPlayer_PlayPtrNext(WINE_WAVEINST* wwo) { * the size of the buffer on the pulse server side. */ static void wodPlayer_CheckReleasing(WINE_WAVEINST *wwo) { + LPWAVEHDR lpWaveHdr; - if (wwo->buffer_attr.tlength == -1 && wwo->lpQueuePtr && !wwo->lpPlayPtr && wwo->state != WINE_WS_STOPPED) { - const pa_buffer_attr *returned; - - /* Try and adjust the buffer attributes so that playback can start. - * Because of bugs pa_stream_set_buffer_attr() does not work on started - * streams for server version 0.9.11 to 0.9.14 */ - + if (wwo->buffer_attr.tlength == -1) { pa_threaded_mainloop_lock(PULSE_ml); - - /* Calculate desired buffer length. write_index is the amount of data - * written. If there is more than one buffer queued, subtract the - * length of one to allow there to be a free buffer for the app. */ - wwo->buffer_attr.tlength = wwo->timing_info->write_index; - if (wwo->lpQueuePtr->lpNext) wwo->buffer_attr.tlength -= wwo->lpQueuePtr->dwBufferLength; - - WARN("Asking for new buffer target length of %llums (%u bytes)\n", - pa_bytes_to_usec(wwo->buffer_attr.tlength, &wwo->sample_spec) / 1000, - wwo->buffer_attr.tlength); - - PULSE_WaitForOperation(pa_stream_set_buffer_attr(wwo->stream, &wwo->buffer_attr, PULSE_StreamSuccessCallback, wwo)); - - returned = pa_stream_get_buffer_attr(wwo->stream); - - if (returned->tlength > wwo->timing_info->write_index) { - WARN("Couldn't get the buffer size needed. Triggering and hoping for the best.\n"); - PULSE_WaitForOperation(pa_stream_trigger(wwo->stream, PULSE_StreamSuccessCallback, wwo)); + if (!wwo->timing_info->playing) { + + /* Calculate how large a buffer the application has made so far */ + wwo->buffer_attr.tlength = 0; + wwo->buffer_attr.minreq = wwo->lpQueuePtr->dwBufferLength; + for (lpWaveHdr = wwo->lpQueuePtr; lpWaveHdr; lpWaveHdr = lpWaveHdr->lpNext) + wwo->buffer_attr.tlength += lpWaveHdr->dwBufferLength; + + WARN("Asking for new buffer target length of %llums (%u bytes)\n", + pa_bytes_to_usec(wwo->buffer_attr.tlength, &wwo->sample_spec) / 1000, + wwo->buffer_attr.tlength); + + /* Try and adjust the buffer attributes so that playback can start. + * Because of bugs pa_stream_set_buffer_attr() does not work on started + * streams for server version 0.9.11 to 0.9.14 */ + PULSE_WaitForOperation(pa_stream_set_buffer_attr(wwo->stream, &wwo->buffer_attr, PULSE_StreamSuccessCallback, wwo)); } - pa_threaded_mainloop_unlock(PULSE_ml); } } @@ -250,10 +242,11 @@ static DWORD wodPlayer_NotifyCompletions(WINE_WAVEINST* wwo, BOOL force, pa_usec /* See if this data has been played, and if not, return when it will have been */ wait = pa_bytes_to_usec(lpWaveHdr->reserved + lpWaveHdr->dwBufferLength, &wwo->sample_spec); if (wait >= time) { - wait = ((wait - time) + 999) / 1000; + wait = ((wait - time) + (pa_usec_t)999) / (pa_usec_t)1000; return wait ?: 1; } } + TRACE("Returning %p.[%i]\n", lpWaveHdr, (DWORD)lpWaveHdr->reserved); /* return the wavehdr */ wwo->lpQueuePtr = lpWaveHdr->lpNext; @@ -274,7 +267,7 @@ static DWORD wodPlayer_NotifyCompletions(WINE_WAVEINST* wwo, BOOL force, pa_usec * Write either how much free space or how much data we have, depending on * which is less */ -static int wodPlayer_WriteMax(WINE_WAVEINST *wwo, size_t *space) { +static DWORD wodPlayer_WriteMax(WINE_WAVEINST *wwo, size_t *space) { LPWAVEHDR lpWaveHdr = wwo->lpPlayPtr; size_t nbytes; @@ -302,10 +295,7 @@ static int wodPlayer_WriteMax(WINE_WAVEINST *wwo, size_t *space) { */ static void wodPlayer_Feed(WINE_WAVEINST* wwo, size_t space) { - /* No more room... no need to try to feed */ - if (space == 0) return; - - if (!wwo->stream || !PULSE_context || + if (!space || !wwo->stream || !PULSE_context || pa_context_get_state(PULSE_context) != PA_CONTEXT_READY || pa_stream_get_state(wwo->stream) != PA_STREAM_READY) return; @@ -319,8 +309,9 @@ static void wodPlayer_Feed(WINE_WAVEINST* wwo, size_t space) { if (wwo->dwPartialOffset == 0 && wwo->lpPlayPtr) { do { wwo->lpPlayPtr->reserved = wwo->timing_info->write_index; - } while (wodPlayer_WriteMax(wwo, &space) > 0 && wwo->lpPlayPtr && space > 0); + } while (wodPlayer_WriteMax(wwo, &space) && wwo->lpPlayPtr && space > 0); } + pa_threaded_mainloop_unlock(PULSE_ml); } @@ -387,7 +378,7 @@ static void wodPlayer_Reset(WINE_WAVEINST* wwo) { * not reset to 0 on Reset() calls. Better than pa_stream_get_time() as it is * more constant. */ -static pa_usec_t WAVEOUT_GetStreamTime(WINE_WAVEINST *wwo) { +static pa_usec_t wodPlayer_GetStreamTime(WINE_WAVEINST *wwo) { pa_usec_t time, temp; const pa_timing_info *t; @@ -424,15 +415,14 @@ static pa_usec_t WAVEOUT_GetStreamTime(WINE_WAVEINST *wwo) { /************************************************************************** * wodPlayer_ProcessMessages [internal] */ -static DWORD wodPlayer_ProcessMessages(WINE_WAVEINST* wwo) { +static void wodPlayer_ProcessMessages(WINE_WAVEINST* wwo) { LPWAVEHDR lpWaveHdr; enum win_wm_message msg; - DWORD param, msgcount = 0; + DWORD param; HANDLE ev; while (PULSE_RetrieveRingMessage(&wwo->msgRing, &msg, ¶m, &ev)) { TRACE("Received %s %x\n", PULSE_getCmdString(msg), param); - msgcount++; switch (msg) { case WINE_WM_PAUSING: @@ -448,8 +438,8 @@ static DWORD wodPlayer_ProcessMessages(WINE_WAVEINST* wwo) { wwo->state = WINE_WS_PLAYING; pa_threaded_mainloop_lock(PULSE_ml); PULSE_WaitForOperation(pa_stream_cork(wwo->stream, 0, PULSE_StreamSuccessCallback, wwo)); - /* If the serverside buffer was near full before pause, we need to - * have space to write soon, so force playback start */ + /* If the serverside buffer was near full before pausing, we + * need to have space to write soon, so force playback start */ PULSE_WaitForOperation(pa_stream_trigger(wwo->stream, PULSE_StreamSuccessCallback, wwo)); pa_threaded_mainloop_unlock(PULSE_ml); } @@ -496,29 +486,11 @@ static DWORD wodPlayer_ProcessMessages(WINE_WAVEINST* wwo) { /* Return all the queued wavehdrs, so the app will send more data */ wodPlayer_NotifyCompletions(wwo, FALSE, (pa_usec_t)-1); - /* Underrun means playback started, so don't allow future setting of the buffer attributes */ - if (wwo->buffer_attr.tlength == (uint32_t)-1) wwo->buffer_attr.tlength = 0; - SetEvent(ev); break; - case WINE_WM_CLOSING: /* If param = 1, close because of a failure */ + case WINE_WM_CLOSING: wwo->hThread = NULL; - if ((DWORD)param == 1) { - /* If we are here, the stream has failed */ - wwo->state = WINE_WS_FAILED; - SetEvent(ev); - PULSE_DestroyRingMessage(&wwo->msgRing); - wodPlayer_NotifyCompletions(wwo, TRUE, 0); - wodPlayer_NotifyClient(wwo, WOM_CLOSE, 0L, 0L); - wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL; - pa_threaded_mainloop_lock(PULSE_ml); - pa_stream_disconnect(wwo->stream); - pa_threaded_mainloop_unlock(PULSE_ml); - TRACE("Thread exiting because of failure.\n"); - ExitThread(1); - /* Stream instance will get dereferenced in wod_Close */ - } wwo->state = WINE_WS_CLOSED; /* sanity check: this should not happen since the device must have been reset before */ if (wwo->lpQueuePtr || wwo->lpPlayPtr) ERR("out of sync\n"); @@ -532,8 +504,6 @@ static DWORD wodPlayer_ProcessMessages(WINE_WAVEINST* wwo) { break; } } - - return msgcount; } /************************************************************************** @@ -545,6 +515,7 @@ static DWORD wodPlayer_ProcessMessages(WINE_WAVEINST* wwo) { static DWORD CALLBACK wodPlayer(LPVOID lpParam) { WINE_WAVEINST *wwo = (WINE_WAVEINST*)lpParam; DWORD dwSleepTime = INFINITE; + int64_t delta_write; wwo->state = WINE_WS_STOPPED; SetEvent(wwo->hStartUpEvent); @@ -555,17 +526,23 @@ static DWORD CALLBACK wodPlayer(LPVOID lpParam) { TRACE("Waiting %u ms\n", dwSleepTime); PULSE_WaitRingMessage(&wwo->msgRing, dwSleepTime); - /* If no messages were processed during the timeout it might be because - * audio is not flowing yet, so check. */ - if (wodPlayer_ProcessMessages(wwo) == 0) + delta_write = wwo->timing_info->write_index; + wodPlayer_ProcessMessages(wwo); + + /* Check for a stall situaiton */ + if (delta_write == wwo->timing_info->write_index + && wwo->lpQueuePtr && !wwo->lpPlayPtr + && wwo->state != WINE_WS_STOPPED) wodPlayer_CheckReleasing(wwo); /* If there is audio playing, return headers and get next timeout */ if (wwo->state == WINE_WS_PLAYING) { - dwSleepTime = wodPlayer_NotifyCompletions(wwo, FALSE, WAVEOUT_GetStreamTime(wwo)); + dwSleepTime = wodPlayer_NotifyCompletions(wwo, FALSE, wodPlayer_GetStreamTime(wwo)); } else dwSleepTime = INFINITE; } + + return 0; } /************************************************************************** @@ -640,7 +617,7 @@ static DWORD wodOpen(WORD wDevID, DWORD_PTR lpdwUser, LPWAVEOPENDESC lpDesc, DWO pa_stream_set_moved_callback (wwo->stream, PULSE_StreamMovedCallback, wwo); pa_stream_set_suspended_callback (wwo->stream, PULSE_StreamSuspendedCallback, wwo); - /* Blank (but don't send) Buffer Attributes */ + /* Blank Buffer Attributes */ wwo->buffer_attr.prebuf = (uint32_t)-1; wwo->buffer_attr.tlength = (uint32_t)-1; wwo->buffer_attr.minreq = (uint32_t)-1; @@ -802,7 +779,7 @@ static DWORD wodGetPosition(WINE_WAVEINST *wwo, LPMMTIME lpTime, DWORD uSize) { if (lpTime == NULL) return MMSYSERR_INVALPARAM; - time = WAVEOUT_GetStreamTime(wwo); + time = wodPlayer_GetStreamTime(wwo); temp = pa_bytes_to_usec(wwo->dwLastReset, &wwo->sample_spec); if (time > temp) time -= temp; else time = 0; @@ -844,7 +821,7 @@ static DWORD wodGetDevCaps(DWORD wDevID, LPWAVEOUTCAPSW lpCaps, DWORD dwSize) { * Context-sanity check here, as if we respond with 0, WINE will move on * to the next waveout driver. */ -static DWORD wodGetNumDevs() { +static DWORD wodGetNumDevs(void) { if (!PULSE_ml || !PULSE_context || pa_context_get_state(PULSE_context) != PA_CONTEXT_READY) return 0; @@ -855,7 +832,7 @@ static DWORD wodGetNumDevs() { * wodGetVolume [internal] */ static DWORD wodGetVolume(WINE_WAVEINST *wwo, LPDWORD lpdwVol) { - float value1, value2; + double value1, value2; DWORD wleft, wright; if (!wwo || wwo->state == WINE_WS_FAILED) { @@ -877,21 +854,15 @@ static DWORD wodGetVolume(WINE_WAVEINST *wwo, LPDWORD lpdwVol) { if (wwo->volume.channels == 2) { - value1 = pa_sw_volume_to_dB(wwo->volume.values[0]); - value2 = pa_sw_volume_to_dB(wwo->volume.values[1]); + value1 = pa_sw_volume_to_linear(wwo->volume.values[0]); + value2 = pa_sw_volume_to_linear(wwo->volume.values[1]); } else { - value1 = pa_sw_volume_to_dB(pa_cvolume_avg(&wwo->volume)); + value1 = pa_sw_volume_to_linear(pa_cvolume_avg(&wwo->volume)); value2 = value1; } - if (value1 < -60) - wleft = 0; - else - - if (value2 < -60) - wright = 0; - else - wright = 0xFFFFl - ((value2 / -60)*(float)0xFFFFl); + wleft = 0xFFFFl * value1; + wright = 0xFFFFl * value2; if (wleft > 0xFFFFl) wleft = 0xFFFFl; @@ -915,18 +886,17 @@ static DWORD wodSetVolume(WINE_WAVEINST *wwo, DWORD dwParam1) { return MMSYSERR_INVALHANDLE; } - /* waveOut volumes are /supposed/ to be logarithmic */ - value1 = LOWORD(dwParam1) == 0 ? PA_DECIBEL_MININFTY : ((float)(0xFFFFl - LOWORD(dwParam1))/0xFFFFl) * -60.0; - value2 = HIWORD(dwParam1) == 0 ? PA_DECIBEL_MININFTY : ((float)(0xFFFFl - HIWORD(dwParam1))/0xFFFFl) * -60.0; + value1 = (double)LOWORD(dwParam1)/(double)0xFFFFl; + value2 = (double)HIWORD(dwParam1)/(double)0xFFFFl; if (wwo->sample_spec.channels == 2) { wwo->volume.channels = 2; - wwo->volume.values[0] = pa_sw_volume_from_dB(value1); - wwo->volume.values[1] = pa_sw_volume_from_dB(value2); + wwo->volume.values[0] = pa_sw_volume_from_linear(value1); + wwo->volume.values[1] = pa_sw_volume_from_linear(value2); } else { if (value1 != value2) FIXME("Non-stereo streams can't pan!\n"); wwo->volume.channels = wwo->sample_spec.channels; - pa_cvolume_set(&wwo->volume, wwo->volume.channels, pa_sw_volume_from_dB(max(value1, value2))); + pa_cvolume_set(&wwo->volume, wwo->volume.channels, pa_sw_volume_from_linear(value1 > value2 ? value1 : value2)); } if (TRACE_ON(wave)) { diff --git a/dlls/winepulse.drv/winepulse.h b/dlls/winepulse.drv/winepulse.h index 4a834cd913c..0aa7e867120 100644 --- a/dlls/winepulse.drv/winepulse.h +++ b/dlls/winepulse.drv/winepulse.h @@ -129,7 +129,7 @@ struct WINE_WAVEDEV { /* Per-playback/record instance */ struct WINE_WAVEINST { - volatile INT state; /* one of the WINE_WS_ manifest constants */ + INT state; /* one of the WINE_WS_ manifest constants */ WAVEOPENDESC waveDesc; WORD wFlags; -- 2.11.4.GIT