static void play(short buf[], int samples) { int ret = 0; if (alsa_handle == NULL) { ret = open_alsa_device(); if ((ret == 0) && (audio_alsa.volume)) audio_alsa.volume(set_volume); } if (ret == 0) { pthread_mutex_lock(&alsa_mutex); snd_pcm_sframes_t current_delay = 0; int err, ignore; if ((snd_pcm_state(alsa_handle) == SND_PCM_STATE_PREPARED) || (snd_pcm_state(alsa_handle) == SND_PCM_STATE_RUNNING)) { err = snd_pcm_writei(alsa_handle, (char *)buf, samples); if (err < 0) { ignore = snd_pcm_recover(alsa_handle, err, 0); debug(1, "Error %d writing %d samples in play() %s.", err, samples, snd_strerror(err)); } } else { debug(1, "Error -- ALSA device in incorrect state (%d) for play.", snd_pcm_state(alsa_handle)); if ((err = snd_pcm_prepare(alsa_handle))) { ignore = snd_pcm_recover(alsa_handle, err, 0); debug(1, "Error preparing after play error: %s.", snd_strerror(err)); } } pthread_mutex_unlock(&alsa_mutex); } }
static uint32_t delay() { if (alsa_handle == NULL) { return 0; } else { pthread_mutex_lock(&alsa_mutex); snd_pcm_sframes_t current_avail, current_delay = 0; int derr, ignore; if (snd_pcm_state(alsa_handle) == SND_PCM_STATE_RUNNING) { derr = snd_pcm_avail_delay(alsa_handle, ¤t_avail, ¤t_delay); // current_avail not used if (derr != 0) { ignore = snd_pcm_recover(alsa_handle, derr, 0); debug(1, "Error %d in delay(): %s. Delay reported is %d frames.", derr, snd_strerror(derr), current_delay); current_delay = -1; } } else if (snd_pcm_state(alsa_handle) == SND_PCM_STATE_PREPARED) { current_delay = 0; } else { if (snd_pcm_state(alsa_handle) == SND_PCM_STATE_XRUN) current_delay = 0; else { current_delay = -1; debug(1, "Error -- ALSA delay(): bad state: %d.", snd_pcm_state(alsa_handle)); } if ((derr = snd_pcm_prepare(alsa_handle))) { ignore = snd_pcm_recover(alsa_handle, derr, 0); debug(1, "Error preparing after delay error: %s.", snd_strerror(derr)); current_delay = -1; } } pthread_mutex_unlock(&alsa_mutex); return current_delay; } }
static int verify_state(snd_pcm_t *handle) { snd_pcm_state_t state = snd_pcm_state(handle); int err; switch(state) { case SND_PCM_STATE_OPEN: case SND_PCM_STATE_SETUP: case SND_PCM_STATE_PREPARED: case SND_PCM_STATE_RUNNING: case SND_PCM_STATE_DRAINING: case SND_PCM_STATE_PAUSED: /* All Okay */ break; case SND_PCM_STATE_XRUN: if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0) return err; break; case SND_PCM_STATE_SUSPENDED: if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0) return err; break; case SND_PCM_STATE_DISCONNECTED: return -ENODEV; } return state; }
static void * audio_thread_f(void *V) { int16_t inbuf[BUFFER_SIZE], outbuf[BUFFER_SIZE]; int frames; audio_callback_t callback = (audio_callback_t) V; while (audio_thread_running) { frames = snd_pcm_readi(capture_handle, inbuf, BUFFER_SIZE); if (frames < 0) snd_pcm_recover(capture_handle, frames, 0); else if (frames != BUFFER_SIZE) fprintf(stderr, "read %d/%d frames\n", frames, BUFFER_SIZE); callback(inbuf, outbuf, BUFFER_SIZE); frames = snd_pcm_writei(playback_handle, outbuf, BUFFER_SIZE); if (frames < 0) { snd_pcm_recover(playback_handle, frames, 0); } else if (frames != BUFFER_SIZE) fprintf(stderr, "wrote %d/%d frames\n", frames, BUFFER_SIZE); } snd_pcm_drop(playback_handle); snd_pcm_close(playback_handle); snd_pcm_drop(capture_handle); snd_pcm_close(capture_handle); return NULL; }
static ALCuint alsa_available_samples(ALCdevice *Device) { alsa_data *data = (alsa_data*)Device->ExtraData; snd_pcm_sframes_t avail; avail = (Device->Connected ? snd_pcm_avail_update(data->pcmHandle) : 0); if(avail < 0) { ERR("avail update failed: %s\n", snd_strerror(avail)); if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0) { if(data->doCapture) avail = snd_pcm_start(data->pcmHandle); if(avail >= 0) avail = snd_pcm_avail_update(data->pcmHandle); } if(avail < 0) { ERR("restore error: %s\n", snd_strerror(avail)); aluHandleDisconnect(Device); } } while(avail > 0) { snd_pcm_sframes_t amt; amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size); if(avail < amt) amt = avail; amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt); if(amt < 0) { ERR("read error: %s\n", snd_strerror(amt)); if(amt == -EAGAIN) continue; if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0) { if(data->doCapture) amt = snd_pcm_start(data->pcmHandle); if(amt >= 0) amt = snd_pcm_avail_update(data->pcmHandle); } if(amt < 0) { ERR("restore error: %s\n", snd_strerror(amt)); aluHandleDisconnect(Device); break; } avail = amt; continue; } WriteRingBuffer(data->ring, data->buffer, amt); avail -= amt; } return RingBufferSize(data->ring); }
bool readFromInputDevice (AudioBuffer<float>& inputChannelBuffer, const int numSamples) { jassert (numChannelsRunning <= inputChannelBuffer.getNumChannels()); float* const* const data = inputChannelBuffer.getArrayOfWritePointers(); if (isInterleaved) { scratch.ensureSize ((size_t) ((int) sizeof (float) * numSamples * numChannelsRunning), false); scratch.fillWith (0); // (not clearing this data causes warnings in valgrind) auto num = snd_pcm_readi (handle, scratch.getData(), (snd_pcm_uframes_t) numSamples); if (num < 0) { if (num == -(EPIPE)) overrunCount++; if (JUCE_ALSA_FAILED (snd_pcm_recover (handle, (int) num, 1 /* silent */))) return false; } if (num < numSamples) JUCE_ALSA_LOG ("Did not read all samples: num: " << num << ", numSamples: " << numSamples); for (int i = 0; i < numChannelsRunning; ++i) converter->convertSamples (data[i], 0, scratch.getData(), i, numSamples); } else { auto num = snd_pcm_readn (handle, (void**) data, (snd_pcm_uframes_t) numSamples); if (num < 0) { if (num == -(EPIPE)) overrunCount++; if (JUCE_ALSA_FAILED (snd_pcm_recover (handle, (int) num, 1 /* silent */))) return false; } if (num < numSamples) JUCE_ALSA_LOG ("Did not read all samples: num: " << num << ", numSamples: " << numSamples); for (int i = 0; i < numChannelsRunning; ++i) converter->convertSamples (data[i], data[i], numSamples); } return true; }
static bool_t alsa_can_read(snd_pcm_t *dev, int frames) { snd_pcm_sframes_t avail; int err; avail = snd_pcm_avail_update(dev); ms_debug("*** %s %d %d", __FUNCTION__, (long)avail, frames); if (avail < 0) { ms_error("snd_pcm_avail_update: %s\n", snd_strerror(avail)); // most probably -EPIPE /* overrun occured, snd_pcm_state() would return SND_PCM_STATE_XRUN FIXME: handle other error conditions*/ ms_error("*** alsa_can_read fixup, trying to recover"); snd_pcm_drain(dev); /* Ignore possible error, at least -EAGAIN.*/ err = snd_pcm_recover(dev, avail, 0); if (err){ ms_error("snd_pcm_recover() failed with err %d: %s", err, snd_strerror(err)); return FALSE; } err = snd_pcm_start(dev); if (err){ ms_error("snd_pcm_start() failed with err %d: %s\n", err, snd_strerror(err)); return FALSE; } ms_message("Recovery done\n"); } return avail >= frames; }
int main(void) { int err; unsigned int i; snd_pcm_t *handle; snd_pcm_sframes_t frames; fill_buffer(buffer); if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { printf("Playback open error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } if ((err = snd_pcm_set_params(handle, SND_PCM_FORMAT_U8, SND_PCM_ACCESS_RW_INTERLEAVED, 1, 11025, 1, 500000)) < 0) { /* 0.5sec */ printf("Playback open error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } for (i = 0; i < 4; i++) { frames = snd_pcm_writei(handle, buffer, sizeof(buffer)); if (frames < 0) frames = snd_pcm_recover(handle, frames, 0); if (frames < 0) { printf("snd_pcm_writei failed: %s\n", snd_strerror(err)); break; } if (frames > 0 && frames < (long)sizeof(buffer)) printf("Short write (expected %li, wrote %li)\n", (long)sizeof(buffer), frames); } snd_pcm_close(handle); return 0; }
static void play(short buf[], int samples) { int err = snd_pcm_writei(alsa_handle, (char*)buf, samples); if (err < 0) err = snd_pcm_recover(alsa_handle, err, 0); if (err < 0) die("Failed to write to PCM device: %s\n", snd_strerror(err)); }
static int alsa_can_read(snd_pcm_t *dev) { snd_pcm_sframes_t avail; int err; alsa_resume(dev); avail = snd_pcm_avail_update(dev); /* A buggy driver does not return an error while being in Xrun */ if (avail >= 0 && snd_pcm_state(dev) == SND_PCM_STATE_XRUN) avail=-EPIPE; if (avail < 0) { ms_error("snd_pcm_avail_update: %s", snd_strerror(avail)); // most probably -EPIPE /* overrun occured, snd_pcm_state() would return SND_PCM_STATE_XRUN FIXME: handle other error conditions*/ ms_error("*** alsa_can_read fixup, trying to recover"); snd_pcm_drain(dev); /* Ignore possible error, at least -EAGAIN.*/ err = snd_pcm_recover(dev, avail, 0); if (err){ ms_error("snd_pcm_recover() failed with err %d: %s", err, snd_strerror(err)); return -1; } err = snd_pcm_start(dev); if (err){ ms_error("snd_pcm_start() failed with err %d: %s", err, snd_strerror(err)); return -1; } ms_message("Recovery done"); } return avail; }
// TODO first frame causes broken pipe (underrun) because not enough data is sent // we should wait until the handle is ready void AlsaLayer::write(SFLAudioSample* buffer, int frames, snd_pcm_t * handle) { // Skip empty buffers if (!frames) return; int err = snd_pcm_writei(handle, (const void*)buffer, frames); if (err < 0) snd_pcm_recover(handle, err, 0); if (err >= 0) return; switch (err) { case -EPIPE: case -ESTRPIPE: case -EIO: { snd_pcm_status_t* status; snd_pcm_status_alloca(&status); if (ALSA_CALL(snd_pcm_status(handle, status), "Cannot get playback handle status") >= 0) if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { stopPlaybackStream(); preparePlaybackStream(); startPlaybackStream(); } ALSA_CALL(snd_pcm_writei(handle, (const void*)buffer, frames), "XRUN handling failed"); break; } case -EBADFD: { snd_pcm_status_t* status; snd_pcm_status_alloca(&status); if (ALSA_CALL(snd_pcm_status(handle, status), "Cannot get playback handle status") >= 0) { if (snd_pcm_status_get_state(status) == SND_PCM_STATE_SETUP) { ERROR("Writing in state SND_PCM_STATE_SETUP, should be " "SND_PCM_STATE_PREPARED or SND_PCM_STATE_RUNNING"); int error = snd_pcm_prepare(handle); if (error < 0) { ERROR("Failed to prepare handle: %s", snd_strerror(error)); stopPlaybackStream(); } } } break; } default: ERROR("Unknown write error, dropping frames: %s", snd_strerror(err)); stopPlaybackStream(); break; } }
TErrors SalsaStream::read(llaAudioPipe& buffer) { if(pcm_state_ == CLOSED) { LOGGER().warning(E_READ_STREAM, "Attempt to write to a closed stream."); return E_READ_STREAM; } TErrors err; if( (err = updateSettings(buffer)) != E_OK) return err; char *iraw, **niraw; int rc; getRawInputBuffers(buffer, &iraw, &niraw); if(organization_ == SND_PCM_ACCESS_RW_NONINTERLEAVED) { rc = snd_pcm_readn(pcm_, (void**)niraw, buffer.getBufferLength()); } else { rc = snd_pcm_readi(pcm_, (void*)iraw, buffer.getBufferLength()); } setBufferLastWrite(buffer, rc); if (rc == -EPIPE) { /* EPIPE means underrun */ snd_pcm_prepare(pcm_); } else if (rc < 0) { LOGGER().warning(E_READ_STREAM, snd_strerror(rc)); snd_pcm_recover(pcm_, rc, 0); } return E_OK; }
static int xrun_recovery(snd_pcm_t *handle, int err) { err = snd_pcm_recover(handle, err, 1); if(err < 0) ERR("recover failed: %s\n", snd_strerror(err)); return err; }
ssize_t alsa_write(struct codec *c, sample_t *buf, ssize_t frames) { ssize_t n, i = 0; struct alsa_state *state = (struct alsa_state *) c->data; while (i < frames) { n = (frames - i > state->buf_frames) ? state->buf_frames : frames - i; state->enc_info->write_func(&buf[i * c->channels], state->buf, n * c->channels); try_again: n = snd_pcm_writei(state->dev, state->buf, n); if (n < 0) { if (n == -EPIPE) LOG(LL_ERROR, "dsp: alsa: warning: underrun occurred\n"); n = snd_pcm_recover(state->dev, n, 1); if (n < 0) { LOG(LL_ERROR, "dsp: alsa: error: write failed\n"); return i; } else goto try_again; } i += n; } return i; }
bool ALSAPCMPlayer::TryRecoverFromError(snd_pcm_t &alsa_handle, int error) { assert(error < 0); if (-EPIPE == error) LogFormat("ALSA PCM buffer underrun"); else if ((-EINTR == error) || (-ESTRPIPE == error)) LogFormat("ALSA PCM error: %s - trying to recover", snd_strerror(error)); else { // snd_pcm_recover() can only handle EPIPE, EINTR and ESTRPIPE LogFormat("Unrecoverable ALSA PCM error: %s", snd_strerror(error)); return false; } int recover_error = snd_pcm_recover(&alsa_handle, error, 1); if (0 == recover_error) { LogFormat("ALSA PCM successfully recovered"); return true; } else { LogFormat("snd_pcm_recover(0x%p, %d, 1) failed: %d - %s", &alsa_handle, error, recover_error, snd_strerror(recover_error)); return false; } }
unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking) { if (!m_pcm) { CLog::Log(LOGERROR, "CAESinkALSA - Tried to add packets without a sink"); return INT_MAX; } int ret = snd_pcm_writei(m_pcm, (void*)data, frames); if (ret < 0) { CLog::Log(LOGERROR, "CAESinkALSA - snd_pcm_writei(%d) %s - trying to recover", ret, snd_strerror(ret)); ret = snd_pcm_recover(m_pcm, ret, 1); if(ret < 0) { HandleError("snd_pcm_writei(1)", ret); ret = snd_pcm_writei(m_pcm, (void*)data, frames); if (ret < 0) { HandleError("snd_pcm_writei(2)", ret); ret = 0; } } } if ( ret > 0 && snd_pcm_state(m_pcm) == SND_PCM_STATE_PREPARED) snd_pcm_start(m_pcm); return ret; }
int QAudioOutputPrivate::bytesFree() const { if(resuming) return period_size; if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) return 0; int frames = snd_pcm_avail_update(handle); if (frames == -EPIPE) { // Try and handle buffer underrun int err = snd_pcm_recover(handle, frames, 0); if (err < 0) return 0; else frames = snd_pcm_avail_update(handle); } else if (frames < 0) { return 0; } if ((int)frames > (int)buffer_frames) frames = buffer_frames; return snd_pcm_frames_to_bytes(handle, frames); }
static void recover_maybe(struct audio *audio) { if (audio->err < 0) { audio->err = snd_pcm_recover(audio->pcm, audio->err, 1); audio->underruns++; } }
/* Read as far as you can (when in non-blocking mode) or until our * buffer is filled (when in blocking mode). */ int audioRead(void) { if (sound.reprepare) { int ret; ret = snd_pcm_drop(sound.handle); if (ret < 0) { fprintf(stderr, "Error while dropping samples: %s\n", snd_strerror(ret)); } ret = snd_pcm_prepare(sound.handle); if (ret < 0) { fprintf(stderr, "Error while preparing to record: %s\n", snd_strerror(ret)); } sound.reprepare = 0; } /* Request * "size - fill" frames * starting at * "base + numFramesFilled * 2" bytes. * Do "* 2" because we get two bytes per sample. * * When in blocking mode, this always fills the buffer to its * maximum capacity. */ snd_pcm_sframes_t rc; rc = snd_pcm_readi(sound.handle, sound.buffer + (sound.bufferFill * 2), sound.bufferSizeFrames - sound.bufferFill); if (rc == -EPIPE) { /* EPIPE means overrun */ snd_pcm_recover(sound.handle, rc, 0); } else if (rc == -EAGAIN) { /* Not ready yet. Come back again later. */ } else if (rc < 0) { fprintf(stderr, "error from read: %s\n", snd_strerror(rc)); } else { sound.bufferFill += rc; if (sound.bufferFill == sound.bufferSizeFrames) { /* Buffer full. display() can add this to the history. */ sound.bufferFill = 0; sound.bufferReady = 1; } } return rc; }
void* reader_thread(void* param) { int i=0; snd_pcm_sframes_t frames; while (1) { sem_wait(&g_empty_cnt_sem); frames = snd_pcm_readi( g_handle_rec, g_rec_buffers[i], NUM_SAMPLES ); if (frames < 0) { printf("snd_pcm_readi failed: %s\n", snd_strerror(frames)); frames = snd_pcm_recover(g_handle_rec, frames, 0); } if (frames < 0) { printf("snd_pcm_recover failed: %s\n", snd_strerror(frames)); break; } if ((frames > 0) && (frames < NUM_SAMPLES)) printf("Short read (expected %d, read %ld)\n", NUM_SAMPLES, frames); sem_post(&g_full_cnt_sem); i = (i+1) % NUM_BUFFERS; } return NULL; }
size_t audio_write(const void* data, size_t amount) { int err; amount /= 4; for(;;) { err = snd_pcm_writei(playback_handle, data, amount); if(err == -EAGAIN) return 0; if(err < 0) { err = snd_pcm_recover(playback_handle, err, 0); if(err < 0) errx(EXIT_FAILURE, "Audio playback failed: %s", strerror(-err)); } break; } written += err; err *= 4; return err; }
int sndout_alsa_write_nb(const void *samples, int len) { snd_pcm_sframes_t left; int ret; len /= 2; if (channels == 2) len /= 2; left = snd_pcm_avail(handle); if (left >= 0 && left < len) return 0; ret = snd_pcm_writei(handle, samples, len); if (ret < 0) { ret = snd_pcm_recover(handle, ret, 1); if (ret != 0 && failure_counter++ < 5) fprintf(stderr, PFX "snd_pcm_recover: %d\n", ret); if (silent_period) snd_pcm_writei(handle, silent_period, period_size); snd_pcm_writei(handle, samples, len); } return len; }
mp_sint32 AudioDriver_ALSA::start() { const snd_pcm_channel_area_t *my_areas; snd_pcm_uframes_t offset, frames, size; snd_async_handler_t *ahandler; int err; err = snd_async_add_pcm_handler(&ahandler, pcm, async_direct_callback, this); if (err < 0) { fprintf(stderr, "ALSA: Unable to register async handler (%s)\n", snd_strerror(err)); } for (int count = 0; count < 2; count++) { size = period_size; while (size > 0) { frames = size; err = snd_pcm_mmap_begin(pcm, &my_areas, &offset, &frames); if (err < 0) { if ((err = snd_pcm_recover(pcm, err, 0)) < 0) { fprintf(stderr, "ALSA: MMAP begin error: %s\n", snd_strerror(err)); } } // Sanity check if (my_areas->step != 32 && my_areas->first != 0) fprintf(stderr, "ALSA: Unsupported audio format.\n"); memset(static_cast<char*> (my_areas->addr) + offset*4, 0, frames * 4); int commitres = snd_pcm_mmap_commit(pcm, offset, frames); if (err < 0 || (snd_pcm_uframes_t)commitres != frames) { if ((err = snd_pcm_recover(pcm, commitres >= 0 ? -EPIPE : commitres, 0)) < 0) { fprintf(stderr, "ALSA: MMAP commit error: %s\n", snd_strerror(err)); } } size -= frames; } } \ err = snd_pcm_start(pcm); if (err < 0) { fprintf(stderr, "ALSA: Could not start PCM device (%s)\n", snd_strerror(err)); return -1; } deviceHasStarted = true; return 0; }
void AudioDriverALSA::thread_func(void* p_udata) { AudioDriverALSA* ad = (AudioDriverALSA*)p_udata; while (!ad->exit_thread) { if (!ad->active) { for (unsigned int i=0; i < ad->period_size*ad->channels; i++) { ad->samples_out[i] = 0; }; } else { ad->lock(); ad->audio_server_process(ad->period_size, ad->samples_in); ad->unlock(); for(unsigned int i=0;i<ad->period_size*ad->channels;i++) { ad->samples_out[i]=ad->samples_in[i]>>16; } }; int todo = ad->period_size; int total = 0; while (todo) { if (ad->exit_thread) break; uint8_t* src = (uint8_t*)ad->samples_out; int wrote = snd_pcm_writei(ad->pcm_handle, (void*)(src + (total*ad->channels)), todo); if (wrote < 0) { if (ad->exit_thread) break; if ( wrote == -EAGAIN ) { //can't write yet (though this is blocking..) usleep(1000); continue; } wrote = snd_pcm_recover(ad->pcm_handle, wrote, 0); if ( wrote < 0 ) { //absolute fail fprintf(stderr, "ALSA failed and can't recover: %s\n", snd_strerror(wrote)); ad->active=false; ad->exit_thread=true; break; } continue; }; total += wrote; todo -= wrote; }; }; ad->thread_exited=true; };
static void* audin_alsa_thread_func(void* arg) { int error; uint8* buffer; int rbytes_per_frame; int tbytes_per_frame; snd_pcm_t* capture_handle = NULL; AudinALSADevice* alsa = (AudinALSADevice*) arg; DEBUG_DVC("in"); rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_channel; tbytes_per_frame = alsa->target_channels * alsa->bytes_per_channel; alsa->buffer = (uint8*) xzalloc(tbytes_per_frame * alsa->frames_per_packet); alsa->buffer_frames = 0; buffer = (uint8*) xzalloc(rbytes_per_frame * alsa->frames_per_packet); memset(&alsa->adpcm, 0, sizeof(ADPCM)); do { if ((error = snd_pcm_open(&capture_handle, alsa->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0) { DEBUG_WARN("snd_pcm_open (%s)", snd_strerror(error)); break; } if (!audin_alsa_set_params(alsa, capture_handle)) { break; } while (!freerdp_thread_is_stopped(alsa->thread)) { error = snd_pcm_readi(capture_handle, buffer, alsa->frames_per_packet); if (error == -EPIPE) { snd_pcm_recover(capture_handle, error, 0); continue; } else if (error < 0) { DEBUG_WARN("snd_pcm_readi (%s)", snd_strerror(error)); break; } if (!audin_alsa_thread_receive(alsa, buffer, error * rbytes_per_frame)) break; } } while (0); xfree(buffer); xfree(alsa->buffer); alsa->buffer = NULL; if (capture_handle) snd_pcm_close(capture_handle); freerdp_thread_quit(alsa->thread); DEBUG_DVC("out"); return NULL; }
static void pcm_play (unsigned char* buff, int size) { snd_pcm_sframes_t frames = snd_pcm_writei(handle, buff, size); if (frames < 0) { frames = snd_pcm_recover(handle, frames, 0); } }
static void recover_pcm(snd_pcm_t *pcm) { switch (snd_pcm_state(pcm)) { case SND_PCM_STATE_XRUN: snd_pcm_recover(pcm, -EPIPE, 1); break; case SND_PCM_STATE_SUSPENDED: snd_pcm_recover(pcm, -ESTRPIPE, 1); break; default: snd_pcm_drop(pcm); snd_pcm_prepare(pcm); break; } }
static void play(snd_pcm_t *playback_handle, const unsigned char* buf, size_t s) { int ret = snd_pcm_writei(playback_handle, buf, s); if (ret<0) { DPRINTF(2, "write to audio interface failed (%s)\n", snd_strerror(ret)); snd_pcm_state_t state = snd_pcm_state(playback_handle); DPRINTF(2, "%s\n", getstatus_string(state)); if(state == SND_PCM_STATE_XRUN) snd_pcm_recover(playback_handle, ret, 1); } }
int main(int argc, char **argv) { char *buf; int i, err; if (parse_options(argc, argv)) return 1; err = snd_pcm_open(&pcm, devname, stream, 0); if (err < 0) { fprintf(stderr, "cannot open pcm %s\n", devname); return 1; } if (setup_params()) return 1; buf = calloc(1, snd_pcm_format_size(format, bufsize) * channels); if (!buf) { fprintf(stderr, "cannot alloc buffer\n"); return 1; } for (i = 0; i < num_threads; i++) { if (pthread_create(&peeper_threads[i], NULL, peeper, (void *)(long)i)) { fprintf(stderr, "pthread_create error\n"); return 1; } } if (stream == SND_PCM_STREAM_CAPTURE) snd_pcm_start(pcm); for (;;) { int size = rand() % (bufsize / 2); if (stream == SND_PCM_STREAM_PLAYBACK) err = snd_pcm_writei(pcm, buf, size); else err = snd_pcm_readi(pcm, buf, size); if (err < 0) { fprintf(stderr, "read/write error %d\n", err); err = snd_pcm_recover(pcm, err, 0); if (err < 0) break; if (stream == SND_PCM_STREAM_CAPTURE) snd_pcm_start(pcm); } } running = 0; for (i = 0; i < num_threads; i++) pthread_cancel(peeper_threads[i]); for (i = 0; i < num_threads; i++) pthread_join(peeper_threads[i], NULL); return 1; }
static ALuint ALSANoMMapProc(ALvoid *ptr) { ALCdevice *Device = (ALCdevice*)ptr; alsa_data *data = (alsa_data*)Device->ExtraData; snd_pcm_sframes_t avail; char *WritePtr; SetRTPriority(); while(!data->killNow) { int state = verify_state(data->pcmHandle); if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); aluHandleDisconnect(Device); break; } WritePtr = data->buffer; avail = data->size / snd_pcm_frames_to_bytes(data->pcmHandle, 1); aluMixData(Device, WritePtr, avail); while(avail > 0) { int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail); switch (ret) { case -EAGAIN: continue; case -ESTRPIPE: case -EPIPE: case -EINTR: ret = snd_pcm_recover(data->pcmHandle, ret, 1); if(ret < 0) avail = 0; break; default: if (ret >= 0) { WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret); avail -= ret; } break; } if (ret < 0) { ret = snd_pcm_prepare(data->pcmHandle); if(ret < 0) break; } } } return 0; }