bool SoundProcessor::Record(){ SetUpRecorder(); snd_pcm_sframes_t fwdframes=snd_pcm_forwardable(handle_m); printf("forwarding %d\n",fwdframes); snd_pcm_forward(handle_m,fwdframes); while (true) { rc_m = snd_pcm_readi(handle_m, buffer_m, frames); if (rc_m == -EPIPE) { /* EPIPE means overrun */ fprintf(stderr, "overrun occurred\n"); snd_pcm_prepare(handle_m); } else if (rc_m < 0) { fprintf(stderr, "error from read: %s\n", snd_strerror(rc_m)); } else if (rc_m != (int)frames) { fprintf(stderr, "short read, read %d frames\n", rc_m); } rc_m = write(1, buffer_m, size); if (rc_m != size) fprintf(stderr, "short write: wrote %d bytes\n", rc_m); } snd_pcm_drain(handle_m); snd_pcm_close(handle_m); free(buffer_m); return true; }
static long long get_delay(void) { snd_pcm_sframes_t frames = 0; snd_pcm_delay(alsa_handle, &frames); if (frames < 0) { #if SND_LIB_VERSION >= 0x000901 /* snd_pcm_forward() exists since 0.9.0rc8 */ snd_pcm_forward(alsa_handle, -frames); #endif frames = 0; } return (long long)(frames * 1000000L / device_sample_rate); }
double CAESinkALSA::GetDelay() { if (!m_pcm) return 0; snd_pcm_sframes_t frames = 0; snd_pcm_delay(m_pcm, &frames); if (frames < 0) { #if SND_LIB_VERSION >= 0x000901 /* snd_pcm_forward() exists since 0.9.0rc8 */ snd_pcm_forward(m_pcm, -frames); #endif frames = 0; } return (double)frames * m_formatSampleRateMul; }
int audio_play_samples(struct audio_info_struct *ai, unsigned char *buf, int bytes) { snd_pcm_uframes_t frames; snd_pcm_sframes_t written; #if SND_LIB_VERSION >= 0x000901 snd_pcm_sframes_t delay; if (snd_pcm_delay(ai->handle, &delay) >= 0 && delay < 0) /* underrun - move the application pointer forward to catch up */ snd_pcm_forward(ai->handle, -delay); #endif frames = snd_pcm_bytes_to_frames(ai->handle, bytes); written = snd_pcm_writei(ai->handle, buf, frames); if (written >= 0) return snd_pcm_frames_to_bytes(ai->handle, written); else return written; }
/* delay in seconds between first and last sample in buffer */ static float get_delay(void) { if (alsa_handler) { snd_pcm_sframes_t delay; if (snd_pcm_delay(alsa_handler, &delay) < 0) return 0; if (delay < 0) { /* underrun - move the application pointer forward to catch up */ #if SND_LIB_VERSION >= 0x000901 /* snd_pcm_forward() exists since 0.9.0rc8 */ snd_pcm_forward(alsa_handler, -delay); #endif delay = 0; } return (float)delay / (float)ao_data.samplerate; } else { return 0; } }
/************************************************************************** * widRecorder [internal] */ static DWORD CALLBACK widRecorder(LPVOID pmt) { WORD uDevID = (DWORD_PTR)pmt; WINE_WAVEDEV* wwi = &WInDev[uDevID]; WAVEHDR* lpWaveHdr; DWORD dwSleepTime; DWORD bytesRead; enum win_wm_message msg; DWORD_PTR param; HANDLE ev; DWORD frames_per_period; wwi->state = WINE_WS_STOPPED; InterlockedExchange((LONG*)&wwi->dwTotalRecorded, 0); wwi->lpQueuePtr = NULL; SetEvent(wwi->hStartUpEvent); /* make sleep time to be # of ms to output a period */ dwSleepTime = (wwi->dwPeriodSize * 1000) / wwi->format.Format.nAvgBytesPerSec; frames_per_period = snd_pcm_bytes_to_frames(wwi->pcm, wwi->dwPeriodSize); TRACE("sleeptime=%d ms, total buffer length=%d ms (%d bytes)\n", dwSleepTime, wwi->dwBufferSize * 1000 / wwi->format.Format.nAvgBytesPerSec, wwi->dwBufferSize); for (;;) { /* wait for dwSleepTime or an event in thread's queue */ if (wwi->lpQueuePtr != NULL && wwi->state == WINE_WS_PLAYING) { DWORD frames; DWORD bytes; DWORD read; lpWaveHdr = wwi->lpQueuePtr; /* read all the fragments accumulated so far */ frames = snd_pcm_avail_update(wwi->pcm); bytes = snd_pcm_frames_to_bytes(wwi->pcm, frames); TRACE("frames = %d bytes = %d state=%d\n", frames, bytes, snd_pcm_state(wwi->pcm)); if (snd_pcm_state(wwi->pcm) == SND_PCM_STATE_XRUN) { FIXME("Recovering from XRUN!\n"); snd_pcm_prepare(wwi->pcm); frames = snd_pcm_avail_update(wwi->pcm); bytes = snd_pcm_frames_to_bytes(wwi->pcm, frames); snd_pcm_start(wwi->pcm); snd_pcm_forward(wwi->pcm, frames - snd_pcm_bytes_to_frames(wwi->pcm, wwi->dwPeriodSize)); continue; } while (frames > 0 && wwi->lpQueuePtr) { TRACE("bytes = %d\n", bytes); if (lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded < bytes) { bytes = lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded; frames = snd_pcm_bytes_to_frames(wwi->pcm, bytes); } /* directly read fragment in wavehdr */ read = wwi->read(wwi->pcm, lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded, frames); bytesRead = snd_pcm_frames_to_bytes(wwi->pcm, read); TRACE("bytesRead=(%d(%d)/(%d)) -> (%d/%d)\n", bytesRead, read, frames, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded); if (read != (DWORD) -1) { /* update number of bytes recorded in current buffer and by this device */ lpWaveHdr->dwBytesRecorded += bytesRead; InterlockedExchangeAdd((LONG*)&wwi->dwTotalRecorded, bytesRead); frames -= read; bytes -= bytesRead; /* buffer is full. notify client */ if (!snd_pcm_bytes_to_frames(wwi->pcm, lpWaveHdr->dwBytesRecorded - lpWaveHdr->dwBufferLength)) { /* must copy the value of next waveHdr, because we have no idea of what * will be done with the content of lpWaveHdr in callback */ LPWAVEHDR lpNext = lpWaveHdr->lpNext; lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; lpWaveHdr->dwFlags |= WHDR_DONE; wwi->lpQueuePtr = lpNext; widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0); lpWaveHdr = lpNext; } } else { WARN("read(%s, %p, %d) failed (%d/%s)\n", wwi->pcmname, lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded, frames, frames, snd_strerror(read)); } } } ALSA_WaitRingMessage(&wwi->msgRing, dwSleepTime); while (ALSA_RetrieveRingMessage(&wwi->msgRing, &msg, ¶m, &ev)) { TRACE("msg=%s param=0x%lx\n", ALSA_getCmdString(msg), param); switch (msg) { case WINE_WM_PAUSING: wwi->state = WINE_WS_PAUSED; /*FIXME("Device should stop recording\n");*/ SetEvent(ev); break; case WINE_WM_STARTING: wwi->state = WINE_WS_PLAYING; snd_pcm_start(wwi->pcm); SetEvent(ev); break; case WINE_WM_HEADER: lpWaveHdr = (LPWAVEHDR)param; lpWaveHdr->lpNext = 0; /* insert buffer at the end of queue */ { LPWAVEHDR* wh; for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext)); *wh = lpWaveHdr; } break; case WINE_WM_STOPPING: if (wwi->state != WINE_WS_STOPPED) { snd_pcm_drain(wwi->pcm); /* read any headers in queue */ widRecorder_ReadHeaders(wwi); /* return current buffer to app */ lpWaveHdr = wwi->lpQueuePtr; if (lpWaveHdr) { LPWAVEHDR lpNext = lpWaveHdr->lpNext; TRACE("stop %p %p\n", lpWaveHdr, lpWaveHdr->lpNext); lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; lpWaveHdr->dwFlags |= WHDR_DONE; wwi->lpQueuePtr = lpNext; widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0); } } wwi->state = WINE_WS_STOPPED; SetEvent(ev); break; case WINE_WM_RESETTING: if (wwi->state != WINE_WS_STOPPED) { snd_pcm_drain(wwi->pcm); } wwi->state = WINE_WS_STOPPED; wwi->dwTotalRecorded = 0; /* read any headers in queue */ widRecorder_ReadHeaders(wwi); /* return all buffers to the app */ while (wwi->lpQueuePtr) { lpWaveHdr = wwi->lpQueuePtr; TRACE("reset %p %p\n", lpWaveHdr, lpWaveHdr->lpNext); wwi->lpQueuePtr = lpWaveHdr->lpNext; lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; lpWaveHdr->dwFlags |= WHDR_DONE; widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0); } SetEvent(ev); break; case WINE_WM_CLOSING: wwi->hThread = 0; wwi->state = WINE_WS_CLOSED; SetEvent(ev); ExitThread(0); /* shouldn't go here */ default: FIXME("unknown message %d\n", msg); break; } } } ExitThread(0); /* just for not generating compilation warnings... should never be executed */ return 0; }
static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface, LPDWORD lpdwPlay, LPDWORD lpdwWrite) { IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; snd_pcm_uframes_t hw_pptr, hw_wptr; snd_pcm_state_t state; /* **** */ EnterCriticalSection(&This->pcm_crst); if (!This->pcm) { FIXME("Bad pointer for pcm: %p\n", This->pcm); LeaveCriticalSection(&This->pcm_crst); return DSERR_GENERIC; } if (!lpdwPlay && !lpdwWrite) CommitAll(This); state = snd_pcm_state(This->pcm); if (state != SND_PCM_STATE_PREPARED && state != SND_PCM_STATE_RUNNING) { CheckXRUN(This); state = snd_pcm_state(This->pcm); } if (state == SND_PCM_STATE_RUNNING) { snd_pcm_sframes_t used = This->mmap_buflen_frames - snd_pcm_avail_update(This->pcm); if (used < 0) { WARN("Underrun: %ld / %ld\n", used, snd_pcm_avail_update(This->pcm)); if (This->mmap) { snd_pcm_forward(This->pcm, -used); This->mmap_pos += -used; This->mmap_pos %= This->mmap_buflen_frames; } used = 0; } if (This->mmap_pos > used) hw_pptr = This->mmap_pos - used; else hw_pptr = This->mmap_buflen_frames + This->mmap_pos - used; hw_pptr %= This->mmap_buflen_frames; TRACE("At position: %ld (%ld) - Used %ld\n", hw_pptr, This->mmap_pos, used); } else hw_pptr = This->mmap_pos; hw_wptr = This->mmap_pos; LeaveCriticalSection(&This->pcm_crst); /* **** */ if (lpdwPlay) *lpdwPlay = snd_pcm_frames_to_bytes(This->pcm, hw_pptr); if (lpdwWrite) *lpdwWrite = snd_pcm_frames_to_bytes(This->pcm, hw_wptr); TRACE("hw_pptr=0x%08x, hw_wptr=0x%08x playpos=%d, writepos=%d\n", (unsigned int)hw_pptr, (unsigned int)hw_wptr, lpdwPlay?*lpdwPlay:-1, lpdwWrite?*lpdwWrite:-1); return DS_OK; }