// I/O error handler static void xrun(void) { snd_pcm_status_t *status; int res; snd_pcm_status_alloca(&status); if ((res = snd_pcm_status(handle, status))<0) { error(_("status error: %s"), snd_strerror(res)); exit(EXIT_FAILURE); } if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { struct timeval now, diff, tstamp; gettimeofday(&now, 0); snd_pcm_status_get_trigger_tstamp(status, &tstamp); timersub(&now, &tstamp, &diff); fprintf(stderr, _("%s!!! (at least %.3f ms long)\n"), stream == SND_PCM_STREAM_PLAYBACK ? _("underrun") : _("overrun"), diff.tv_sec * 1000 + diff.tv_usec / 1000.0); if ((res = snd_pcm_prepare(handle))<0) { error(_("xrun: prepare error: %s"), snd_strerror(res)); exit(EXIT_FAILURE); } return; // ok, data should be accepted again } if (snd_pcm_status_get_state(status) == SND_PCM_STATE_DRAINING) { } error(_("read/write error, state = %s"), snd_pcm_state_name(snd_pcm_status_get_state(status))); exit(EXIT_FAILURE); }
// 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; } }
static void xrun(void) { snd_pcm_status_t *status; int res; snd_pcm_status_alloca(&status); if ((res = snd_pcm_status(AHandle, status)) < 0) { fprintf(stderr, "status error: %s", snd_strerror(res)); exit(EXIT_FAILURE); } if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { struct timeval now, diff, tstamp; gettimeofday(&now, 0); snd_pcm_status_get_trigger_tstamp(status, &tstamp); timersub(&now, &tstamp, &diff); fprintf(stderr, "Underrun!!! (at least %.3f ms long)\n", diff.tv_sec * 1000 + diff.tv_usec / 1000.0); if ((res = snd_pcm_prepare(AHandle)) < 0) { fprintf(stderr, "xrun: prepare error: %s", snd_strerror(res)); exit(EXIT_FAILURE); } return; // ok, data should be accepted // again } fprintf(stderr, "read/write error, state = %s", snd_pcm_state_name(snd_pcm_status_get_state(status))); exit(EXIT_FAILURE); }
/* I/O error handler */ static void xrun(void) { snd_pcm_status_t *status; int res; snd_pcm_status_alloca(&status); if ((res = snd_pcm_status(handle, status))<0) { error("status error: %s", snd_strerror(res)); exit(EXIT_FAILURE); } if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { struct timeval now, diff, tstamp; gettimeofday(&now, 0); snd_pcm_status_get_trigger_tstamp(status, &tstamp); timersub(&now, &tstamp, &diff); fprintf(stderr, "%s!!! (at least %.3f ms long)\n", stream == SND_PCM_STREAM_PLAYBACK ? "underrun" : "overrun", diff.tv_sec * 1000 + diff.tv_usec / 1000.0); if (verbose) { fprintf(stderr, "Status:\n"); snd_pcm_status_dump(status, log); } if ((res = snd_pcm_prepare(handle))<0) { error("xrun: prepare error: %s", snd_strerror(res)); exit(EXIT_FAILURE); } return; /* ok, data should be accepted again */ } if (snd_pcm_status_get_state(status) == SND_PCM_STATE_DRAINING) { if (verbose) { fprintf(stderr, "Status(DRAINING):\n"); snd_pcm_status_dump(status, log); } if (stream == SND_PCM_STREAM_CAPTURE) { fprintf(stderr, "capture stream format change? attempting recover...\n"); if ((res = snd_pcm_prepare(handle))<0) { error("xrun(DRAINING): prepare error: %s", snd_strerror(res)); exit(EXIT_FAILURE); } return; } } if (verbose) { fprintf(stderr, "Status(R/W):\n"); snd_pcm_status_dump(status, log); } error("read/write error, state = %s", snd_pcm_state_name(snd_pcm_status_get_state(status))); exit(EXIT_FAILURE); }
int ai_alsa_xrun(audio_in_t *ai) { snd_pcm_status_t *status; int res; snd_pcm_status_alloca(&status); if ((res = snd_pcm_status(ai->alsa.handle, status))<0) { mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA status error: %s", snd_strerror(res)); return -1; } if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { struct timeval now, diff, tstamp; gettimeofday(&now, 0); snd_pcm_status_get_trigger_tstamp(status, &tstamp); timersub(&now, &tstamp, &diff); mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA xrun!!! (at least %.3f ms long)\n", diff.tv_sec * 1000 + diff.tv_usec / 1000.0); if (mp_msg_test(MSGT_TV, MSGL_V)) { mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA Status:\n"); snd_pcm_status_dump(status, ai->alsa.log); } if ((res = snd_pcm_prepare(ai->alsa.handle))<0) { mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA xrun: prepare error: %s", snd_strerror(res)); return -1; } return 0; /* ok, data should be accepted again */ } mp_tmsg(MSGT_TV, MSGL_ERR, "ALSA read/write error"); return -1; }
int ai_alsa_xrun(audio_in_t *ai) { snd_pcm_status_t *status; int res; snd_pcm_status_alloca(&status); if ((res = snd_pcm_status(ai->alsa.handle, status))<0) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatusError, snd_strerror(res)); return -1; } if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { struct timeval now, diff, tstamp; gettimeofday(&now, 0); snd_pcm_status_get_trigger_tstamp(status, &tstamp); timersub(&now, &tstamp, &diff); mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUN, diff.tv_sec * 1000 + diff.tv_usec / 1000.0); if (mp_msg_test(MSGT_TV, MSGL_V)) { mp_msg(MSGT_TV, MSGL_ERR, "ALSA Status:\n"); snd_pcm_status_dump(status, ai->alsa.log); } if ((res = snd_pcm_prepare(ai->alsa.handle))<0) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUNPrepareError, snd_strerror(res)); return -1; } return 0; /* ok, data should be accepted again */ } mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaReadWriteError); return -1; }
static int log_state(ALSA_CARD *card) { // log card state snd_pcm_status_t *status; snd_pcm_state_t state; const char *state_str; snd_pcm_status_alloca(&status); snd_pcm_status(card->handle, status); state = snd_pcm_status_get_state(status); switch (state) { case SND_PCM_STATE_RUNNING: state_str = "running"; break; case SND_PCM_STATE_XRUN: state_str = "overrun"; break; case SND_PCM_STATE_DRAINING: state_str = "draining"; break; case SND_PCM_STATE_PAUSED: state_str = "paused"; break; case SND_PCM_STATE_SUSPENDED: state_str = "suspended"; break; case SND_PCM_STATE_DISCONNECTED: state_str = "disconnected"; break; default: state_str = "other"; } log_msg("ALSA: state: %s [%d]\n", state_str, (int)state); return state; }
static GstClockTime gst_alsasrc_get_timestamp (GstAlsaSrc * asrc) { snd_pcm_status_t *status; snd_htimestamp_t tstamp; GstClockTime timestamp; snd_pcm_uframes_t avail; gint err = -EPIPE; if (G_UNLIKELY (!asrc)) { GST_ERROR_OBJECT (asrc, "No alsa handle created yet !"); return GST_CLOCK_TIME_NONE; } if (G_UNLIKELY (snd_pcm_status_malloc (&status) != 0)) { GST_ERROR_OBJECT (asrc, "snd_pcm_status_malloc failed"); return GST_CLOCK_TIME_NONE; } if (G_UNLIKELY (snd_pcm_status (asrc->handle, status) != 0)) { GST_ERROR_OBJECT (asrc, "snd_pcm_status failed"); return GST_CLOCK_TIME_NONE; } /* in case an xrun condition has occured we need to handle this */ if (snd_pcm_status_get_state (status) != SND_PCM_STATE_RUNNING) { if (xrun_recovery (asrc, asrc->handle, err) < 0) { GST_WARNING_OBJECT (asrc, "Could not recover from xrun condition !"); } /* reload the status alsa status object, since recovery made it invalid */ if (G_UNLIKELY (snd_pcm_status (asrc->handle, status) != 0)) { GST_ERROR_OBJECT (asrc, "snd_pcm_status failed"); } } /* get high resolution time stamp from driver */ snd_pcm_status_get_htstamp (status, &tstamp); timestamp = GST_TIMESPEC_TO_TIME (tstamp); /* max available frames sets the depth of the buffer */ avail = snd_pcm_status_get_avail (status); /* calculate the timestamp of the next sample to be read */ timestamp -= gst_util_uint64_scale_int (avail, GST_SECOND, asrc->rate); /* compensate for the fact that we really need the timestamp of the * previously read data segment */ timestamp -= asrc->period_time * 1000; snd_pcm_status_free (status); GST_LOG_OBJECT (asrc, "ALSA timestamp : %" GST_TIME_FORMAT ", delay %lu", GST_TIME_ARGS (timestamp), avail); return timestamp; }
static void xrun(void) { snd_pcm_status_t *status; int res; snd_pcm_status_alloca(&status); if ((res = snd_pcm_status(AHandle, status))<0) { fprintf(stderr, "status error: %s", snd_strerror(res)); return; } if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { if (monotonic) { #ifdef HAVE_CLOCK_GETTIME struct timespec now, diff, tstamp; clock_gettime(CLOCK_MONOTONIC, &now); snd_pcm_status_get_trigger_htstamp(status, &tstamp); timermsub(&now, &tstamp, &diff); fprintf(stderr, _("%s!!! (at least %.3f ms long)\n"), stream == SND_PCM_STREAM_PLAYBACK ? _("underrun") : _("overrun"), diff.tv_sec * 1000 + diff.tv_nsec / 10000000.0); #else fprintf(stderr, "%s !!!\n", "underrun"); #endif } else { struct timeval now, diff, tstamp; gettimeofday(&now, 0); snd_pcm_status_get_trigger_tstamp(status, &tstamp); timersub(&now, &tstamp, &diff); fprintf(stderr, "%s!!! (at least %.3f ms long)\n", "Underrun", diff.tv_sec * 1000 + diff.tv_usec / 1000.0); } if ((res = snd_pcm_prepare(AHandle))<0) { fprintf(stderr, "xrun: prepare error: %s", snd_strerror(res)); /* we should probably die here */ return; } return; /* ok, data should be accepted again */ } fprintf(stderr, "read/write error, state = %s", snd_pcm_state_name(snd_pcm_status_get_state(status))); }
static void alsa_resume(snd_pcm_t *handle){ int err; snd_pcm_status_t *status=NULL; snd_pcm_status_alloca(&status); if ((err=snd_pcm_status(handle,status))!=0){ ms_warning("snd_pcm_status() failed: %s",snd_strerror(err)); return; } if (snd_pcm_status_get_state(status)==SND_PCM_STATE_SUSPENDED){ ms_warning("Maybe suspended, trying resume"); if ((err=snd_pcm_resume(handle))!=0){ if (err!=EWOULDBLOCK) ms_warning("snd_pcm_resume() failed: %s",snd_strerror(err)); } } }
int AlsaLayer::read(SFLAudioSample* buffer, int frames) { if (snd_pcm_state(captureHandle_) == SND_PCM_STATE_XRUN) { prepareCaptureStream(); startCaptureStream(); } int err = snd_pcm_readi(captureHandle_, (void*)buffer, frames); if (err >= 0) return err; switch (err) { case -EPIPE: case -ESTRPIPE: case -EIO: { snd_pcm_status_t* status; snd_pcm_status_alloca(&status); if (ALSA_CALL(snd_pcm_status(captureHandle_, status), "Get status failed") >= 0) if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { stopCaptureStream(); prepareCaptureStream(); startCaptureStream(); } ERROR("XRUN capture ignored (%s)", snd_strerror(err)); break; } case -EPERM: ERROR("Can't capture, EPERM (%s)", snd_strerror(err)); prepareCaptureStream(); startCaptureStream(); break; } return 0; }
/*a@nufront start*/ void AudioStreamInALSA::xrun(snd_pcm_t * handle) { snd_pcm_status_t *status; int res; ZJFLOGD("function in."); snd_pcm_status_alloca(&status); if ((res = snd_pcm_status(handle, status))<0) { ZJFLOGE("status error: %s", snd_strerror(res)); return; } if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { struct timeval now, diff, tstamp; gettimeofday(&now, 0); snd_pcm_status_get_trigger_tstamp(status, &tstamp); timersub(&now, &tstamp, &diff); ZJFLOGE("overrun!!! (at least %.3f ms long)", diff.tv_sec * 1000 + diff.tv_usec / 1000.0); } ZJFLOGD("function out."); return; }
int main(int argc, char *argv[]) { const char *dev; int r, cap, count = 0; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_status_t *status; snd_pcm_t *pcm; unsigned rate = 44100; unsigned periods = 2; snd_pcm_uframes_t boundary, buffer_size = 44100/10; /* 100s */ int dir = 1; struct timespec start, last_timestamp = { 0, 0 }; uint64_t start_us, last_us = 0; snd_pcm_sframes_t last_avail = 0, last_delay = 0; struct pollfd *pollfds; int n_pollfd; int64_t sample_count = 0; struct sched_param sp; r = -1; #ifdef _POSIX_PRIORITY_SCHEDULING sp.sched_priority = 5; r = pthread_setschedparam(pthread_self(), SCHED_RR, &sp); #endif if (r) printf("Could not get RT prio. :(\n"); snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); snd_pcm_status_alloca(&status); r = clock_gettime(CLOCK_MONOTONIC, &start); assert(r == 0); start_us = timespec_us(&start); dev = argc > 1 ? argv[1] : "front:AudioPCI"; cap = argc > 2 ? atoi(argv[2]) : 0; if (cap == 0) r = snd_pcm_open(&pcm, dev, SND_PCM_STREAM_PLAYBACK, 0); else r = snd_pcm_open(&pcm, dev, SND_PCM_STREAM_CAPTURE, 0); assert(r == 0); r = snd_pcm_hw_params_any(pcm, hwparams); assert(r == 0); r = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 0); assert(r == 0); r = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); assert(r == 0); r = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE); assert(r == 0); r = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, NULL); assert(r == 0); r = snd_pcm_hw_params_set_channels(pcm, hwparams, 2); assert(r == 0); r = snd_pcm_hw_params_set_periods_integer(pcm, hwparams); assert(r == 0); r = snd_pcm_hw_params_set_periods_near(pcm, hwparams, &periods, &dir); assert(r == 0); r = snd_pcm_hw_params_set_buffer_size_near(pcm, hwparams, &buffer_size); assert(r == 0); r = snd_pcm_hw_params(pcm, hwparams); assert(r == 0); r = snd_pcm_hw_params_current(pcm, hwparams); assert(r == 0); r = snd_pcm_sw_params_current(pcm, swparams); assert(r == 0); if (cap == 0) r = snd_pcm_sw_params_set_avail_min(pcm, swparams, 1); else r = snd_pcm_sw_params_set_avail_min(pcm, swparams, 0); assert(r == 0); r = snd_pcm_sw_params_set_period_event(pcm, swparams, 0); assert(r == 0); r = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); assert(r == 0); r = snd_pcm_sw_params_set_start_threshold(pcm, swparams, buffer_size); assert(r == 0); r = snd_pcm_sw_params_get_boundary(swparams, &boundary); assert(r == 0); r = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary); assert(r == 0); r = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE); assert(r == 0); r = snd_pcm_sw_params(pcm, swparams); assert(r == 0); r = snd_pcm_prepare(pcm); assert(r == 0); r = snd_pcm_sw_params_current(pcm, swparams); assert(r == 0); /* assert(snd_pcm_hw_params_is_monotonic(hwparams) > 0); */ n_pollfd = snd_pcm_poll_descriptors_count(pcm); assert(n_pollfd > 0); pollfds = malloc(sizeof(struct pollfd) * n_pollfd); assert(pollfds); r = snd_pcm_poll_descriptors(pcm, pollfds, n_pollfd); assert(r == n_pollfd); printf("Starting. Buffer size is %u frames\n", (unsigned int) buffer_size); if (cap) { r = snd_pcm_start(pcm); assert(r == 0); } for (;;) { snd_pcm_sframes_t avail, delay; struct timespec now, timestamp; unsigned short revents; int handled = 0; uint64_t now_us, timestamp_us; snd_pcm_state_t state; unsigned long long pos; r = poll(pollfds, n_pollfd, 0); assert(r >= 0); r = snd_pcm_poll_descriptors_revents(pcm, pollfds, n_pollfd, &revents); assert(r == 0); if (cap == 0) assert((revents & ~POLLOUT) == 0); else assert((revents & ~POLLIN) == 0); avail = snd_pcm_avail(pcm); assert(avail >= 0); r = snd_pcm_status(pcm, status); assert(r == 0); /* This assertion fails from time to time. ALSA seems to be broken */ /* assert(avail == (snd_pcm_sframes_t) snd_pcm_status_get_avail(status)); */ /* printf("%lu %lu\n", (unsigned long) avail, (unsigned long) snd_pcm_status_get_avail(status)); */ snd_pcm_status_get_htstamp(status, ×tamp); delay = snd_pcm_status_get_delay(status); state = snd_pcm_status_get_state(status); r = clock_gettime(CLOCK_MONOTONIC, &now); assert(r == 0); assert(!revents || avail > 0); if ((!cap && avail) || (cap && (unsigned)avail >= buffer_size)) { snd_pcm_sframes_t sframes; static const uint16_t psamples[2] = { 0, 0 }; uint16_t csamples[2]; if (cap == 0) sframes = snd_pcm_writei(pcm, psamples, 1); else sframes = snd_pcm_readi(pcm, csamples, 1); assert(sframes == 1); handled = 1; sample_count++; } if (!handled && memcmp(×tamp, &last_timestamp, sizeof(timestamp)) == 0 && avail == last_avail && delay == last_delay) { /* This is boring */ continue; } now_us = timespec_us(&now); timestamp_us = timespec_us(×tamp); if (cap == 0) pos = (unsigned long long) ((sample_count - handled - delay) * 1000000LU / 44100); else pos = (unsigned long long) ((sample_count - handled + delay) * 1000000LU / 44100); if (count++ % 50 == 0) printf("Elapsed\tCPU\tALSA\tPos\tSamples\tavail\tdelay\trevents\thandled\tstate\n"); printf("%llu\t%llu\t%llu\t%llu\t%llu\t%li\t%li\t%i\t%i\t%i\n", (unsigned long long) (now_us - last_us), (unsigned long long) (now_us - start_us), (unsigned long long) (timestamp_us ? timestamp_us - start_us : 0), pos, (unsigned long long) sample_count, (signed long) avail, (signed long) delay, revents, handled, state); if (cap == 0) /** When this assert is hit, most likely something bad * happened, i.e. the avail jumped suddenly. */ assert((unsigned) avail <= buffer_size); last_avail = avail; last_delay = delay; last_timestamp = timestamp; last_us = now_us; } return 0; }
static int alsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels) { static int epipe_count = 0 ; int total = 0 ; int retval ; if (epipe_count > 0) epipe_count -- ; while (total < frames) { retval = snd_pcm_writei (alsa_dev, data + total * channels, frames - total) ; if (retval >= 0) { total += retval ; if (total == frames) return total ; continue ; } ; switch (retval) { case -EAGAIN : puts ("alsa_write_float: EAGAIN") ; continue ; break ; case -EPIPE : if (epipe_count > 0) { printf ("alsa_write_float: EPIPE %d\n", epipe_count) ; if (epipe_count > 140) return retval ; } ; epipe_count += 100 ; #if 0 if (0) { snd_pcm_status_t *status ; snd_pcm_status_alloca (&status) ; if ((retval = snd_pcm_status (alsa_dev, status)) < 0) fprintf (stderr, "alsa_out: xrun. can't determine length\n") ; else if (snd_pcm_status_get_state (status) == SND_PCM_STATE_XRUN) { struct timeval now, diff, tstamp ; gettimeofday (&now, 0) ; snd_pcm_status_get_trigger_tstamp (status, &tstamp) ; timersub (&now, &tstamp, &diff) ; fprintf (stderr, "alsa_write_float xrun: of at least %.3f msecs. resetting stream\n", diff.tv_sec * 1000 + diff.tv_usec / 1000.0) ; } else fprintf (stderr, "alsa_write_float: xrun. can't determine length\n") ; } ; #endif snd_pcm_prepare (alsa_dev) ; break ; case -EBADFD : fprintf (stderr, "alsa_write_float: Bad PCM state.n") ; return 0 ; break ; case -ESTRPIPE : fprintf (stderr, "alsa_write_float: Suspend event.n") ; return 0 ; break ; case -EIO : puts ("alsa_write_float: EIO") ; return 0 ; default : fprintf (stderr, "alsa_write_float: retval = %d\n", retval) ; return 0 ; break ; } ; /* switch */ } ; /* while */ return total ; } /* alsa_write_float */
/*---------------------------------------------------------------------- | AlsaOutput_Write +---------------------------------------------------------------------*/ static BLT_Result AlsaOutput_Write(AlsaOutput* self, void* buffer, BLT_Size size) { int watchdog = 5; int io_result; unsigned int sample_count; unsigned int sample_size; BLT_Result result; /* ensure that the device is prepared */ result = AlsaOutput_Prepare(self); if (BLT_FAILED(result)) return result; /* compute the number of samples */ sample_size = self->media_type.channel_count*self->media_type.bits_per_sample/8; sample_count = size / sample_size; /* write samples to the device and handle underruns */ do { while (sample_count) { io_result = snd_pcm_writei(self->device_handle, buffer, sample_count); if (io_result > 0) { buffer = (void*)((char*)buffer + io_result*sample_size); if ((unsigned int)io_result <= sample_count) { sample_count -= io_result; } else { /* strange, snd_pcm_writei returned more than we wrote */ sample_count = 0; } } else { break; } } if (sample_count == 0) return BLT_SUCCESS; /* we reach this point if the first write failed */ if (io_result < 0) { snd_pcm_status_t* status; snd_pcm_state_t state; snd_pcm_status_alloca_no_assert(&status); io_result = snd_pcm_status(self->device_handle, status); if (io_result != 0) { return BLT_FAILURE; } state = snd_pcm_status_get_state(status); if (state == SND_PCM_STATE_XRUN) { ATX_LOG_FINE("**** UNDERRUN *****"); /* re-prepare the channel */ io_result = snd_pcm_prepare(self->device_handle); if (io_result != 0) { return BLT_FAILURE; } } else { ATX_LOG_WARNING_1("**** STATE = %d ****", state); } } else { ATX_LOG_WARNING_1("snd_pcm_writei() returned %d", io_result); } ATX_LOG_FINE("**** RETRY *****"); } while(watchdog--); ATX_LOG_SEVERE("**** THE WATCHDOG BIT US ****"); return BLT_FAILURE; }
/***************************************************************************** * ALSAFill: function used to fill the ALSA buffer as much as possible *****************************************************************************/ static void ALSAFill( aout_instance_t * p_aout ) { struct aout_sys_t * p_sys = p_aout->output.p_sys; snd_pcm_t *p_pcm = p_sys->p_snd_pcm; snd_pcm_status_t * p_status; int i_snd_rc; mtime_t next_date; int canc = vlc_savecancel(); /* Fill in the buffer until space or audio output buffer shortage */ /* Get the status */ snd_pcm_status_alloca(&p_status); i_snd_rc = snd_pcm_status( p_pcm, p_status ); if( i_snd_rc < 0 ) { msg_Err( p_aout, "cannot get device status" ); goto error; } /* Handle buffer underruns and get the status again */ if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN ) { /* Prepare the device */ i_snd_rc = snd_pcm_prepare( p_pcm ); if( i_snd_rc ) { msg_Err( p_aout, "cannot recover from buffer underrun" ); goto error; } msg_Dbg( p_aout, "recovered from buffer underrun" ); /* Get the new status */ i_snd_rc = snd_pcm_status( p_pcm, p_status ); if( i_snd_rc < 0 ) { msg_Err( p_aout, "cannot get device status after recovery" ); goto error; } /* Underrun, try to recover as quickly as possible */ next_date = mdate(); } else { /* Here the device should be in RUNNING state, p_status is valid. */ snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status ); if( delay == 0 ) /* workaround buggy alsa drivers */ if( snd_pcm_delay( p_pcm, &delay ) < 0 ) delay = 0; /* FIXME: use a positive minimal delay */ size_t i_bytes = snd_pcm_frames_to_bytes( p_pcm, delay ); mtime_t delay_us = CLOCK_FREQ * i_bytes / p_aout->output.output.i_bytes_per_frame / p_aout->output.output.i_rate * p_aout->output.output.i_frame_length; #ifdef ALSA_DEBUG snd_pcm_state_t state = snd_pcm_status_get_state( p_status ); if( state != SND_PCM_STATE_RUNNING ) msg_Err( p_aout, "pcm status (%d) != RUNNING", state ); msg_Dbg( p_aout, "Delay is %ld frames (%zu bytes)", delay, i_bytes ); msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame ); msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate ); msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length ); msg_Dbg( p_aout, "Next date: in %"PRId64" microseconds", delay_us ); #endif next_date = mdate() + delay_us; } block_t *p_buffer = aout_OutputNextBuffer( p_aout, next_date, (p_aout->output.output.i_format == VLC_CODEC_SPDIFL) ); /* Audio output buffer shortage -> stop the fill process and wait */ if( p_buffer == NULL ) goto error; for (;;) { int n = snd_pcm_poll_descriptors_count(p_pcm); struct pollfd ufd[n]; unsigned short revents; snd_pcm_poll_descriptors(p_pcm, ufd, n); do { vlc_restorecancel(canc); poll(ufd, n, -1); canc = vlc_savecancel(); snd_pcm_poll_descriptors_revents(p_pcm, ufd, n, &revents); } while(!revents); if(revents & POLLOUT) { i_snd_rc = snd_pcm_writei( p_pcm, p_buffer->p_buffer, p_buffer->i_nb_samples ); if( i_snd_rc != -ESTRPIPE ) break; } /* a suspend event occurred * (stream is suspended and waiting for an application recovery) */ msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." ); while( ( i_snd_rc = snd_pcm_resume( p_pcm ) ) == -EAGAIN ) { vlc_restorecancel(canc); msleep(CLOCK_FREQ); /* device still suspended, wait... */ canc = vlc_savecancel(); } if( i_snd_rc < 0 ) /* Device does not support resuming, restart it */ i_snd_rc = snd_pcm_prepare( p_pcm ); } if( i_snd_rc < 0 ) msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) ); vlc_restorecancel(canc); block_Release( p_buffer ); return; error: if( i_snd_rc < 0 ) msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) ); vlc_restorecancel(canc); msleep(p_sys->i_period_time / 2); }
/***************************************************************************** * ALSAFill: function used to fill the ALSA buffer as much as possible *****************************************************************************/ static void ALSAFill( aout_instance_t * p_aout ) { struct aout_sys_t * p_sys = p_aout->output.p_sys; aout_buffer_t * p_buffer; snd_pcm_status_t * p_status = p_sys->p_status; int i_snd_rc; mtime_t next_date; /* Fill in the buffer until space or audio output buffer shortage */ /* Get the status */ i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status ); if( i_snd_rc < 0 ) { msg_Err( p_aout, "cannot get device status" ); goto error; } /* Handle buffer underruns and get the status again */ if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN ) { /* Prepare the device */ i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm ); if( i_snd_rc ) { msg_Err( p_aout, "cannot recover from buffer underrun" ); goto error; } msg_Dbg( p_aout, "recovered from buffer underrun" ); /* Get the new status */ i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status ); if( i_snd_rc < 0 ) { msg_Err( p_aout, "cannot get device status after recovery" ); goto error; } /* Underrun, try to recover as quickly as possible */ next_date = mdate(); } else { /* Here the device should be in RUNNING state, p_status is valid. */ snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status ); if( delay == 0 ) /* workaround buggy alsa drivers */ if( snd_pcm_delay( p_sys->p_snd_pcm, &delay ) < 0 ) delay = 0; /* FIXME: use a positive minimal delay */ int i_bytes = snd_pcm_frames_to_bytes( p_sys->p_snd_pcm, delay ); next_date = mdate() + ( (mtime_t)i_bytes * 1000000 / p_aout->output.output.i_bytes_per_frame / p_aout->output.output.i_rate * p_aout->output.output.i_frame_length ); #ifdef ALSA_DEBUG snd_pcm_state_t state = snd_pcm_status_get_state( p_status ); if( state != SND_PCM_STATE_RUNNING ) msg_Err( p_aout, "pcm status (%d) != RUNNING", state ); msg_Dbg( p_aout, "Delay is %ld frames (%d bytes)", delay, i_bytes ); msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame ); msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate ); msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length ); msg_Dbg( p_aout, "Next date is in %d microseconds", (int)(next_date - mdate()) ); #endif } p_buffer = aout_OutputNextBuffer( p_aout, next_date, (p_aout->output.output.i_format == VLC_CODEC_SPDIFL) ); /* Audio output buffer shortage -> stop the fill process and wait */ if( p_buffer == NULL ) goto error; for (;;) { i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer, p_buffer->i_nb_samples ); if( i_snd_rc != -ESTRPIPE ) break; /* a suspend event occurred * (stream is suspended and waiting for an application recovery) */ msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." ); while( vlc_object_alive (p_aout) && vlc_object_alive (p_aout->p_libvlc) && ( i_snd_rc = snd_pcm_resume( p_sys->p_snd_pcm ) ) == -EAGAIN ) { msleep( 1000000 ); } if( i_snd_rc < 0 ) /* Device does not supprot resuming, restart it */ i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm ); } if( i_snd_rc < 0 ) msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) ); aout_BufferFree( p_buffer ); return; error: if( i_snd_rc < 0 ) msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) ); msleep( p_sys->i_period_time >> 1 ); }