static ALCuint alsa_available_samples(ALCdevice *Device) { alsa_data *data = (alsa_data*)Device->ExtraData; snd_pcm_sframes_t avail; avail = (Device->Connected ? snd_pcm_avail_update(data->pcmHandle) : 0); if(avail < 0) { ERR("avail update failed: %s\n", snd_strerror(avail)); if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0) { if(data->doCapture) avail = snd_pcm_start(data->pcmHandle); if(avail >= 0) avail = snd_pcm_avail_update(data->pcmHandle); } if(avail < 0) { ERR("restore error: %s\n", snd_strerror(avail)); aluHandleDisconnect(Device); } } while(avail > 0) { snd_pcm_sframes_t amt; amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size); if(avail < amt) amt = avail; amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt); if(amt < 0) { ERR("read error: %s\n", snd_strerror(amt)); if(amt == -EAGAIN) continue; if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0) { if(data->doCapture) amt = snd_pcm_start(data->pcmHandle); if(amt >= 0) amt = snd_pcm_avail_update(data->pcmHandle); } if(amt < 0) { ERR("restore error: %s\n", snd_strerror(amt)); aluHandleDisconnect(Device); break; } avail = amt; continue; } WriteRingBuffer(data->ring, data->buffer, amt); avail -= amt; } return RingBufferSize(data->ring); }
static int drvHostALSAAudioGetAvail(snd_pcm_t *phPCM, snd_pcm_sframes_t *pFramesAvail) { AssertPtrReturn(phPCM, VERR_INVALID_POINTER); AssertPtrReturn(pFramesAvail, VERR_INVALID_POINTER); int rc; snd_pcm_sframes_t framesAvail; framesAvail = snd_pcm_avail_update(phPCM); if (framesAvail < 0) { if (framesAvail == -EPIPE) { rc = drvHostALSAAudioRecover(phPCM); if (RT_SUCCESS(rc)) framesAvail = snd_pcm_avail_update(phPCM); } else rc = VERR_ACCESS_DENIED; /** @todo Find a better rc. */ } else rc = VINF_SUCCESS; if (framesAvail >= 0) *pFramesAvail = framesAvail; return rc; }
int QAudioOutputPrivate::bytesFree() const { if(resuming) return period_size; if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) return 0; int frames = snd_pcm_avail_update(handle); if (frames == -EPIPE) { // Try and handle buffer underrun int err = snd_pcm_recover(handle, frames, 0); if (err < 0) return 0; else frames = snd_pcm_avail_update(handle); } else if (frames < 0) { return 0; } if ((int)frames > (int)buffer_frames) frames = buffer_frames; return snd_pcm_frames_to_bytes(handle, frames); }
void write( const char *data, qint64 len ) { if ( !handle ) return; int count=0; qLog(QAudioOutput)<<"frames to write out = "<< snd_pcm_bytes_to_frames( handle, (int)len )<<" ("<<len<<") bytes"; while ( len > 0 ) { int err=0; int frames = snd_pcm_bytes_to_frames( handle, (int)len ); #ifdef ALSA_USE_AVAILABLE if(frames < (int)period_size) return; int available = snd_pcm_avail_update(handle); qLog(QAudioOutput) <<"available space = "<<available; if(available == 0) { while(available < frames) { snd_pcm_wait(handle,period_size/1000); usleep(period_size*10); available = snd_pcm_avail_update(handle); qLog(QAudioOutput) <<"->available space = "<<available; count++; if((count > 5)||(available < 0)) return; } } #endif err = snd_pcm_writei( handle, data, frames ); // Handle errors if ( err >= 0 ) { if(err == 0) count++; int bytes = snd_pcm_frames_to_bytes( handle, err ); qLog(QAudioOutput) << QString("write out = %1").arg(bytes).toLatin1().constData(); data += bytes; len -= bytes; } else { count++; qLog(QAudioOutput) <<"err = "<<err; err = xrun_recovery(err); } if(count > 5) { qLog(QAudioOutput) <<"failing to write, close() and re-open() to try and recover!"; close(); open(); snd_pcm_prepare(handle); break; } } }
void *speaker_thread(void* ptr){ audiobuffer* buf = ((spk_pcm_package*)ptr)->buffer; //cast pointer, get buffer struct snd_pcm_t* speaker_handle = ((spk_pcm_package*)ptr)->pcm_handle; //cast pointer, get device pointer free(ptr); //free message memory snd_pcm_nonblock(speaker_handle, SND_PCM_NONBLOCK); //set in nonblocking mode char started = 0; //track when to start reading data while(!global_kill && !speaker_kill_flag) { //loop until program stops us //wait until adequate buffer is achieved and can be written if((!started && BUFFER_SIZE(*buf) < (MIN_BUFFER)) \ || BUFFER_EMPTY(*buf) \ || !snd_pcm_avail_update(speaker_handle)) { //printf("Speaker Waiting\n"); usleep(PERIOD_UTIME*2); //wait to reduce CPU usage continue; //don't start yet } else { if(!started) snd_pcm_prepare(speaker_handle); //reset speaker started = 1; //indicate that we've startd } //write data to speaker buffer, check responses int write_count = MIN(BUFFER_SIZE(*buf), snd_pcm_avail_update(speaker_handle)/(buf->period)); #ifdef DEBUG_MODE printf("Writing %d packets to speaker\n", write_count); #endif //loop over avaliable buffer entries while(write_count-- > 0 && started){ /* Note: This call performs a syscall to copy data to kernel space so it would be better to write multiple entries in one operation, but using the audiobuffer without the abstraction was something I didn't want to do at the time of writing. */ int rc = snd_pcm_writei(speaker_handle, GET_QUEUE_HEAD(*buf), buf->period); INC_QUEUE_HEAD(*buf); if (rc == -EPIPE){ //Catch underruns (not enough data) fprintf(stderr, "underrun occurred\n"); started = 0; //stop and wait for buffer to buildup } else if (rc < 0) fprintf(stderr, "error from writei: %s\n", snd_strerror(rc)); //other errors else if (rc != (int)buf->period) fprintf(stderr, "short write, write %d frames\n", rc); //else fprintf(stderr, "audio written correctly\n"); //snd_pcm_wait(speaker_handle, 1000); //wait for IO to be ready } #ifdef DEBUG_MODE printf("%d unwritten\n", write_count); #endif } // notify kernel to empty/close the speakers snd_pcm_drain(speaker_handle); //finish transferring the audio snd_pcm_close(speaker_handle); //close the device printf("Audio Controller: Speaker Thread shutdown\n"); pthread_exit(NULL); //exit thread safetly }
/************************************************************************** * wodPlayer_FeedDSP [internal] * Feed as much sound data as we can into the DSP and return the number of * milliseconds before it will be necessary to feed the DSP again. */ static DWORD wodPlayer_FeedDSP(WINE_WAVEDEV* wwo) { DWORD availInQ; wodUpdatePlayedTotal(wwo, NULL); availInQ = snd_pcm_avail_update(wwo->pcm); /* no more room... no need to try to feed */ if (availInQ > 0) { /* Feed from partial wavehdr */ if (wwo->lpPlayPtr && wwo->dwPartialOffset != 0) { wodPlayer_WriteMaxFrags(wwo, &availInQ); } /* Feed wavehdrs until we run out of wavehdrs or DSP space */ if (wwo->dwPartialOffset == 0 && wwo->lpPlayPtr) { do { TRACE("Setting time to elapse for %p to %u\n", wwo->lpPlayPtr, wwo->dwWrittenTotal + wwo->lpPlayPtr->dwBufferLength); /* note the value that dwPlayedTotal will return when this wave finishes playing */ wwo->lpPlayPtr->reserved = wwo->dwWrittenTotal + wwo->lpPlayPtr->dwBufferLength; } while (wodPlayer_WriteMaxFrags(wwo, &availInQ) && wwo->lpPlayPtr && availInQ > 0); } } return wodPlayer_DSPWait(wwo); }
/* from PA */ static snd_pcm_sframes_t alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const StreamSpec& ss) { snd_pcm_sframes_t n; size_t k; /* Some ALSA drivers expose weird bugs, let's inform the user about what is going on */ n = snd_pcm_avail_update(pcm); if (n <= 0) return n; k = (size_t) n * ss.FrameBytes(); if (k >= hwbuf_size * 5 || k >= ss.BytesPerSecond() * 10) { // Print this on console to allow users to report their driver. printf("snd_pcm_avail_update() returned a value that is exceptionally large: %lu bytes (%lu ms).\n" "Most likely this is a bug in the ALSA driver. Please report this issue to the ALSA developers.\n", (unsigned long) k, (unsigned long) ss.FramesToMs(k / ss.FrameBytes())); /* Mhmm, let's try not to fail completely */ n = (snd_pcm_sframes_t) (hwbuf_size / ss.FrameBytes()); } return n; }
static int alsa_can_read(snd_pcm_t *dev) { snd_pcm_sframes_t avail; int err; alsa_resume(dev); avail = snd_pcm_avail_update(dev); /* A buggy driver does not return an error while being in Xrun */ if (avail >= 0 && snd_pcm_state(dev) == SND_PCM_STATE_XRUN) avail=-EPIPE; if (avail < 0) { ms_error("snd_pcm_avail_update: %s", snd_strerror(avail)); // most probably -EPIPE /* overrun occured, snd_pcm_state() would return SND_PCM_STATE_XRUN FIXME: handle other error conditions*/ ms_error("*** alsa_can_read fixup, trying to recover"); snd_pcm_drain(dev); /* Ignore possible error, at least -EAGAIN.*/ err = snd_pcm_recover(dev, avail, 0); if (err){ ms_error("snd_pcm_recover() failed with err %d: %s", err, snd_strerror(err)); return -1; } err = snd_pcm_start(dev); if (err){ ms_error("snd_pcm_start() failed with err %d: %s", err, snd_strerror(err)); return -1; } ms_message("Recovery done"); } return avail; }
static bool_t alsa_can_read(snd_pcm_t *dev, int frames) { snd_pcm_sframes_t avail; int err; avail = snd_pcm_avail_update(dev); ms_debug("*** %s %d %d", __FUNCTION__, (long)avail, frames); if (avail < 0) { ms_error("snd_pcm_avail_update: %s\n", snd_strerror(avail)); // most probably -EPIPE /* overrun occured, snd_pcm_state() would return SND_PCM_STATE_XRUN FIXME: handle other error conditions*/ ms_error("*** alsa_can_read fixup, trying to recover"); snd_pcm_drain(dev); /* Ignore possible error, at least -EAGAIN.*/ err = snd_pcm_recover(dev, avail, 0); if (err){ ms_error("snd_pcm_recover() failed with err %d: %s", err, snd_strerror(err)); return FALSE; } err = snd_pcm_start(dev); if (err){ ms_error("snd_pcm_start() failed with err %d: %s\n", err, snd_strerror(err)); return FALSE; } ms_message("Recovery done\n"); } return avail >= frames; }
static HRESULT WINAPI IDsDriverBufferImpl_Stop(PIDSDRIVERBUFFER iface) { const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t avail; snd_pcm_format_t format; IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; TRACE("(%p)\n",iface); /* **** */ EnterCriticalSection(&This->pcm_crst); avail = This->mmap_buflen_frames; snd_pcm_drop(This->pcm); snd_pcm_prepare(This->pcm); avail = snd_pcm_avail_update(This->pcm); snd_pcm_hw_params_get_format(This->hw_params, &format); if (This->mmap) { snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &avail); snd_pcm_format_set_silence(format, areas->addr, This->mmap_buflen_frames); snd_pcm_mmap_commit(This->pcm, This->mmap_pos, 0); } else { snd_pcm_format_set_silence(format, This->mmap_buffer, This->mmap_buflen_frames); snd_pcm_writei(This->pcm, This->mmap_buffer, This->mmap_buflen_frames); This->mmap_pos = 0; } /* **** */ LeaveCriticalSection(&This->pcm_crst); return DS_OK; }
/** Fill buffers, for starting and stopping * Alsa won't start playing until everything is filled up * This also updates mmap_pos * * Returns: Amount of periods in use so snd_pcm_avail_update * doesn't have to be called up to 4x in GetPosition() */ static snd_pcm_uframes_t CommitAll(IDsDriverBufferImpl *This) { const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t used; const snd_pcm_uframes_t commitahead = This->mmap_commitahead; used = This->mmap_buflen_frames - snd_pcm_avail_update(This->pcm); TRACE("%p needs to commit to %lu, used: %lu\n", This, commitahead, used); if (used < commitahead) { snd_pcm_uframes_t done, putin = commitahead - used; snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin); done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin); This->mmap_pos += done; used += done; putin = commitahead - used; if (This->mmap_pos == This->mmap_buflen_frames && (snd_pcm_sframes_t)putin > 0) { snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin); done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin); This->mmap_pos += done; used += done; } } if (This->mmap_pos == This->mmap_buflen_frames) This->mmap_pos = 0; return used; }
/************************************************************************** * wodUpdatePlayedTotal [internal] * */ static BOOL wodUpdatePlayedTotal(WINE_WAVEDEV* wwo, snd_pcm_status_t* ps) { snd_pcm_sframes_t delay; snd_pcm_sframes_t avail; snd_pcm_uframes_t buf_size = 0; snd_pcm_state_t state; state = snd_pcm_state(wwo->pcm); avail = snd_pcm_avail_update(wwo->pcm); snd_pcm_hw_params_get_buffer_size(wwo->hw_params, &buf_size); delay = buf_size - avail; if (state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED) { WARN("Unexpected state (%d) while updating Total Played, resetting\n", state); wine_snd_pcm_recover(wwo->pcm, -EPIPE, 0); delay=0; } /* A delay < 0 indicates an underrun; for our purposes that's 0. */ if (delay < 0) { WARN("Unexpected delay (%ld) while updating Total Played, resetting\n", delay); delay=0; } InterlockedExchange((LONG*)&wwo->dwPlayedTotal, wwo->dwWrittenTotal - snd_pcm_frames_to_bytes(wwo->pcm, delay)); return TRUE; }
// Invoked by the static ExternalCallback method below. void _InternalCallback() { snd_pcm_sframes_t avail; fprintf(stderr, "* SPU2-X:Iz in your internal callback.\n"); avail = snd_pcm_avail_update(handle); while (avail >= (int)period_time) { StereoOut16 buff[PacketsPerBuffer * SndOutPacketSize]; StereoOut16 *p1 = buff; for (int p = 0; p < PacketsPerBuffer; p++, p1 += SndOutPacketSize) SndBuffer::ReadSamples(p1); snd_pcm_writei(handle, buff, period_time); avail = snd_pcm_avail_update(handle); } }
void play_audio(float* xmbuffer, float* alsabuffer) { snd_pcm_sframes_t avail; while((avail = snd_pcm_avail_update(device)) >= period_size) { xm_generate_samples(xmctx, xmbuffer, period_size >> 1); play_floatbuffer(device, format, period_size, 1.f, xmbuffer, alsabuffer); } }
eU32 tfAlsa::getPlayBufferlen() { if (m_handle == NULL) return 0; eU32 len = snd_pcm_avail_update(m_handle); //printf("%i\n", len); return len; }
int AudioInputALSA::PcmRead(void* buf, uint nbytes) { unsigned char* bufptr = (unsigned char*)buf; snd_pcm_uframes_t to_read = snd_pcm_bytes_to_frames(pcm_handle, nbytes); snd_pcm_uframes_t nframes = to_read; snd_pcm_sframes_t nread, avail; int retries = 0; while (nframes > 0 && retries < 3) { if (AlsaBad((avail = snd_pcm_avail_update(pcm_handle)), "available update failed")) { if (!Recovery(avail)) { ++retries; continue; } } if ((nread = snd_pcm_readi(pcm_handle, bufptr, nframes)) < 0) { switch (nread) { case -EAGAIN: break; case -EBADFD: LOG(VB_GENERAL, LOG_ERR, LOC_DEV + QString("in a state unfit to read (%1): %2") .arg(nread).arg(snd_strerror(nread))); break; case -EINTR: case -EPIPE: case -ESTRPIPE: Recovery(nread); break; default: LOG(VB_GENERAL, LOG_ERR, LOC_DEV + QString("weird return from snd_pcm_readi: %1") .arg(snd_strerror(nread))); break; } } else { nframes -= nread; bufptr += snd_pcm_frames_to_bytes(pcm_handle, nread); } ++retries; } if (nframes > 0) LOG(VB_AUDIO, LOG_ERR, LOC_DEV + QString("short pcm read, %1 of %2 frames, retries %3") .arg(to_read - nframes).arg(to_read).arg(retries)); return snd_pcm_frames_to_bytes(pcm_handle, to_read - nframes); }
/** Fill buffers, for starting and stopping * Alsa won't start playing until everything is filled up * This also updates mmap_pos * * Returns: Amount of periods in use so snd_pcm_avail_update * doesn't have to be called up to 4x in GetPosition() */ static snd_pcm_uframes_t CommitAll(IDsDriverBufferImpl *This) { const snd_pcm_channel_area_t *areas; snd_pcm_sframes_t used; const snd_pcm_uframes_t commitahead = This->mmap_commitahead; used = This->mmap_buflen_frames - snd_pcm_avail_update(This->pcm); if (used < 0) used = 0; TRACE("%p needs to commit to %lu, used: %ld\n", This, commitahead, used); if (used < commitahead) { snd_pcm_sframes_t done; snd_pcm_uframes_t putin = commitahead - used; if (This->mmap) { snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin); done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin); } else { if (putin + This->mmap_pos > This->mmap_buflen_frames) putin = This->mmap_buflen_frames - This->mmap_pos; done = snd_pcm_writei(This->pcm, This->mmap_buffer + snd_pcm_frames_to_bytes(This->pcm, This->mmap_pos), putin); if (done < putin) WARN("Short write %ld/%ld\n", putin, done); } if (done < 0) done = 0; This->mmap_pos += done; used += done; putin = commitahead - used; if (This->mmap_pos == This->mmap_buflen_frames && (snd_pcm_sframes_t)putin > 0) { if (This->mmap) { snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin); done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin); This->mmap_pos += done; } else { done = snd_pcm_writei(This->pcm, This->mmap_buffer, putin); if (done < putin) WARN("Short write %ld/%ld\n", putin, done); if (done < 0) done = 0; This->mmap_pos = done; } used += done; } } if (This->mmap_pos == This->mmap_buflen_frames) This->mmap_pos = 0; return used; }
static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface, LPDWORD lpdwPlay, LPDWORD lpdwWrite) { IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface; snd_pcm_uframes_t hw_pptr, hw_wptr; snd_pcm_state_t state; /* **** */ EnterCriticalSection(&This->pcm_crst); if (!This->pcm) { FIXME("Bad pointer for pcm: %p\n", This->pcm); LeaveCriticalSection(&This->pcm_crst); return DSERR_GENERIC; } if (!lpdwPlay && !lpdwWrite) CommitAll(This); state = snd_pcm_state(This->pcm); if (state != SND_PCM_STATE_PREPARED && state != SND_PCM_STATE_RUNNING) { CheckXRUN(This); state = snd_pcm_state(This->pcm); } if (state == SND_PCM_STATE_RUNNING) { snd_pcm_uframes_t used = This->mmap_buflen_frames - snd_pcm_avail_update(This->pcm); if (This->mmap_pos > used) hw_pptr = This->mmap_pos - used; else hw_pptr = This->mmap_buflen_frames + This->mmap_pos - used; hw_pptr %= This->mmap_buflen_frames; TRACE("At position: %ld (%ld) - Used %ld\n", hw_pptr, This->mmap_pos, used); } else hw_pptr = This->mmap_pos; hw_wptr = This->mmap_pos; LeaveCriticalSection(&This->pcm_crst); /* **** */ if (lpdwPlay) *lpdwPlay = snd_pcm_frames_to_bytes(This->pcm, hw_pptr); if (lpdwWrite) *lpdwWrite = snd_pcm_frames_to_bytes(This->pcm, hw_wptr); TRACE("hw_pptr=0x%08x, hw_wptr=0x%08x playpos=%d, writepos=%d\n", (unsigned int)hw_pptr, (unsigned int)hw_wptr, lpdwPlay?*lpdwPlay:-1, lpdwWrite?*lpdwWrite:-1); return DS_OK; }
unsigned int sound_get_buffer () { int ret; snd_pcm_uframes_t buffer_size, period_size; ret = snd_pcm_get_params (handle, &buffer_size, &period_size); if (ret < 0) return 0; return buffer_size - snd_pcm_avail_update (handle); }
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; }
int GetEmptySampleCount() { if (handle == NULL) { fprintf(stderr, "Handle is NULL!\n"); return 0; } // Returns the amount of free buffer space, in samples. int l = snd_pcm_avail_update(handle); if (l < 0) return 0; return (l / 1000) * (SampleRate / 1000); }
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; }
int QAudioOutputPrivate::bytesFree() const { if(resuming) return period_size; if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) return 0; int frames = snd_pcm_avail_update(handle); if((int)frames > (int)buffer_frames) frames = buffer_frames; return snd_pcm_frames_to_bytes(handle, frames); }
int sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes) { snd_pcm_sframes_t frames, nframes, avail; if (s == NULL || s->output_unit == NULL) { return SA_ERROR_NO_INIT; } if (nbytes == 0) { return SA_SUCCESS; } nframes = snd_pcm_bytes_to_frames(s->output_unit, nbytes); while(nframes>0) { if (s->resumed) { avail = snd_pcm_avail_update(s->output_unit); frames = snd_pcm_writei(s->output_unit, data, nframes > avail ? avail : nframes); avail = snd_pcm_avail_update(s->output_unit); s->resumed = avail != 0; } else { avail = snd_pcm_avail_update(s->output_unit); avail = avail < 64 ? 64 : avail; frames = snd_pcm_writei(s->output_unit, data, nframes > avail ? avail : nframes); } if (frames < 0) { int r = snd_pcm_recover(s->output_unit, frames, 1); if (r < 0) { return SA_ERROR_SYSTEM; } } else { size_t bytes = snd_pcm_frames_to_bytes(s->output_unit, frames); nframes -= frames; data = ((unsigned char *)data) + bytes; s->bytes_written += bytes; } } return SA_SUCCESS; }
/** * \brief Obtain delay for a running PCM handle * \param pcm ordinary PCM handle * \param delayp Returned delay in frames * \return 0 on success otherwise a negative error code * * Delay is distance between current application frame position and * sound frame position. * It's positive and less than buffer size in normal situation, * negative on playback underrun and greater than buffer size on * capture overrun. */ int sndo_pcm_delay(sndo_pcm_t *pcm, snd_pcm_sframes_t *delayp) { int err; snd_pcm_sframes_t pdelay, cdelay; assert(pcm); assert(delayp); err = sndo_pcm_check_setup(pcm); if (err < 0) return err; if (pcm->playback) err = snd_pcm_avail_update(pcm->playback); if (err >= 0 && pcm->capture) err = snd_pcm_avail_update(pcm->capture); if (err >= 0 && pcm->playback) err = snd_pcm_delay(pcm->playback, &pdelay); if (err >= 0 && pcm->capture) err = snd_pcm_delay(pcm->capture, &cdelay); if (pdelay > cdelay) pdelay = cdelay; *delayp = pdelay; return err; }
unsigned long SoundGetBytesBuffered(void) { unsigned long l; if(handle == NULL) // failed to open? return SOUNDSIZE; l = snd_pcm_avail_update(handle); if(l<0) return 0; if(l<buffer_size/2) // can we write in at least the half of fragments? l=SOUNDSIZE; // -> no? wait else l=0; // -> else go on return l; }
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; }
static void async_callback(snd_async_handler_t *ahandler) { snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler); struct async_private_data *data = snd_async_handler_get_callback_private(ahandler); signed short *samples = data->samples; snd_pcm_channel_area_t *areas = data->areas; snd_pcm_sframes_t avail; int err; avail = snd_pcm_avail_update(handle); while (avail >= period_size) { generate_sine(areas, 0, period_size, &data->phase); err = snd_pcm_writei(handle, samples, period_size); if (err < 0) { printf("Initial write error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } if (err != period_size) { printf("Initial write error: written %i expected %li\n", err, period_size); exit(EXIT_FAILURE); } avail = snd_pcm_avail_update(handle); } }
int snd_pcm_avail_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *availp, snd_pcm_sframes_t *delayp) { int err; snd_pcm_sframes_t val; err = snd_pcm_delay(pcm, delayp); if (err < 0) return err; val = snd_pcm_avail_update(pcm); if (val < 0) return (int)val; *availp = val; return 0; }
static bool safeUpdate(snd_pcm_t *handle, int &samples) { samples = snd_pcm_avail_update(handle); if (samples < 0) { samples = snd_pcm_recover(handle, samples, 0); if (samples < 0) { ERROR("Got unrecoverable error from snd_pcm_avail_update: %s", snd_strerror(samples)); return false; } } return true; }