static int alsa_audio_deliver(audio_decoder_t *ad, int samples, int64_t pts, int epoch) { decoder_t *d = (decoder_t *)ad; media_pipe_t *mp = ad->ad_mp; int c; retry: c = snd_pcm_wait(d->h, 100); if(c >= 0) { c = snd_pcm_avail_update(d->h); } if(c == -EPIPE) { snd_pcm_prepare(d->h); usleep(100000); TRACE(TRACE_DEBUG, "ALSA", "Audio underrun"); d->samples = 0; goto retry; } c = MIN(d->max_frames_per_write, c); uint8_t *planes[8] = {0}; planes[0] = d->tmp; c = avresample_read(ad->ad_avr, planes, c); snd_pcm_status_t *status; int err; snd_pcm_status_alloca(&status); if ((err = snd_pcm_status(d->h, status)) >= 0) { if(pts != AV_NOPTS_VALUE) { snd_htimestamp_t hts; snd_pcm_status_get_trigger_htstamp(status, &hts); int64_t ts = hts.tv_sec * 1000000LL + hts.tv_nsec / 1000; ts += d->samples * 1000000LL / ad->ad_out_sample_rate; hts_mutex_lock(&mp->mp_clock_mutex); mp->mp_audio_clock_avtime = ts; mp->mp_audio_clock = pts; mp->mp_audio_clock_epoch = epoch; hts_mutex_unlock(&mp->mp_clock_mutex); } } snd_pcm_sframes_t fr; if(!snd_pcm_delay(d->h, &fr)) ad->ad_delay = 1000000L * fr / ad->ad_out_sample_rate; c = snd_pcm_writei(d->h, d->tmp, c); d->samples += c; return 0; }
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))); }