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; }
void FFTWidget::processFFT() { int avail = snd_pcm_avail(capture_handle); if(avail<0) { fprintf (stderr, "Cannot read audio samples (%s)\n", snd_strerror (avail)); exit(1); } if(avail > (2*1024)) { short input[2*1024]; int err; if ((err = snd_pcm_readi(capture_handle, input, 1024)) != 1024) { fprintf(stderr, "read from audio interface failed (%s)\n", snd_strerror (err)); exit(1); } for(int i=0; i<1024; i++) { buffer[i]= window_function[i] * std::complex<float>(input[2*i+1], input[2*i]); } FFT::dft(buffer); update(); } }
size_t write_avail() { snd_pcm_sframes_t rc = snd_pcm_avail(pcm); if (rc < 0) { runnable = false; return 0; } return snd_pcm_frames_to_bytes(pcm, rc) / sizeof(T); }
void audio_buffer_stats(struct audio *audio, int *samples, int *stutter) { /* Accuracy is like... irrelevant */ *stutter = audio->underruns; audio->underruns = 0; *samples = snd_pcm_avail(audio->pcm); if (*samples < 0) { *samples = 0; } }
qint64 ALSAWriter::write(const QByteArray &arr) { if (!readyWrite()) return 0; const int samples = arr.size() / sizeof(float); const int to_write = samples / channels; const int bytes = samples * sample_size; if (int_samples.size() < bytes) int_samples.resize(bytes); switch (sample_size) { case 4: convert_samples((const float *)arr.constData(), samples, (qint32 *)int_samples.constData(), mustSwapChn ? channels : 0); break; case 2: convert_samples((const float *)arr.constData(), samples, (qint16 *)int_samples.constData(), mustSwapChn ? channels : 0); break; case 1: convert_samples((const float *)arr.constData(), samples, (qint8 *)int_samples.constData(), mustSwapChn ? channels : 0); break; } switch (snd_pcm_state(snd)) { case SND_PCM_STATE_XRUN: if (!snd_pcm_prepare(snd)) { const int silence = snd_pcm_avail(snd) - to_write; if (silence > 0) { QByteArray silenceArr(silence * channels * sample_size, 0); snd_pcm_writei(snd, silenceArr.constData(), silence); } } break; case SND_PCM_STATE_PAUSED: snd_pcm_pause(snd, false); break; default: break; } int ret = snd_pcm_writei(snd, int_samples.constData(), to_write); if (ret < 0 && ret != -EPIPE && snd_pcm_recover(snd, ret, false)) { QMPlay2Core.logError("ALSA :: " + tr("Playback error")); err = true; return 0; } return arr.size(); }
void sndout_alsa_wait(void) { snd_pcm_sframes_t left; while (1) { left = snd_pcm_avail(handle); if (left < 0 || left >= buffer_size / 2) break; usleep(4000); } }
static size_t alsa_write_avail(void *data) { alsa_t *alsa = (alsa_t*)data; snd_pcm_sframes_t avail = snd_pcm_avail(alsa->pcm); if (avail < 0) { //RARCH_WARN("[ALSA]: snd_pcm_avail() failed: %s\n", snd_strerror(avail)); return alsa->buffer_size; } return snd_pcm_frames_to_bytes(alsa->pcm, avail); }
static int alsa_bufferspace(void) { #ifdef HAVE_SND_PCM_AVAIL snd_pcm_sframes_t space = snd_pcm_avail(handle); #else snd_pcm_sframes_t space = snd_pcm_avail_update(handle); #endif /* keep alsa values real. Values < 0 mean errors, call to alsa_write * will resume. */ if (space < 0 || space > alsa_bufsize) space = alsa_bufsize; return space; }
inline void audio_play(char* outbuf, int samples, void* priv_data) { #ifdef DEBUGALSA snd_pcm_sframes_t avail=snd_pcm_avail (alsa_handle); syslog(LOG_DEBUG,"AUDIO_PLAY: Available buffer in ALSA:%d, Sample size %d\n",(int)avail,samples); #endif int err = snd_pcm_writei(alsa_handle, outbuf, samples); if (err < 0) { err = snd_pcm_recover(alsa_handle, err, 0); if (err < 0) syslog(LOG_DEBUG, "AUDIO_PLAY: snd_pcm_writei failed: %s\n", snd_strerror(err)); } }
unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking) { if (!m_pcm) { SoftResume(); if(!m_pcm) return 0; CLog::Log(LOGDEBUG, "CAESinkALSA - the grAEken is hunger, feed it (I am the downmost fallback - fix your code)"); } int ret; ret = snd_pcm_avail(m_pcm); if (ret < 0) { HandleError("snd_pcm_avail", ret); ret = 0; } if ((unsigned int)ret < frames) { if(blocking) { ret = snd_pcm_wait(m_pcm, m_timeout); if (ret < 0) HandleError("snd_pcm_wait", ret); } else return 0; } ret = snd_pcm_writei(m_pcm, (void*)data, frames); 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; }
BOOL auTransferData(Audio* self, snd_pcm_sframes_t (*transfer)(snd_pcm_t*, void*, snd_pcm_uframes_t)) { int numFramesTransferred = 0, error = 0; int numFramesLeft = self->bufferNumFrames; auSample_t* p = self->sampleBuffer; while((numFramesLeft > 0) && self->threadShouldContinueRunning) { error = numFramesTransferred = transfer(self->device, p, numFramesLeft); if(numFramesTransferred < 0) { //fprintf(stderr, "Audio.c: audio device error while transferring samples: %s, attempting to recover... ", snd_strerror(error)); switch(error) { case -EPIPE: //overflow / underflow snd_pcm_wait(self->device, 100); if((error = snd_pcm_avail(self->device)) < 0) //broken pipe usleep(10000); //wait for more samples to come else numFramesLeft = 0; //overrun, skip remaining samples; error = snd_pcm_prepare(self->device); break; case -ESTRPIPE: while(((error = snd_pcm_resume(self->device)) == -EAGAIN) && self->threadShouldContinueRunning) sleep(1); if(error == -ENOSYS) error = snd_pcm_prepare(self->device); break; } if(error < 0) { //fprintf(stderr, "Aborting\n"); self->threadShouldContinueRunning = NO; break; } else { //fprintf(stderr, "Okay\n"); numFramesTransferred = 0; } } p += numFramesTransferred * self->numChannels; numFramesLeft -= numFramesTransferred; } return (numFramesLeft == 0) ? YES : NO; }
void AudioProvider::update(AudioData& audioData) { audioData.channels = channels; audioData.sampleRate = sampleRate; unsigned available = std::min((unsigned) snd_pcm_avail(handle), maxFrames); audioData.samples.resize(available * channels); int status = snd_pcm_readi(handle, audioData.samples.data(), available); if(status < 0) { OUTPUT_WARNING("Lost audio stream (" << status << "), recovering..."); snd_pcm_recover(handle, status, 1); ASSERT(channels <= 4); short buf[4]; VERIFY(snd_pcm_readi(handle, buf, 1) >= 0); audioData.samples.clear(); } }
INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) { AlsaPcmInfo* info = (AlsaPcmInfo*) id; int ret; INT64 result = javaBytePos; snd_pcm_state_t state; state = snd_pcm_state(info->handle); if (state != SND_PCM_STATE_XRUN) { #ifdef GET_POSITION_METHOD2 snd_timestamp_t* ts; snd_pcm_uframes_t framesAvail; // note: slight race condition if this is called simultaneously from 2 threads ret = snd_pcm_status(info->handle, info->positionStatus); if (ret != 0) { ERROR1("ERROR in snd_pcm_status: %s\n", snd_strerror(ret)); result = javaBytePos; } else { // calculate from time value, or from available bytes framesAvail = snd_pcm_status_get_avail(info->positionStatus); result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize); } #endif #ifdef GET_POSITION_METHOD3 snd_pcm_uframes_t framesAvail; ret = snd_pcm_avail(info->handle, &framesAvail); if (ret != 0) { ERROR1("ERROR in snd_pcm_avail: %s\n", snd_strerror(ret)); result = javaBytePos; } else { result = estimatePositionFromAvail(info, isSource, javaBytePos, framesAvail * info->frameSize); } #endif #ifdef GET_POSITION_METHOD1 result = estimatePositionFromAvail(info, isSource, javaBytePos, DAUDIO_GetAvailable(id, isSource)); #endif } //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result); return result; }
unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio) { if (!m_pcm) return 0; if (snd_pcm_state(m_pcm) == SND_PCM_STATE_PREPARED) snd_pcm_start(m_pcm); int ret; ret = snd_pcm_avail(m_pcm); if (ret < 0) { HandleError("snd_pcm_avail", ret); ret = 0; } if ((unsigned int)ret < frames); { ret = snd_pcm_wait(m_pcm, m_timeout); if (ret < 0) HandleError("snd_pcm_wait", ret); } ret = snd_pcm_writei(m_pcm, (void*)data, frames); 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; } } return ret; }
static void * audio_thread(void *param) { struct pollfd *fds = NULL; nfds_t nfds = 0; static char buf[16 * 1024]; ppb_message_loop_mark_thread_unsuitable(); nfds = do_rebuild_fds(&fds); pthread_barrier_wait(&stream_list_update_barrier); if (nfds == 0) goto quit; while (1) { if (g_atomic_int_get(&terminate_thread)) goto quit; int res = poll(fds, nfds, 10 * 1000); if (res == -1) { if (errno == EINTR) continue; trace_error("%s, poll, errno=%d\n", __func__, errno); continue; } if (res == 0 || fds == NULL) continue; if (fds[0].revents) drain_wakeup_pipe(fds[0].fd); if (g_atomic_int_get(&rebuild_fds)) { nfds = do_rebuild_fds(&fds); pthread_barrier_wait(&stream_list_update_barrier); if (nfds == 0) goto quit; } for (uintptr_t k = 1; k < nfds; k ++) { unsigned short revents = 0; audio_stream *as = g_hash_table_lookup(stream_by_fd_ht, GINT_TO_POINTER(fds[k].fd)); // check if stream was deleted if (!as) continue; snd_pcm_poll_descriptors_revents(as->pcm, &fds[k], 1, &revents); if (revents & (~(POLLIN | POLLOUT))) { trace_warning("%s, revents have unexpected flags set (%u)\n", __func__, (unsigned int)revents); recover_pcm(as->pcm); } if (revents & (POLLIN | POLLOUT)) { int paused = g_atomic_int_get(&as->paused); snd_pcm_sframes_t frame_count = snd_pcm_avail(as->pcm); if (revents & POLLIN) { // POLLIN const size_t frame_size = 1 * sizeof(int16_t); // mono 16-bit const size_t max_segment_length = MIN(as->sample_frame_count * frame_size, sizeof(buf)); size_t to_process = frame_count * frame_size; while (to_process > 0) { snd_pcm_sframes_t frames_read; const size_t segment_length = MIN(to_process, max_segment_length); frames_read = snd_pcm_readi(as->pcm, buf, segment_length / frame_size); if (frames_read < 0) { trace_warning("%s, snd_pcm_readi error %d\n", __func__, (int)frames_read); recover_pcm(as->pcm); continue; } if (!paused && as->capture_cb) as->capture_cb(buf, frames_read * frame_size, 0, as->cb_user_data); to_process -= frames_read * frame_size; } } else { // POLLOUT const size_t frame_size = 2 * sizeof(int16_t); // stereo 16-bit const size_t max_segment_length = MIN(as->sample_frame_count * frame_size, sizeof(buf)); size_t to_process = frame_count * frame_size; while (to_process > 0) { snd_pcm_sframes_t frames_written; const size_t segment_length = MIN(to_process, max_segment_length); if (paused || !as->playback_cb) memset(buf, 0, segment_length); else as->playback_cb(buf, segment_length, 0, as->cb_user_data); frames_written = snd_pcm_writei(as->pcm, buf, segment_length / frame_size); if (frames_written < 0) { trace_warning("%s, snd_pcm_writei error %d\n", __func__, (int)frames_written); recover_pcm(as->pcm); continue; } to_process -= frames_written * frame_size; } } } } } quit: free(fds); return NULL; }
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; }
/** * The process callback for this JACK application. * It is called by JACK at the appropriate times. */ int process (jack_nframes_t nframes, void *arg) { int rlen; int err; snd_pcm_sframes_t delay = target_delay; int i; delay = (num_periods*period_size)-snd_pcm_avail( alsa_handle ) ; delay -= jack_frames_since_cycle_start( client ); // Do it the hard way. // this is for compensating xruns etc... if( delay > (target_delay+max_diff) ) { snd_pcm_rewind( alsa_handle, delay - target_delay ); output_new_delay = (int) delay; delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. // first look at the PI controller, this code is just a special case, which should never execute once // everything is swung in. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i<smooth_size; i++ ) offset_array[i] = 0.0; } if( delay < (target_delay-max_diff) ) { output_new_delay = (int) delay; while ((target_delay-delay) > 0) { snd_pcm_uframes_t to_write = ((target_delay-delay) > 512) ? 512 : (target_delay-delay); snd_pcm_writei( alsa_handle, tmpbuf, to_write ); delay += to_write; } delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i<smooth_size; i++ ) offset_array[i] = 0.0; } /* ok... now we should have target_delay +- max_diff on the alsa side. * * calculate the number of frames, we want to get. */ double offset = delay - target_delay; // Save offset. offset_array[(offset_differential_index++)% smooth_size ] = offset; // Build the mean of the windowed offset array // basically fir lowpassing. double smooth_offset = 0.0; for( i=0; i<smooth_size; i++ ) smooth_offset += offset_array[ (i + offset_differential_index-1) % smooth_size] * window_array[i]; smooth_offset /= (double) smooth_size; // this is the integral of the smoothed_offset offset_integral += smooth_offset; // Clamp offset. // the smooth offset still contains unwanted noise // which would go straigth onto the resample coeff. // it only used in the P component and the I component is used for the fine tuning anyways. if( fabs( smooth_offset ) < pclamp ) smooth_offset = 0.0; // ok. now this is the PI controller. // u(t) = K * ( e(t) + 1/T \int e(t') dt' ) // K = 1/catch_factor and T = catch_factor2 double current_resample_factor = static_resample_factor - smooth_offset / (double) catch_factor - offset_integral / (double) catch_factor / (double)catch_factor2; // now quantize this value around resample_mean, so that the noise which is in the integral component doesnt hurt. current_resample_factor = floor( (current_resample_factor - resample_mean) * controlquant + 0.5 ) / controlquant + resample_mean; // Output "instrumentatio" gonna change that to real instrumentation in a few. output_resampling_factor = (float) current_resample_factor; output_diff = (float) smooth_offset; output_integral = (float) offset_integral; output_offset = (float) offset; // Clamp a bit. if( current_resample_factor < resample_lower_limit ) current_resample_factor = resample_lower_limit; if( current_resample_factor > resample_upper_limit ) current_resample_factor = resample_upper_limit; // Now Calculate how many samples we need. rlen = ceil( ((double)nframes) * current_resample_factor )+2; assert( rlen > 2 ); // Calculate resample_mean so we can init ourselves to saner values. resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor; /* * now this should do it... */ outbuf = alloca( rlen * formats[format].sample_size * num_channels ); resampbuf = alloca( rlen * sizeof( float ) ); /* * render jack ports to the outbuf... */ int chn = 0; JSList *node = playback_ports; JSList *src_node = playback_srcs; SRC_DATA src; while ( node != NULL) { jack_port_t *port = (jack_port_t *) node->data; float *buf = jack_port_get_buffer (port, nframes); SRC_STATE *src_state = src_node->data; src.data_in = buf; src.input_frames = nframes; src.data_out = resampbuf; src.output_frames = rlen; src.end_of_input = 0; src.src_ratio = current_resample_factor; src_process( src_state, &src ); formats[format].jack_to_soundcard( outbuf + format[formats].sample_size * chn, resampbuf, src.output_frames_gen, num_channels*format[formats].sample_size, NULL); src_node = jack_slist_next (src_node); node = jack_slist_next (node); chn++; } // now write the output... again: err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen); //err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen); if( err < 0 ) { printf( "err = %d\n", err ); if (xrun_recovery(alsa_handle, err) < 0) { printf("Write error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } goto again; } return 0; }
void S9xAlsaSoundDriver::samples_available() { snd_pcm_sframes_t frames_written, frames; int bytes; frames = snd_pcm_avail(pcm); if (frames < 0) { frames = snd_pcm_recover(pcm, frames, 1); return; } if (Settings.DynamicRateControl) { S9xUpdateDynamicRate(snd_pcm_frames_to_bytes(pcm, frames), output_buffer_size); } int snes_frames_available = S9xGetSampleCount() >> 1; if (Settings.DynamicRateControl && !Settings.SoundSync) { // Using rate control, we should always keep the emulator's sound buffers empty to // maintain an accurate measurement. if (frames < snes_frames_available) { S9xClearSamples(); return; } } if (Settings.SoundSync && !Settings.TurboMode && !Settings.Mute) { snd_pcm_nonblock(pcm, 0); frames = snes_frames_available; } else { snd_pcm_nonblock(pcm, 1); frames = MIN(frames, snes_frames_available); } bytes = snd_pcm_frames_to_bytes(pcm, frames); if (bytes <= 0) return; if (sound_buffer_size < bytes || sound_buffer == NULL) { sound_buffer = (uint8 *)realloc(sound_buffer, bytes); sound_buffer_size = bytes; } S9xMixSamples(sound_buffer, frames * 2); frames_written = 0; while (frames_written < frames) { int result; result = snd_pcm_writei(pcm, sound_buffer + snd_pcm_frames_to_bytes(pcm, frames_written), frames - frames_written); if (result < 0) { result = snd_pcm_recover(pcm, result, 1); if (result < 0) { break; } } else { frames_written += result; } } }
static void data_available_for_stream(pa_mainloop_api *a, pa_io_event *ioe, int fd, pa_io_event_flags_t events, void *userdata) { pa_stream *s = userdata; snd_pcm_sframes_t frame_count; size_t frame_size = pa_frame_size(&s->ss); char buf[16 * 1024]; int paused = g_atomic_int_get(&s->paused); if (events & (PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT)) { #if HAVE_SND_PCM_AVAIL frame_count = snd_pcm_avail(s->ph); #else snd_pcm_hwsync(s->ph); frame_count = snd_pcm_avail_update(s->ph); #endif if (frame_count < 0) { if (frame_count == -EBADFD) { // stream was closed return; } int cnt = 0, ret; do { cnt ++; ret = snd_pcm_recover(s->ph, frame_count, 1); } while (ret == -1 && errno == EINTR && cnt < 5); #if HAVE_SND_PCM_AVAIL frame_count = snd_pcm_avail(s->ph); #else snd_pcm_hwsync(s->ph); frame_count = snd_pcm_avail_update(s->ph); #endif if (frame_count < 0) { trace_error("%s, can't recover after failed snd_pcm_avail (%d)\n", __func__, (int)frame_count); return; } } } else { return; } if (events & PA_IO_EVENT_OUTPUT) { if (paused) { // client stream is corked. Pass silence to ALSA size_t bytecnt = MIN(sizeof(buf), frame_count * frame_size); memset(buf, 0, bytecnt); snd_pcm_writei(s->ph, buf, bytecnt / frame_size); } else { size_t writable_size = pa_stream_writable_size(s); if (s->write_cb && writable_size > 0) s->write_cb(s, writable_size, s->write_cb_userdata); size_t bytecnt = MIN(sizeof(buf), frame_count * frame_size); bytecnt = ringbuffer_read(s->rb, buf, bytecnt); if (bytecnt == 0) { // application is not ready yet, play silence bytecnt = MIN(sizeof(buf), frame_count * frame_size); memset(buf, 0, bytecnt); } snd_pcm_writei(s->ph, buf, bytecnt / frame_size); } } if (events & PA_IO_EVENT_INPUT) { if (paused) { // client stream is corked. Read data from ALSA and discard them size_t bytecnt = MIN(sizeof(buf), frame_count * frame_size); snd_pcm_readi(s->ph, buf, bytecnt / frame_size); } else { size_t bytecnt = ringbuffer_writable_size(s->rb); if (bytecnt == 0) { // ringbuffer is full because app doesn't read data fast enough. // Make some room ringbuffer_drop(s->rb, frame_count * frame_size); bytecnt = ringbuffer_writable_size(s->rb); } bytecnt = MIN(bytecnt, frame_count * frame_size); bytecnt = MIN(bytecnt, sizeof(buf)); if (bytecnt > 0) { snd_pcm_readi(s->ph, buf, bytecnt / frame_size); ringbuffer_write(s->rb, buf, bytecnt); } size_t readable_size = pa_stream_readable_size(s); if (s->read_cb && readable_size > 0) s->read_cb(s, readable_size, s->read_cb_userdata); } } }
bool ALSAPCMPlayer::Start(PCMDataSource &_source) { const unsigned new_sample_rate = _source.GetSampleRate(); if ((nullptr != source) && alsa_handle && (source->GetSampleRate() == new_sample_rate)) { /* just change the source / resume playback */ bool success = false; DispatchWait(io_service, [this, &_source, &success]() { bool recovered_from_underrun = false; switch (snd_pcm_state(alsa_handle.get())) { case SND_PCM_STATE_XRUN: if (0 != snd_pcm_prepare(alsa_handle.get())) return; else { recovered_from_underrun = true; success = true; } break; case SND_PCM_STATE_RUNNING: success = true; break; default: return; } if (success) { source = &_source; if (recovered_from_underrun) { const size_t n = buffer_size / channels; const size_t n_read = FillPCMBuffer(buffer.get(), n); if (!WriteFrames(n_read)) { success = false; return; } } if (success) StartEventHandling(); } }); if (success) return true; } Stop(); assert(!alsa_handle); AlsaHandleUniquePtr new_alsa_handle = MakeAlsaHandleUniquePtr(); { const char *alsa_device = ALSAEnv::GetALSADeviceName(); snd_pcm_t *raw_alsa_handle; int alsa_error = snd_pcm_open(&raw_alsa_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, 0); if (alsa_error < 0) { LogFormat("snd_pcm_open(0x%p, \"%s\", SND_PCM_STREAM_PLAYBACK, 0) " "failed: %s", &alsa_handle, alsa_device, snd_strerror(alsa_error)); return false; } new_alsa_handle = MakeAlsaHandleUniquePtr(raw_alsa_handle); assert(new_alsa_handle); } unsigned latency = ALSAEnv::GetALSALatency(); channels = 1; bool big_endian_source = _source.IsBigEndian(); if (!SetParameters(*new_alsa_handle, new_sample_rate, big_endian_source, latency, channels)) return false; snd_pcm_sframes_t n_available = snd_pcm_avail(new_alsa_handle.get()); if (n_available <= 0) { LogFormat("snd_pcm_avail(0x%p) failed: %ld - %s", new_alsa_handle.get(), static_cast<long>(n_available), snd_strerror(static_cast<int>(n_available))); return false; } buffer_size = static_cast<snd_pcm_uframes_t>(n_available * channels); buffer = std::unique_ptr<int16_t[]>(new int16_t[buffer_size]); /* Why does Boost.Asio make it so hard to register a set of of standard poll() descriptors (struct pollfd)? */ int poll_fds_count = snd_pcm_poll_descriptors_count(new_alsa_handle.get()); if (poll_fds_count < 1) { LogFormat("snd_pcm_poll_descriptors_count(0x%p) returned %d", new_alsa_handle.get(), poll_fds_count); return false; } std::unique_ptr<struct pollfd[]> poll_fds( new struct pollfd[poll_fds_count]); BOOST_VERIFY( poll_fds_count == snd_pcm_poll_descriptors(new_alsa_handle.get(), poll_fds.get(), static_cast<unsigned>(poll_fds_count))); for (int i = 0; i < poll_fds_count; ++i) { if ((poll_fds[i].events & POLLIN) || (poll_fds[i].events & POLLPRI)) { read_poll_descs.emplace_back( boost::asio::posix::stream_descriptor(io_service, poll_fds[i].fd)); } if (poll_fds[i].events & POLLOUT) { write_poll_descs.emplace_back( boost::asio::posix::stream_descriptor(io_service, poll_fds[i].fd)); } } source = &_source; size_t n_read = FillPCMBuffer(buffer.get(), static_cast<size_t>(n_available)); if (0 == n_read) { LogFormat("ALSA PCMPlayer started with data source which " "does not deliver any data"); return false; } if (!WriteFrames(*new_alsa_handle, buffer.get(), static_cast<size_t>(n_available), false)) return false; alsa_handle = std::move(new_alsa_handle); StartEventHandling(); return true; }