// 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; } }
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; }
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; }
uint32_t AudioStreamOutALSA::latency() const { int err; int t; snd_pcm_status_t *status; snd_pcm_status_alloca(&status); if(mHandle->handle == NULL) { LOGV("handle is null, error !"); return 0; } if ((err = snd_pcm_status(mHandle->handle, status)) < 0) { LOGV("stream status error :%s\n", snd_strerror(err)); return USEC_TO_MSEC (mHandle->latency); } t = snd_pcm_status_get_delay(status); LOGV("snd_pcm_status_get_delay = %d", t); LOGV("AudioStreamOutALSA::latency = %d, sampleRate = %d", (t * 1000) / sampleRate(), sampleRate()); return (t * 1000) / sampleRate(); }
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 ((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); }
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; }
qint64 QAudioOutputPrivate::elapsedUSecs() const { if(!handle) return 0; if (deviceState == QAudio::StoppedState) return 0; #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) snd_pcm_status_t* status; snd_pcm_status_alloca(&status); snd_timestamp_t t1,t2; if( snd_pcm_status(handle, status) >= 0) { snd_pcm_status_get_tstamp(status,&t1); snd_pcm_status_get_trigger_tstamp(status,&t2); t1.tv_sec-=t2.tv_sec; signed long l = (signed long)t1.tv_usec - (signed long)t2.tv_usec; if(l < 0) { t1.tv_sec--; l = -l; l %= 1000000; } return ((t1.tv_sec * 1000000)+l); } else return 0; #else return clockStamp.elapsed()*1000; #endif return 0; }
static void DumpDeviceStatus (vlc_object_t *obj, snd_pcm_t *pcm) { snd_pcm_status_t *status; snd_pcm_status_alloca (&status); snd_pcm_status (pcm, status); Dump (obj, "current status:\n", snd_pcm_status_dump, status); }
void gettimestamp(snd_pcm_t *handle, snd_timestamp_t *timestamp) { int err; snd_pcm_status_t *status; snd_pcm_status_alloca(&status); if ((err = snd_pcm_status(handle, status)) < 0) { printf("Stream status error: %s\n", snd_strerror(err)); exit(0); } snd_pcm_status_get_trigger_tstamp(status, timestamp); }
void showstat(snd_pcm_t *handle, size_t frames) { int err; snd_pcm_status_t *status; snd_pcm_status_alloca(&status); if ((err = snd_pcm_status(handle, status)) < 0) { printf("Stream status error: %s\n", snd_strerror(err)); exit(0); } printf("*** frames = %li ***\n", (long)frames); snd_pcm_status_dump(status, output); }
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; }
void alsamm_showstat(snd_pcm_t *handle) { int err; snd_pcm_status_t *status; snd_output_t *output = NULL; snd_pcm_status_alloca(&status); if ((err = snd_pcm_status(handle, status)) < 0) { check_error(err, "Get Stream status error"); return; } snd_pcm_status_dump(status, alsa_stdout); }
static void *peeper(void *data) { int thread_no = (long)data; snd_pcm_sframes_t val; snd_pcm_status_t *stat; snd_htimestamp_t tstamp; int mode = running_mode, err; snd_pcm_status_alloca(&stat); while (running) { if (running_mode == MODE_RANDOM) mode = rand() % MODE_RANDOM; switch (mode) { case MODE_AVAIL_UPDATE: val = snd_pcm_avail_update(pcm); err = 0; break; case MODE_STATUS: err = snd_pcm_status(pcm, stat); val = snd_pcm_status_get_avail(stat); break; case MODE_HWSYNC: err = snd_pcm_hwsync(pcm); break; case MODE_TIMESTAMP: err = snd_pcm_htimestamp(pcm, (snd_pcm_uframes_t *)&val, &tstamp); break; default: err = snd_pcm_delay(pcm, &val); break; } if (quiet) continue; if (running_mode == MODE_RANDOM) { fprintf(stderr, "%d%c%s", thread_no, mode_suffix[mode], err ? "!" : ""); } else { if (show_value && mode != MODE_HWSYNC) fprintf(stderr, "\r%d ", (int)val); else fprintf(stderr, "%d%s", thread_no, err ? "!" : ""); } } return NULL; }
/* 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); }
/* how many byes are free in the buffer */ static int get_space(void) { snd_pcm_status_t *status; int ret; snd_pcm_status_alloca(&status); if ((ret = snd_pcm_status(alsa_handler, status)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_CannotGetPcmStatus, snd_strerror(ret)); return 0; } ret = snd_pcm_status_get_avail(status) * bytes_per_sample; if (ret > ao_data.buffersize) // Buffer underrun? ret = ao_data.buffersize; return ret; }
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)); } } }
/* how many byes are free in the buffer */ static int get_space(void) { snd_pcm_status_t *status; int ret; snd_pcm_status_alloca(&status); if ((ret = snd_pcm_status(alsa_handler, status)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_CannotGetPcmStatus, snd_strerror(ret)); return(0); } ret = snd_pcm_status_get_avail(status) * bytes_per_sample; if (ret > MAX_OUTBURST) ret = MAX_OUTBURST; return(ret); }
static int ao_alsa_space(alsa_ctx_t *ctx) { snd_pcm_t *alsa_handle = (snd_pcm_t *) ctx->handle; int ret; snd_pcm_status_t *status; int bytes_per_sample = ctx->bps * ctx->channels / 8; snd_pcm_status_alloca(&status); if ((ret = snd_pcm_status(alsa_handle, status)) < 0) { dt_info("%s,%d: %s\n", __FUNCTION__, __LINE__, snd_strerror(ret)); return 0; } ret = snd_pcm_status_get_avail(status) * bytes_per_sample; if (ret > ctx->buf_size) { ret = ctx->buf_size; } return ret; }
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; }
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))); }
/*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; }
void CALSAAudioSource::ProcessAudio(void) { int err; if (m_audioSrcFrameNumber == 0) { // Start the device if ((err = snd_pcm_start(m_pcmHandle)) < 0) { error_message("Couldn't start the PCM device: %s", snd_strerror(err)); } } snd_pcm_status_t *status; snd_pcm_status_alloca(&status); // for efficiency, process 1 second before returning to check for commands for (int pass = 0; pass < m_maxPasses && m_stop_thread == false; pass++) { u_int8_t* pcmFrameBuffer; pcmFrameBuffer = (u_int8_t*)malloc(m_pcmFrameSize); // The alsa frames is not the same as the pcm frames used to feed the encoder // Calculate how many alsa frames is neccesary to read to fill one pcm frame snd_pcm_uframes_t num_frames = m_pcmFrameSize / (m_audioSrcChannels * sizeof(u_int16_t)); // Check how many bytes there is to read in the buffer, it will be used to calculate timestamp snd_pcm_status(m_pcmHandle, status); unsigned long avail_bytes = snd_pcm_status_get_avail(status) * (m_audioSrcChannels * sizeof(u_int16_t)); Timestamp currentTime = GetTimestamp(); Timestamp timestamp; // Read num_frames frames from the PCM device // pointed to by pcm_handle to buffer capdata. // Returns the number of frames actually read. // TODO On certain alsa configurations, e.g. when using dsnoop with low sample rate, the period gets too small. What to do about that? snd_pcm_sframes_t framesRead; if((framesRead = snd_pcm_readi(m_pcmHandle, pcmFrameBuffer, num_frames)) == -EPIPE) { snd_pcm_prepare(m_pcmHandle); // Buffer Overrun. This means the audio buffer is full, and not capturing // we want to make the timestamp based on the previous one // When we hit this case, we start using the m_timestampOverflowArray // This will give us a timestamp for when the array is full. // // In other words, if we have a full audio buffer (ie: it's not loading // any more), we start storing the current timestamp into the array. // This will let us "catch up", and have a somewhat accurate timestamp // when we loop around // // wmay - I'm not convinced that this actually works - if the buffer // cleans up, we'll ignore m_timestampOverflowArray if (m_timestampOverflowArray != NULL && m_timestampOverflowArray[m_timestampOverflowArrayIndex] != 0) { timestamp = m_timestampOverflowArray[m_timestampOverflowArrayIndex]; } else { timestamp = m_prevTimestamp + SrcSamplesToTicks(avail_bytes); } if (m_timestampOverflowArray != NULL) m_timestampOverflowArray[m_timestampOverflowArrayIndex] = currentTime; debug_message("audio buffer full !"); } else { if (framesRead < (snd_pcm_sframes_t) num_frames) { error_message("Bad audio read. Expected %li frames, got %li", num_frames, framesRead); free(pcmFrameBuffer); continue; } // buffer is not full - so, we make the timestamp based on the number // of bytes in the buffer that we read. timestamp = currentTime - SrcSamplesToTicks(SrcBytesToSamples(avail_bytes)); if (m_timestampOverflowArray != NULL) m_timestampOverflowArray[m_timestampOverflowArrayIndex] = 0; } //debug_message("alsa read"); #ifdef DEBUG_TIMESTAMPS debug_message("avail_bytes=%lu t="U64" timestamp="U64" delta="U64, avail_bytes, currentTime, timestamp, timestamp - m_prevTimestamp); #endif m_prevTimestamp = timestamp; if (m_timestampOverflowArray != NULL) { m_timestampOverflowArrayIndex = (m_timestampOverflowArrayIndex + 1) % m_audioMaxBufferFrames; } #ifdef DEBUG_TIMESTAMPS debug_message("pcm forward "U64" %u", timestamp, m_pcmFrameSize); #endif if (m_audioSrcFrameNumber == 0 && m_videoSource != NULL) { m_videoSource->RequestKeyFrame(timestamp); } m_audioSrcFrameNumber++; CMediaFrame *frame = new CMediaFrame(PCMAUDIOFRAME, pcmFrameBuffer, m_pcmFrameSize, timestamp); ForwardFrame(frame); } }
s32 Init() { //fprintf(stderr,"* SPU2-X: Initing Alsa\n"); snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_status_t *status; int pchannels = 2; snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; handle = NULL; pcm_callback = NULL; pspeed = SAMPLE_RATE; // buffer time and period time are in microseconds... // (don't simplify the equation below -- it'll just cause integer rounding errors. period_time = (SndOutPacketSize * 1000) / (SampleRate / 1000); buffer_time = period_time * NumBuffers; int err; err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC /*| SND_PCM_NONBLOCK*/); if (err < 0) { fprintf(stderr, "Audio open error: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_nonblock(handle, 0); if (err < 0) { fprintf(stderr, "Can't set blocking mode: %s\n", snd_strerror(err)); return -1; } snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(handle, hwparams); if (err < 0) { fprintf(stderr, "Broken configuration for this PCM: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { fprintf(stderr, "Access type not available: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_format(handle, hwparams, format); if (err < 0) { fprintf(stderr, "Sample format not available: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_channels(handle, hwparams, pchannels); if (err < 0) { fprintf(stderr, "Channels count not available: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0); if (err < 0) { fprintf(stderr, "Rate not available: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0); if (err < 0) { fprintf(stderr, "Buffer time error: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0); if (err < 0) { fprintf(stderr, "Period time error: %s\n", snd_strerror(err)); return -1; } err = snd_pcm_hw_params(handle, hwparams); if (err < 0) { fprintf(stderr, "Unable to install hw params: %s\n", snd_strerror(err)); return -1; } snd_pcm_status_alloca(&status); err = snd_pcm_status(handle, status); if (err < 0) { fprintf(stderr, "Unable to get status: %s\n", snd_strerror(err)); return -1; } // Bind our asynchronous callback magic: if (handle == NULL) fprintf(stderr, "No handle."); //fprintf(stderr,"* SPU2-X:Iz setting your internal callback.\n"); // The external handler never seems to get called after this. snd_async_add_pcm_handler(&pcm_callback, handle, ExternalCallback, this); err = snd_pcm_start(handle); if (err < 0) { fprintf(stderr, "Pcm start failed: %s\n", snd_strerror(err)); return -1; } // Diagnostic code: //buffer_size = snd_pcm_status_get_avail(status); //fprintf(stderr,"All set up.\n"); return 0; }
void *CallbackThread( void *userData ) { PaAlsaStream *stream = (PaAlsaStream*)userData; pthread_cleanup_push( &Stop, stream ); // Execute Stop on exit if( stream->pcm_playback ) snd_pcm_start( stream->pcm_playback ); else if( stream->pcm_capture ) snd_pcm_start( stream->pcm_capture ); while(1) { int frames_avail; int frames_got; PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */ int callbackResult; int framesProcessed; pthread_testcancel(); { /* calculate time info */ snd_timestamp_t capture_timestamp; snd_timestamp_t playback_timestamp; snd_pcm_status_t *capture_status; snd_pcm_status_t *playback_status; snd_pcm_status_alloca( &capture_status ); snd_pcm_status_alloca( &playback_status ); if( stream->pcm_capture ) { snd_pcm_status( stream->pcm_capture, capture_status ); snd_pcm_status_get_tstamp( capture_status, &capture_timestamp ); } if( stream->pcm_playback ) { snd_pcm_status( stream->pcm_playback, playback_status ); snd_pcm_status_get_tstamp( playback_status, &playback_timestamp ); } /* Hmm, we potentially have both a playback and a capture timestamp. * Hopefully they are the same... */ if( stream->pcm_capture && stream->pcm_playback ) { float capture_time = capture_timestamp.tv_sec + ((float)capture_timestamp.tv_usec/1000000); float playback_time= playback_timestamp.tv_sec + ((float)playback_timestamp.tv_usec/1000000); if( fabsf(capture_time-playback_time) > 0.01 ) PA_DEBUG(("Capture time and playback time differ by %f\n", fabsf(capture_time-playback_time))); timeInfo.currentTime = capture_time; } else if( stream->pcm_playback ) { timeInfo.currentTime = playback_timestamp.tv_sec + ((float)playback_timestamp.tv_usec/1000000); } else { timeInfo.currentTime = capture_timestamp.tv_sec + ((float)capture_timestamp.tv_usec/1000000); } if( stream->pcm_capture ) { snd_pcm_sframes_t capture_delay = snd_pcm_status_get_delay( capture_status ); timeInfo.inputBufferAdcTime = timeInfo.currentTime - (float)capture_delay / stream->streamRepresentation.streamInfo.sampleRate; } if( stream->pcm_playback ) { snd_pcm_sframes_t playback_delay = snd_pcm_status_get_delay( playback_status ); timeInfo.outputBufferDacTime = timeInfo.currentTime + (float)playback_delay / stream->streamRepresentation.streamInfo.sampleRate; } } /* IMPLEMENT ME: - handle buffer slips */ /* depending on whether the host buffers are interleaved, non-interleaved or a mixture, you will want to call PaUtil_ProcessInterleavedBuffers(), PaUtil_ProcessNonInterleavedBuffers() or PaUtil_ProcessBuffers() here. */ framesProcessed = frames_avail = wait( stream ); while( frames_avail > 0 ) { //PA_DEBUG(( "%d frames available\n", frames_avail )); /* Now we know the soundcard is ready to produce/receive at least * one period. We just need to get the buffers for the client * to read/write. */ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* @todo pass underflow/overflow flags when necessary */ ); frames_got = setup_buffers( stream, frames_avail ); PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); callbackResult = paContinue; /* this calls the callback */ framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); /* inform ALSA how many frames we wrote */ if( stream->pcm_capture ) snd_pcm_mmap_commit( stream->pcm_capture, stream->capture_offset, frames_got ); if( stream->pcm_playback ) snd_pcm_mmap_commit( stream->pcm_playback, stream->playback_offset, frames_got ); if( callbackResult != paContinue ) break; frames_avail -= frames_got; } /* If you need to byte swap outputBuffer, you can do it here using routines in pa_byteswappers.h */ if( callbackResult != paContinue ) { stream->callback_finished = 1; stream->callbackAbort = (callbackResult == paAbort); pthread_exit( NULL ); } } /* This code is unreachable, but important to include regardless because it * is possibly a macro with a closing brace to match the opening brace in * pthread_cleanup_push() above. The documentation states that they must * always occur in pairs. */ pthread_cleanup_pop( 1 ); }
/***************************************************************************** * 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); }
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; }
void SetupSound(void) { snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_status_t *status; int pspeed; int pchannels; int format; int buffer_time; int period_time; int err; if(iDisStereo) pchannels=1; else pchannels=2; pspeed=48000; format=SND_PCM_FORMAT_S16_LE; buffer_time=500000; period_time=buffer_time/4; if((err=snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK))<0) { printf("Audio open error: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_nonblock(handle, 0))<0) { printf("Can't set blocking moded: %s\n", snd_strerror(err)); return; } snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); if((err=snd_pcm_hw_params_any(handle, hwparams))<0) { printf("Broken configuration for this PCM: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED))<0) { printf("Access type not available: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params_set_format(handle, hwparams, format))<0) { printf("Sample format not available: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params_set_channels(handle, hwparams, pchannels))<0) { printf("Channels count not available: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0))<0) { printf("Rate not available: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0))<0) { printf("Buffer time error: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0))<0) { printf("Period time error: %s\n", snd_strerror(err)); return; } if((err=snd_pcm_hw_params(handle, hwparams))<0) { printf("Unable to install hw params: %s\n", snd_strerror(err)); return; } snd_pcm_status_alloca(&status); if((err=snd_pcm_status(handle, status))<0) { printf("Unable to get status: %s\n", snd_strerror(err)); return; } buffer_size=snd_pcm_status_get_avail(status); }
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 */