Commit cb2abbc2 authored by Stephane Lussier's avatar Stephane Lussier Committed by Alexandre Julliard

- Read all the fragments available, not only one fragment before

going back to sleep. - Use SNDCTL_DSP_SETTRIGGER ioctl command to trigger the start the recording. If this command is not supported by the device, read 4 bytes in the sound device instead.
parent 780bb796
...@@ -136,6 +136,7 @@ typedef struct { ...@@ -136,6 +136,7 @@ typedef struct {
LPWAVEHDR lpQueuePtr; LPWAVEHDR lpQueuePtr;
DWORD dwTotalRecorded; DWORD dwTotalRecorded;
WAVEINCAPSA caps; WAVEINCAPSA caps;
BOOL bTriggerSupport;
/* synchronization stuff */ /* synchronization stuff */
HANDLE hThread; HANDLE hThread;
...@@ -293,6 +294,13 @@ LONG OSS_WaveInit(void) ...@@ -293,6 +294,13 @@ LONG OSS_WaveInit(void)
#endif #endif
WInDev[0].caps.dwFormats = 0x00000000; WInDev[0].caps.dwFormats = 0x00000000;
WInDev[0].caps.wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2; WInDev[0].caps.wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
WInDev[0].bTriggerSupport = FALSE;
if (IOCTL(audio, SNDCTL_DSP_GETCAPS, caps) == 0) {
TRACE("OSS dsp in caps=%08X\n", caps);
if (caps & DSP_CAP_TRIGGER)
WInDev[0].bTriggerSupport = TRUE;
}
IOCTL(audio, SNDCTL_DSP_GETFMTS, mask); IOCTL(audio, SNDCTL_DSP_GETFMTS, mask);
TRACE("OSS in dsp mask=%08x\n", mask); TRACE("OSS in dsp mask=%08x\n", mask);
...@@ -417,7 +425,7 @@ static BOOL wodPlayer_WriteFragments(WINE_WAVEOUT* wwo) ...@@ -417,7 +425,7 @@ static BOOL wodPlayer_WriteFragments(WINE_WAVEOUT* wwo)
return FALSE; return FALSE;
} }
TRACE("Fragments %d/%d\n", info.fragments, info.fragstotal); TRACE("info={frag=%d fsize=%d ftotal=%d bytes=%d}\n", info.fragments, info.fragsize, info.fragstotal, info.bytes);
if (!info.fragments) /* output queue is full, wait a bit */ if (!info.fragments) /* output queue is full, wait a bit */
return FALSE; return FALSE;
...@@ -1695,128 +1703,154 @@ static DWORD CALLBACK widRecorder(LPVOID pmt) ...@@ -1695,128 +1703,154 @@ static DWORD CALLBACK widRecorder(LPVOID pmt)
wwi->state = WINE_WS_STOPPED; wwi->state = WINE_WS_STOPPED;
wwi->dwTotalRecorded = 0; wwi->dwTotalRecorded = 0;
TRACE("imhere[0]\n");
SetEvent(wwi->hEvent); SetEvent(wwi->hEvent);
/* make sleep time to be # of ms to output a fragment */ /* make sleep time to be # of ms to output a fragment */
dwSleepTime = (wwi->dwFragmentSize * 1000) / wwi->format.wf.nAvgBytesPerSec; dwSleepTime = (wwi->dwFragmentSize * 1000) / wwi->format.wf.nAvgBytesPerSec;
TRACE("sleeptime=%ld ms\n", dwSleepTime);
for (; ; ) {
for (; ; ) {
/* wait for dwSleepTime or an event in thread's queue */ /* wait for dwSleepTime or an event in thread's queue */
/* FIXME: could improve wait time depending on queue state, /* FIXME: could improve wait time depending on queue state,
* ie, number of queued fragments * ie, number of queued fragments
*/ */
TRACE("imhere[1]\n");
if (wwi->lpQueuePtr != NULL && wwi->state == WINE_WS_PLAYING) { if (wwi->lpQueuePtr != NULL && wwi->state == WINE_WS_PLAYING)
lpWaveHdr = wwi->lpQueuePtr; {
lpWaveHdr = wwi->lpQueuePtr;
ioctl(wwi->unixdev, SNDCTL_DSP_GETISPACE, &info); ioctl(wwi->unixdev, SNDCTL_DSP_GETISPACE, &info);
TRACE("info={frag=%d fsize=%d ftotal=%d bytes=%d}\n", info.fragments, info.fragsize, info.fragstotal, info.bytes);
if (info.fragments > 1)
{
if (lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded > wwi->dwFragmentSize) /* read all the fragments accumulated so far */
{ while ((info.fragments > 0) && (wwi->lpQueuePtr))
/* directly read fragment in wavehdr */ {
bytesRead = read(wwi->unixdev, info.fragments --;
lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
wwi->dwFragmentSize); if (lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded > wwi->dwFragmentSize)
{
/* directly read fragment in wavehdr */
bytesRead = read(wwi->unixdev,
lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
wwi->dwFragmentSize);
TRACE("bytesRead=%ld (direct)\n", bytesRead);
if (bytesRead != (DWORD) -1) if (bytesRead != (DWORD) -1)
{ {
/* update number of bytes recorded in current buffer and by this device */ /* update number of bytes recorded in current buffer and by this device */
lpWaveHdr->dwBytesRecorded += bytesRead; lpWaveHdr->dwBytesRecorded += bytesRead;
wwi->dwTotalRecorded += bytesRead; wwi->dwTotalRecorded += bytesRead;
/* buffer is full. notify client */ /* buffer is full. notify client */
if (lpWaveHdr->dwBytesRecorded == lpWaveHdr->dwBufferLength) if (lpWaveHdr->dwBytesRecorded == lpWaveHdr->dwBufferLength)
{
lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
lpWaveHdr->dwFlags |= WHDR_DONE;
if (OSS_NotifyClient(uDevID,
WIM_DATA,
(DWORD)lpWaveHdr,
lpWaveHdr->dwBytesRecorded) != MMSYSERR_NOERROR)
{ {
lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; WARN("can't notify client !\n");
lpWaveHdr->dwFlags |= WHDR_DONE;
if (OSS_NotifyClient(uDevID,
WIM_DATA,
(DWORD)lpWaveHdr,
lpWaveHdr->dwBytesRecorded) != MMSYSERR_NOERROR)
{
WARN("can't notify client !\n");
}
lpWaveHdr = wwi->lpQueuePtr = lpWaveHdr->lpNext;
} }
} lpWaveHdr = wwi->lpQueuePtr = lpWaveHdr->lpNext;
} }
else }
}
else
{ {
/* read fragment in our local buffer */ /* read the fragment in a local buffer */
bytesRead = read(wwi->unixdev, buffer, wwi->dwFragmentSize); bytesRead = read(wwi->unixdev, buffer, wwi->dwFragmentSize);
pOffset = buffer; pOffset = buffer;
/* copy data in client buffers */ TRACE("bytesRead=%ld (local)\n", bytesRead);
while (bytesRead != (DWORD) -1 && bytesRead > 0)
{ /* copy data in client buffers */
DWORD dwToCopy = min (bytesRead, lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded); while (bytesRead != (DWORD) -1 && bytesRead > 0)
{
memcpy(lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded, DWORD dwToCopy = min (bytesRead, lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded);
pOffset,
dwToCopy); memcpy(lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
pOffset,
/* update number of bytes recorded in current buffer and by this device */ dwToCopy);
lpWaveHdr->dwBytesRecorded += dwToCopy;
wwi->dwTotalRecorded += dwToCopy; /* update number of bytes recorded in current buffer and by this device */
bytesRead -= dwToCopy; lpWaveHdr->dwBytesRecorded += dwToCopy;
pOffset += dwToCopy; wwi->dwTotalRecorded += dwToCopy;
bytesRead -= dwToCopy;
pOffset += dwToCopy;
/* client buffer is full. notify client */ /* client buffer is full. notify client */
if (lpWaveHdr->dwBytesRecorded == lpWaveHdr->dwBufferLength) if (lpWaveHdr->dwBytesRecorded == lpWaveHdr->dwBufferLength)
{ {
lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
lpWaveHdr->dwFlags |= WHDR_DONE; lpWaveHdr->dwFlags |= WHDR_DONE;
if (OSS_NotifyClient(uDevID, if (OSS_NotifyClient(uDevID,
WIM_DATA, WIM_DATA,
(DWORD)lpWaveHdr, (DWORD)lpWaveHdr,
lpWaveHdr->dwBytesRecorded) != MMSYSERR_NOERROR) lpWaveHdr->dwBytesRecorded) != MMSYSERR_NOERROR)
{ {
WARN("can't notify client !\n"); WARN("can't notify client !\n");
} }
if (lpWaveHdr->lpNext) if (lpWaveHdr->lpNext)
{ {
lpWaveHdr = lpWaveHdr->lpNext; lpWaveHdr = lpWaveHdr->lpNext;
wwi->lpQueuePtr = lpWaveHdr; wwi->lpQueuePtr = lpWaveHdr;
} }
else else
{ {
/* no more buffer to copy data to, but we did read more. /* no more buffer to copy data to, but we did read more.
* what hasn't been copied will be dropped * what hasn't been copied will be dropped
*/ */
if (bytesRead) WARN("buffer over run! %lu bytes dropped.\n", bytesRead); if (bytesRead) WARN("buffer over run! %lu bytes dropped.\n", bytesRead);
wwi->lpQueuePtr = NULL; wwi->lpQueuePtr = NULL;
break; break;
} }
} }
} }
} }
} }
else {
TRACE("No data (%s)\n", strerror(errno));
}
} }
MsgWaitForMultipleObjects(0, NULL, FALSE, dwSleepTime, QS_POSTMESSAGE); MsgWaitForMultipleObjects(0, NULL, FALSE, dwSleepTime, QS_POSTMESSAGE);
TRACE("imhere[2] (q=%p)\n", wwi->lpQueuePtr);
while (PeekMessageA(&msg, 0, WINE_WM_FIRST, WINE_WM_LAST, PM_REMOVE)) { while (PeekMessageA(&msg, 0, WINE_WM_FIRST, WINE_WM_LAST, PM_REMOVE)) {
TRACE("msg=0x%x wParam=0x%x lParam=0x%lx\n", msg.message, msg.wParam, msg.lParam);
switch (msg.message) { switch (msg.message) {
case WINE_WM_PAUSING: case WINE_WM_PAUSING:
wwi->state = WINE_WS_PAUSED; wwi->state = WINE_WS_PAUSED;
/*FIXME("Device should stop recording");*/
SetEvent(wwi->hEvent); SetEvent(wwi->hEvent);
break; break;
case WINE_WM_RESTARTING: case WINE_WM_RESTARTING:
{
int enable = PCM_ENABLE_INPUT;
wwi->state = WINE_WS_PLAYING; wwi->state = WINE_WS_PLAYING;
if (wwi->bTriggerSupport)
{
/* start the recording */
if (ioctl(wwi->unixdev, SNDCTL_DSP_SETTRIGGER, &enable) < 0)
{
ERR("ioctl(SNDCTL_DSP_SETTRIGGER) failed (%d)\n", errno);
}
}
else
{
unsigned char data[4];
/* read 4 bytes to start the recording */
read(wwi->unixdev, data, 4);
}
SetEvent(wwi->hEvent); SetEvent(wwi->hEvent);
break; break;
}
case WINE_WM_HEADER: case WINE_WM_HEADER:
lpWaveHdr = (LPWAVEHDR)msg.lParam; lpWaveHdr = (LPWAVEHDR)msg.lParam;
lpWaveHdr->lpNext = 0; lpWaveHdr->lpNext = 0;
......
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