Reduced fragment size.
Reorganized wodOpen (with support for WAVE_QUERY_FORMAT). Fixed buffer underrun recovery. Fixed bug in wodReset()/wodClose().
This commit is contained in:
parent
d785aa646f
commit
b1ec5bcae2
|
@ -169,7 +169,7 @@ static BOOL wodPlayer_WriteFragments(WINE_WAVEOUT* wwo)
|
||||||
LeaveCriticalSection(&wwo->critSect);
|
LeaveCriticalSection(&wwo->critSect);
|
||||||
ExitThread(-1);
|
ExitThread(-1);
|
||||||
}
|
}
|
||||||
TRACE(wave, "Can write %d fragments\n", abinfo.fragments);
|
TRACE(wave, "Can write %d fragments on fd %d\n", abinfo.fragments, wwo->unixdev);
|
||||||
|
|
||||||
if (abinfo.fragments == 0) /* output queue is full, wait a bit */
|
if (abinfo.fragments == 0) /* output queue is full, wait a bit */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -180,6 +180,7 @@ static BOOL wodPlayer_WriteFragments(WINE_WAVEOUT* wwo)
|
||||||
wwo->dwNotifiedBytes >= wwo->dwFragmentSize && /* first fragment has been played */
|
wwo->dwNotifiedBytes >= wwo->dwFragmentSize && /* first fragment has been played */
|
||||||
abinfo.fragstotal - abinfo.fragments < 2) { /* done with all waveOutWrite()' fragments */
|
abinfo.fragstotal - abinfo.fragments < 2) { /* done with all waveOutWrite()' fragments */
|
||||||
|
|
||||||
|
/* FIXME: should do better handling here */
|
||||||
TRACE(wave, "Oooch, buffer underrun !\n");
|
TRACE(wave, "Oooch, buffer underrun !\n");
|
||||||
return TRUE; /* force resetting of waveOut device */
|
return TRUE; /* force resetting of waveOut device */
|
||||||
}
|
}
|
||||||
|
@ -245,7 +246,7 @@ static void wodPlayer_Notify(WINE_WAVEOUT* wwo, WORD uDevID, BOOL force)
|
||||||
LeaveCriticalSection(&wwo->critSect);
|
LeaveCriticalSection(&wwo->critSect);
|
||||||
ExitThread(-1);
|
ExitThread(-1);
|
||||||
}
|
}
|
||||||
TRACE(wave, "Played %d bytes\n", cinfo.bytes);
|
TRACE(wave, "Played %d bytes on fd %d\n", cinfo.bytes, wwo->unixdev);
|
||||||
/* FIXME: this will not work if a RESET or SYNC occurs somewhere */
|
/* FIXME: this will not work if a RESET or SYNC occurs somewhere */
|
||||||
wwo->dwTotalPlayed = cinfo.bytes;
|
wwo->dwTotalPlayed = cinfo.bytes;
|
||||||
}
|
}
|
||||||
|
@ -347,6 +348,7 @@ static DWORD WINAPI wodPlayer(LPVOID pmt)
|
||||||
WARN(wave, "can't notify client !\n");
|
WARN(wave, "can't notify client !\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
wwo->lpQueueHdr = 0;
|
||||||
wwo->state = WINE_WS_STOPPED;
|
wwo->state = WINE_WS_STOPPED;
|
||||||
break;
|
break;
|
||||||
case WINE_WS_CLOSING:
|
case WINE_WS_CLOSING:
|
||||||
|
@ -475,8 +477,12 @@ static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPS16 lpCaps, DWORD dwSize)
|
||||||
*/
|
*/
|
||||||
static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
|
static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
|
||||||
{
|
{
|
||||||
int audio, abuf_size, smplrate, samplesize, dsp_stereo;
|
int audio;
|
||||||
LPWAVEFORMAT lpFormat;
|
int sample_rate;
|
||||||
|
int sample_size;
|
||||||
|
int dsp_stereo;
|
||||||
|
int audio_fragment;
|
||||||
|
int fragment_size;
|
||||||
|
|
||||||
TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
|
TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
|
||||||
if (lpDesc == NULL) {
|
if (lpDesc == NULL) {
|
||||||
|
@ -487,6 +493,19 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
|
||||||
TRACE(wave, "MAX_WAVOUTDRV reached !\n");
|
TRACE(wave, "MAX_WAVOUTDRV reached !\n");
|
||||||
return MMSYSERR_BADDEVICEID;
|
return MMSYSERR_BADDEVICEID;
|
||||||
}
|
}
|
||||||
|
/* only PCM format is supported so far... */
|
||||||
|
if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
|
||||||
|
lpDesc->lpFormat->nChannels == 0 ||
|
||||||
|
lpDesc->lpFormat->nSamplesPerSec == 0) {
|
||||||
|
WARN(wave, "Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",
|
||||||
|
lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
|
||||||
|
lpDesc->lpFormat->nSamplesPerSec);
|
||||||
|
return WAVERR_BADFORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dwFlags & WAVE_FORMAT_QUERY)
|
||||||
|
return MMSYSERR_NOERROR;
|
||||||
|
|
||||||
WOutDev[wDevID].unixdev = 0;
|
WOutDev[wDevID].unixdev = 0;
|
||||||
if (access(SOUND_DEV, 0) != 0)
|
if (access(SOUND_DEV, 0) != 0)
|
||||||
return MMSYSERR_NOTENABLED;
|
return MMSYSERR_NOTENABLED;
|
||||||
|
@ -495,31 +514,11 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
|
||||||
WARN(wave, "can't open !\n");
|
WARN(wave, "can't open !\n");
|
||||||
return MMSYSERR_ALLOCATED ;
|
return MMSYSERR_ALLOCATED ;
|
||||||
}
|
}
|
||||||
IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
|
|
||||||
if (abuf_size < 1024 || abuf_size > 65536) {
|
|
||||||
if (abuf_size == -1)
|
|
||||||
WARN(wave, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
|
|
||||||
else
|
|
||||||
WARN(wave, "SNDCTL_DSP_GETBLKSIZE Invalid dwFragmentSize !\n");
|
|
||||||
return MMSYSERR_NOTENABLED;
|
|
||||||
}
|
|
||||||
WOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
|
WOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
|
||||||
|
|
||||||
/* FIXME: copy lpFormat too? */
|
memcpy(&WOutDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
|
||||||
memcpy(&WOutDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
|
memcpy(&WOutDev[wDevID].format, lpDesc->lpFormat, sizeof(PCMWAVEFORMAT));
|
||||||
TRACE(wave, "lpDesc->lpFormat = %p\n", lpDesc->lpFormat);
|
|
||||||
lpFormat = lpDesc->lpFormat;
|
|
||||||
TRACE(wave, "lpFormat = %p\n", lpFormat);
|
|
||||||
if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
|
|
||||||
WARN(wave, "Bad format %04X !\n", lpFormat->wFormatTag);
|
|
||||||
WARN(wave, "Bad nChannels %d !\n", lpFormat->nChannels);
|
|
||||||
WARN(wave, "Bad nSamplesPerSec %ld !\n", lpFormat->nSamplesPerSec);
|
|
||||||
return WAVERR_BADFORMAT;
|
|
||||||
}
|
|
||||||
memcpy(&WOutDev[wDevID].format, lpFormat, sizeof(PCMWAVEFORMAT));
|
|
||||||
if (WOutDev[wDevID].format.wf.nChannels == 0) return WAVERR_BADFORMAT;
|
|
||||||
if (WOutDev[wDevID].format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
|
|
||||||
TRACE(wave, "wBitsPerSample=%u !\n", WOutDev[wDevID].format.wBitsPerSample);
|
|
||||||
|
|
||||||
if (WOutDev[wDevID].format.wBitsPerSample == 0) {
|
if (WOutDev[wDevID].format.wBitsPerSample == 0) {
|
||||||
WOutDev[wDevID].format.wBitsPerSample = 8 *
|
WOutDev[wDevID].format.wBitsPerSample = 8 *
|
||||||
|
@ -528,30 +527,41 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
|
||||||
WOutDev[wDevID].format.wf.nChannels;
|
WOutDev[wDevID].format.wf.nChannels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* shockwave player uses only 4 1k-fragments at a rate of 22050 bytes/sec
|
||||||
|
* thus leading to 46ms per fragment, and a turnaround time of 185ms
|
||||||
|
*/
|
||||||
|
/* 2^10=1024 bytes per fragment, 16 fragments max */
|
||||||
|
audio_fragment = 0x000F000A;
|
||||||
|
sample_size = WOutDev[wDevID].format.wBitsPerSample;
|
||||||
|
sample_rate = WOutDev[wDevID].format.wf.nSamplesPerSec;
|
||||||
|
dsp_stereo = (WOutDev[wDevID].format.wf.nChannels > 1) ? TRUE : FALSE;
|
||||||
|
|
||||||
|
IOCTL(audio, SNDCTL_DSP_SETFRAGMENT, audio_fragment);
|
||||||
|
/* First size and stereo then samplerate */
|
||||||
|
IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, sample_size);
|
||||||
|
IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
|
||||||
|
IOCTL(audio, SNDCTL_DSP_SPEED, sample_rate);
|
||||||
|
|
||||||
|
/* even if we set fragment size above, read it again, just in case */
|
||||||
|
IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, fragment_size);
|
||||||
|
|
||||||
WOutDev[wDevID].lpQueueHdr = NULL;
|
WOutDev[wDevID].lpQueueHdr = NULL;
|
||||||
WOutDev[wDevID].unixdev = audio;
|
WOutDev[wDevID].unixdev = audio;
|
||||||
WOutDev[wDevID].dwTotalPlayed = 0;
|
WOutDev[wDevID].dwTotalPlayed = 0;
|
||||||
WOutDev[wDevID].dwFragmentSize = abuf_size;
|
WOutDev[wDevID].dwFragmentSize = fragment_size;
|
||||||
WOutDev[wDevID].state = WINE_WS_STOPPED;
|
WOutDev[wDevID].state = WINE_WS_STOPPED;
|
||||||
WOutDev[wDevID].hThread = 0;
|
WOutDev[wDevID].hThread = 0;
|
||||||
|
|
||||||
samplesize = WOutDev[wDevID].format.wBitsPerSample;
|
|
||||||
smplrate = WOutDev[wDevID].format.wf.nSamplesPerSec;
|
|
||||||
dsp_stereo = (WOutDev[wDevID].format.wf.nChannels > 1) ? TRUE : FALSE;
|
|
||||||
|
|
||||||
/* First size and stereo then samplerate */
|
|
||||||
IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
|
|
||||||
IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
|
|
||||||
IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
|
|
||||||
|
|
||||||
/* FIXME: do we need to make critsect global ? */
|
/* FIXME: do we need to make critsect global ? */
|
||||||
InitializeCriticalSection(&WOutDev[wDevID].critSect);
|
InitializeCriticalSection(&WOutDev[wDevID].critSect);
|
||||||
MakeCriticalSectionGlobal(&WOutDev[wDevID].critSect);
|
MakeCriticalSectionGlobal(&WOutDev[wDevID].critSect);
|
||||||
|
|
||||||
TRACE(wave, "wBitsPerSample=%u !\n", WOutDev[wDevID].format.wBitsPerSample);
|
TRACE(wave, "fd=%d fragmentSize=%ld\n",
|
||||||
TRACE(wave, "nAvgBytesPerSec=%lu !\n", WOutDev[wDevID].format.wf.nAvgBytesPerSec);
|
WOutDev[wDevID].unixdev, WOutDev[wDevID].dwFragmentSize);
|
||||||
TRACE(wave, "nSamplesPerSec=%lu !\n", WOutDev[wDevID].format.wf.nSamplesPerSec);
|
|
||||||
TRACE(wave, "nChannels=%u !\n", WOutDev[wDevID].format.wf.nChannels);
|
TRACE(wave, "wBitsPerSample=%u, nAvgBytesPerSec=%lu, nSamplesPerSec=%lu, nChannels=%u !\n",
|
||||||
|
WOutDev[wDevID].format.wBitsPerSample, WOutDev[wDevID].format.wf.nAvgBytesPerSec,
|
||||||
|
WOutDev[wDevID].format.wf.nSamplesPerSec, WOutDev[wDevID].format.wf.nChannels);
|
||||||
|
|
||||||
if (WAVE_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
|
if (WAVE_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
|
||||||
WARN(wave, "can't notify client !\n");
|
WARN(wave, "can't notify client !\n");
|
||||||
|
@ -574,7 +584,7 @@ static DWORD wodClose(WORD wDevID)
|
||||||
return MMSYSERR_BADDEVICEID;
|
return MMSYSERR_BADDEVICEID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WOutDev[wDevID].lpQueueHdr != NULL) {
|
if (WOutDev[wDevID].lpQueueHdr != NULL || WOutDev[wDevID].lpNotifyHdr != NULL) {
|
||||||
WARN(wave, "buffers still playing !\n");
|
WARN(wave, "buffers still playing !\n");
|
||||||
ret = WAVERR_STILLPLAYING;
|
ret = WAVERR_STILLPLAYING;
|
||||||
} else {
|
} else {
|
||||||
|
@ -636,8 +646,8 @@ static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
break;
|
break;
|
||||||
case WINE_WS_STOPPED:
|
case WINE_WS_STOPPED:
|
||||||
|
WOutDev[wDevID].state = WINE_WS_PLAYING;
|
||||||
if (WOutDev[wDevID].hThread == 0) {
|
if (WOutDev[wDevID].hThread == 0) {
|
||||||
WOutDev[wDevID].state = WINE_WS_PLAYING;
|
|
||||||
WOutDev[wDevID].hThread = CreateThread(NULL, 0, wodPlayer, (LPVOID)(DWORD)wDevID, 0, NULL);
|
WOutDev[wDevID].hThread = CreateThread(NULL, 0, wodPlayer, (LPVOID)(DWORD)wDevID, 0, NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue