static void ALSA_MMap_Submit (soundcardinfo_t *sc, int start, int end) { int state; int count = end - start; const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t nframes; snd_pcm_uframes_t offset; nframes = count / sc->sn.numchannels; psnd_pcm_avail_update (sc->handle); psnd_pcm_mmap_begin (sc->handle, &areas, &offset, &nframes); state = psnd_pcm_state (sc->handle); switch (state) { case SND_PCM_STATE_PREPARED: psnd_pcm_mmap_commit (sc->handle, offset, nframes); psnd_pcm_start (sc->handle); break; case SND_PCM_STATE_RUNNING: psnd_pcm_mmap_commit (sc->handle, offset, nframes); break; default: break; } }
static void alsa_start_capture(ALCdevice *Device) { alsa_data *data = (alsa_data*)Device->ExtraData; int err; err = psnd_pcm_start(data->pcmHandle); if(err < 0) { AL_PRINT("start failed: %s\n", psnd_strerror(err)); aluHandleDisconnect(Device); } else data->doCapture = AL_TRUE; }
static unsigned int ALSA_RW_GetDMAPos (soundcardinfo_t *sc) { int frames; frames = psnd_pcm_avail_update(sc->handle); if (frames < 0) { psnd_pcm_start (sc->handle); psnd_pcm_recover(sc->handle, frames, true); frames = psnd_pcm_avail_update(sc->handle); } if (frames >= 0) { sc->sn.samplepos = (sc->snd_sent + frames) * sc->sn.numchannels; } return sc->sn.samplepos; }
static ALuint ALSAProc(ALvoid *ptr) { ALCdevice *pDevice = (ALCdevice*)ptr; alsa_data *data = (alsa_data*)pDevice->ExtraData; const snd_pcm_channel_area_t *areas = NULL; snd_pcm_sframes_t avail, commitres; snd_pcm_uframes_t offset, frames; char *WritePtr; int err; while(!data->killNow) { int state = verify_state(data->pcmHandle); if(state < 0) { AL_PRINT("Invalid state detected: %s\n", psnd_strerror(state)); aluHandleDisconnect(pDevice); break; } avail = psnd_pcm_avail_update(data->pcmHandle); if(avail < 0) { AL_PRINT("available update failed: %s\n", psnd_strerror(avail)); continue; } // make sure there's frames to process if(avail >= 0 && avail < (snd_pcm_sframes_t)pDevice->UpdateSize) { if(state != SND_PCM_STATE_RUNNING) { err = psnd_pcm_start(data->pcmHandle); if(err < 0) { AL_PRINT("start failed: %s\n", psnd_strerror(err)); continue; } } if(psnd_pcm_wait(data->pcmHandle, 1000) == 0) AL_PRINT("Wait timeout... buffer size too low?\n"); continue; } avail -= avail%pDevice->UpdateSize; // it is possible that contiguous areas are smaller, thus we use a loop while(avail > 0) { frames = avail; err = psnd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames); if(err < 0) { AL_PRINT("mmap begin error: %s\n", psnd_strerror(err)); break; } WritePtr = (char*)areas->addr + (offset * areas->step / 8); aluMixData(pDevice, WritePtr, frames); commitres = psnd_pcm_mmap_commit(data->pcmHandle, offset, frames); if(commitres < 0 || (commitres-frames) != 0) { AL_PRINT("mmap commit error: %s\n", psnd_strerror(commitres >= 0 ? -EPIPE : commitres)); break; } avail -= frames; } } return 0; }
static ALCuint alsa_available_samples(ALCdevice *Device) { alsa_data *data = (alsa_data*)Device->ExtraData; snd_pcm_sframes_t avail; avail = (Device->Connected ? psnd_pcm_avail_update(data->pcmHandle) : 0); if(avail < 0) { AL_PRINT("avail update failed: %s\n", psnd_strerror(avail)); if((avail=psnd_pcm_recover(data->pcmHandle, avail, 1)) >= 0 && (avail=psnd_pcm_prepare(data->pcmHandle)) >= 0) { if(data->doCapture) avail = psnd_pcm_start(data->pcmHandle); if(avail >= 0) avail = psnd_pcm_avail_update(data->pcmHandle); } if(avail < 0) { AL_PRINT("restore error: %s\n", psnd_strerror(avail)); aluHandleDisconnect(Device); } } while(avail > 0) { snd_pcm_sframes_t amt; amt = psnd_pcm_bytes_to_frames(data->pcmHandle, data->size); if(avail < amt) amt = avail; amt = psnd_pcm_readi(data->pcmHandle, data->buffer, amt); if(amt < 0) { AL_PRINT("read error: %s\n", psnd_strerror(amt)); if(amt == -EAGAIN) continue; if((amt=psnd_pcm_recover(data->pcmHandle, amt, 1)) >= 0 && (amt=psnd_pcm_prepare(data->pcmHandle)) >= 0) { if(data->doCapture) amt = psnd_pcm_start(data->pcmHandle); if(amt >= 0) amt = psnd_pcm_avail_update(data->pcmHandle); } if(amt < 0) { AL_PRINT("restore error: %s\n", psnd_strerror(amt)); aluHandleDisconnect(Device); break; } avail = amt; continue; } WriteRingBuffer(data->ring, data->buffer, amt); avail -= amt; } return RingBufferSize(data->ring); }