/* stolen from devposs */ static uint32_t gettimer(void) { long tmp=playpos; int odelay; if (busy++) { odelay=kernlen; } else { int err; #ifdef ALSA_DEBUG fprintf(stderr, "ALSA snd_pcm_status(alsa_pcm, alsa_pcm_status) = "); #endif if ((err=snd_pcm_status(alsa_pcm, alsa_pcm_status))<0) { #ifdef ALSA_DEBUG fprintf(stderr, "failed: %s\n", snd_strerror(-err)); #endif fprintf(stderr, "ALSA: snd_pcm_status() failed: %s\n", snd_strerror(-err)); odelay=kernlen; } else { #ifdef ALSA_DEBUG fprintf(stderr, "ok\n"); fprintf(stderr, "snd_pcm_status_get_delay(alsa_pcm_status) = "); #endif odelay=snd_pcm_status_get_delay(alsa_pcm_status); #ifdef ALSA_DEBUG fprintf(stderr, "%i\n", odelay); #endif if (odelay<0) /* we ignore buffer-underruns */ odelay=0; else if (odelay==0) { /* ALSA sometimes (atlast on Stians Ubuntu laptop) gives odelay==0 always */ odelay = snd_pcm_status_get_avail_max(alsa_pcm_status) - snd_pcm_status_get_avail(alsa_pcm_status); if (odelay<0) odelay=0; } odelay<<=(bit16+stereo); if (odelay>kernlen) { odelay=kernlen; } else if ((odelay<kernlen)) { kernlen=odelay; kernpos=(cachepos-kernlen+buflen)%buflen; } } } tmp-=odelay; busy--; return imuldiv(tmp, 65536>>(stereo+bit16), plrRate); }
static GstClockTime gst_alsasrc_get_timestamp (GstAlsaSrc * asrc) { snd_pcm_status_t *status; snd_htimestamp_t tstamp; GstClockTime timestamp; snd_pcm_uframes_t avail; gint err = -EPIPE; if (G_UNLIKELY (!asrc)) { GST_ERROR_OBJECT (asrc, "No alsa handle created yet !"); return GST_CLOCK_TIME_NONE; } if (G_UNLIKELY (snd_pcm_status_malloc (&status) != 0)) { GST_ERROR_OBJECT (asrc, "snd_pcm_status_malloc failed"); return GST_CLOCK_TIME_NONE; } if (G_UNLIKELY (snd_pcm_status (asrc->handle, status) != 0)) { GST_ERROR_OBJECT (asrc, "snd_pcm_status failed"); return GST_CLOCK_TIME_NONE; } /* in case an xrun condition has occured we need to handle this */ if (snd_pcm_status_get_state (status) != SND_PCM_STATE_RUNNING) { if (xrun_recovery (asrc, asrc->handle, err) < 0) { GST_WARNING_OBJECT (asrc, "Could not recover from xrun condition !"); } /* reload the status alsa status object, since recovery made it invalid */ if (G_UNLIKELY (snd_pcm_status (asrc->handle, status) != 0)) { GST_ERROR_OBJECT (asrc, "snd_pcm_status failed"); } } /* get high resolution time stamp from driver */ snd_pcm_status_get_htstamp (status, &tstamp); timestamp = GST_TIMESPEC_TO_TIME (tstamp); /* max available frames sets the depth of the buffer */ avail = snd_pcm_status_get_avail (status); /* calculate the timestamp of the next sample to be read */ timestamp -= gst_util_uint64_scale_int (avail, GST_SECOND, asrc->rate); /* compensate for the fact that we really need the timestamp of the * previously read data segment */ timestamp -= asrc->period_time * 1000; snd_pcm_status_free (status); GST_LOG_OBJECT (asrc, "ALSA timestamp : %" GST_TIME_FORMAT ", delay %lu", GST_TIME_ARGS (timestamp), avail); return timestamp; }
/* more or less stolen from devposs */ static int getplaypos(void) { int retval; if (busy++) { } else { snd_pcm_sframes_t tmp; int err; #ifdef ALSA_DEBUG fprintf(stderr, "ALSA snd_pcm_status(alsa_pcm, alsa_pcm_status) = "); #endif if ((err=snd_pcm_status(alsa_pcm, alsa_pcm_status))<0) { #ifdef ALSA_DEBUG fprintf(stderr, "failed: %s\n", snd_strerror(-err)); #endif fprintf(stderr, "ALSA: snd_pcm_status() failed: %s\n", snd_strerror(-err)); } else { #ifdef ALSA_DEBUG fprintf(stderr, "ok\n"); fprintf(stderr, "ALSA snd_pcm_status_get_delay(alsa_pcm_status = "); #endif tmp=snd_pcm_status_get_delay(alsa_pcm_status); #ifdef ALSA_DEBUG fprintf(stderr, "%ld\n", tmp); #endif tmp<<=(bit16+stereo); if (tmp<0) /* we ignore buffer-underruns */ tmp=0; else if (tmp==0) { /* ALSA sometimes (atlast on Stians Ubuntu laptop) gives odelay==0 always */ tmp = snd_pcm_status_get_avail_max(alsa_pcm_status) - snd_pcm_status_get_avail(alsa_pcm_status); if (tmp<0) tmp=0; } if (tmp>kernlen) { } else { kernlen=tmp; } kernpos=(cachepos-kernlen+buflen)%buflen; } } retval=kernpos; busy--; return retval; }
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; }
/* 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; }
/* 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; }
static void alsa_prefill( void ) { snd_pcm_status_t *status; char buf[512]; int frames, cnt; snd_pcm_status_malloc( &status ); snd_pcm_status( alsa.pcm, status ); frames = snd_pcm_status_get_avail(status); snd_pcm_status_free( status ); memset( buf, 0, sizeof(buf) ); cnt = sizeof(buf)/alsa.bpf; for( ; frames > 0; frames -= cnt ) { if( cnt > frames ) cnt = frames; snd_pcm_writei( alsa.pcm, buf, sizeof(buf)/alsa.bpf ); } }
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; }
int alsa_send_dacs(void) { #ifdef DEBUG_ALSA_XFER static int xferno = 0; static int callno = 0; #endif static double timenow; double timelast; t_sample *fp, *fp1, *fp2; int i, j, k, err, iodev, result, ch; int chansintogo, chansouttogo; unsigned int transfersize; if (alsa_usemmap) return (alsamm_send_dacs()); if (!alsa_nindev && !alsa_noutdev) return (SENDDACS_NO); chansintogo = sys_inchannels; chansouttogo = sys_outchannels; transfersize = DEFDACBLKSIZE; timelast = timenow; timenow = sys_getrealtime(); #ifdef DEBUG_ALSA_XFER if (timenow - timelast > 0.050) fprintf(stderr, "(%d)", (int)(1000 * (timenow - timelast))), fflush(stderr); callno++; #endif alsa_checkiosync(); /* check I/O are in sync and data not late */ for (iodev = 0; iodev < alsa_nindev; iodev++) { snd_pcm_status(alsa_indev[iodev].a_handle, alsa_status); if (snd_pcm_status_get_avail(alsa_status) < transfersize) return SENDDACS_NO; } for (iodev = 0; iodev < alsa_noutdev; iodev++) { snd_pcm_status(alsa_outdev[iodev].a_handle, alsa_status); if (snd_pcm_status_get_avail(alsa_status) < transfersize) return SENDDACS_NO; } /* do output */ for (iodev = 0, fp1 = sys_soundout, ch = 0; iodev < alsa_noutdev; iodev++) { int thisdevchans = alsa_outdev[iodev].a_channels; int chans = (chansouttogo < thisdevchans ? chansouttogo : thisdevchans); chansouttogo -= chans; if (alsa_outdev[iodev].a_sampwidth == 4) { for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; j += thisdevchans, fp2++) { float s1 = *fp2 * INT32_MAX; ((t_alsa_sample32 *)alsa_snd_buf)[j] = CLIP32(s1); } for (; i < thisdevchans; i++, ch++) for (j = i, k = DEFDACBLKSIZE; k--; j += thisdevchans) ((t_alsa_sample32 *)alsa_snd_buf)[j] = 0; } else if (alsa_outdev[iodev].a_sampwidth == 3) { for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; j += thisdevchans, fp2++) { int s = *fp2 * 8388352.; if (s > 8388351) s = 8388351; else if (s < -8388351) s = -8388351; #if BYTE_ORDER == LITTLE_ENDIAN ((char *)(alsa_snd_buf))[3*j] = (s & 255); ((char *)(alsa_snd_buf))[3*j+1] = ((s>>8) & 255); ((char *)(alsa_snd_buf))[3*j+2] = ((s>>16) & 255); #else fprintf(stderr("big endian 24-bit not supported"); #endif } for (; i < thisdevchans; i++, ch++) for (j = i, k = DEFDACBLKSIZE; k--; j += thisdevchans) ((char *)(alsa_snd_buf))[3*j] = ((char *)(alsa_snd_buf))[3*j+1] = ((char *)(alsa_snd_buf))[3*j+2] = 0; } else /* 16 bit samples */ { for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) for (j = ch, k = DEFDACBLKSIZE, fp2 = fp1; k--; j += thisdevchans, fp2++) { int s = *fp2 * 32767.; if (s > 32767) s = 32767; else if (s < -32767) s = -32767; ((t_alsa_sample16 *)alsa_snd_buf)[j] = s; } for (; i < thisdevchans; i++, ch++) for (j = ch, k = DEFDACBLKSIZE; k--; j += thisdevchans) ((t_alsa_sample16 *)alsa_snd_buf)[j] = 0; } result = snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, transfersize); if (result != (int)transfersize) { #ifdef DEBUG_ALSA_XFER if (result >= 0 || errno == EAGAIN) fprintf(stderr, "ALSA: write returned %d of %d\n", result, transfersize); else fprintf(stderr, "ALSA: write: %s\n", snd_strerror(errno)); fprintf(stderr, "inputcount %d, outputcount %d, outbufsize %d\n", inputcount, outputcount, (ALSA_EXTRABUFFER + sys_advance_samples) * alsa_outdev[iodev].a_sampwidth * outchannels); #endif sys_log_error(ERR_DACSLEPT); return (SENDDACS_NO); } /* zero out the output buffer */ memset(sys_soundout, 0, DEFDACBLKSIZE * sizeof(*sys_soundout) * sys_outchannels); if (sys_getrealtime() - timenow > 0.002) { #ifdef DEBUG_ALSA_XFER fprintf(stderr, "output %d took %d msec\n", callno, (int)(1000 * (timenow - timelast))), fflush(stderr); #endif timenow = sys_getrealtime(); sys_log_error(ERR_DACSLEPT); } }
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); }
/* more or less stolen from devposs */ static void flush(void) { int result, n, odelay; int err; if (busy++) { busy--; return; } #ifdef ALSA_DEBUG fprintf(stderr, "ALSA snd_pcm_status(alsa_pcm, alsa_pcm_status) = "); #endif if ((err=snd_pcm_status(alsa_pcm, alsa_pcm_status))<0) { #ifdef ALSA_DEBUG fprintf(stderr, "failed: %s\n", snd_strerror(-err)); #endif fprintf(stderr, "ALSA: snd_pcm_status() failed: %s\n", snd_strerror(-err)); busy--; return; } #ifdef ALSA_DEBUG fprintf(stderr, "ok\n"); fprintf(stderr, "ALSA snd_pcm_status_get_delay(alsa_pcm_status) = "); #endif odelay=snd_pcm_status_get_delay(alsa_pcm_status); #ifdef ALSA_DEBUG fprintf(stderr, "%i\n", odelay); #endif odelay<<=(bit16+stereo); if (odelay<0) /* we ignore buffer-underruns */ odelay=0; else if (odelay==0) { /* ALSA sometimes (atlast on Stians Ubuntu laptop) gives odelay==0 always */ odelay = snd_pcm_status_get_avail_max(alsa_pcm_status) - snd_pcm_status_get_avail(alsa_pcm_status); if (odelay<0) odelay=0; } if (odelay>kernlen) { odelay=kernlen; } else if ((odelay<kernlen)) { kernlen=odelay; kernpos=(cachepos-kernlen+buflen)%buflen; } if (!cachelen) { busy--; return; } if (bufpos<=cachepos) n=buflen-cachepos; else n=bufpos-cachepos; /* TODO, check kernel-size if (n>info.bytes) n=info.bytes; */ if (n<=0) { busy--; return; } #ifdef ALSA_DEBUG fprintf(stderr, "ALSA snd_pcm_writei(alsa_pcm, buffer, %i) = ", n>>(bit16+stereo)); #endif result=snd_pcm_writei(alsa_pcm, playbuf+cachepos, n>>(bit16+stereo)); if (result<0) { #ifdef ALSA_DEBUG fprintf(stderr, "failed: %s\n", snd_strerror(-result)); #endif if (result==-EPIPE) { fprintf(stderr, "ALSA: Machine is too slow, calling snd_pcm_prepare()\n"); fprintf(stderr, "ALSA snd_pcm_prepare(alsa_pcm)"); snd_pcm_prepare(alsa_pcm); /* TODO, can this fail? */ } busy--; return; #ifdef ALSA_DEBUG } else { fprintf(stderr, "ok\n"); #endif } result<<=(bit16+stereo); cachepos=(cachepos+result+buflen)%buflen; playpos+=result; cachelen-=result; kernlen+=result; busy--; }
int alsa_send_dacs(void) { static double timenow; double timelast; t_sample *fp, *fp1, *fp2; int i, j, k, err, iodev, result, ch, resync = 0;; int chansintogo, chansouttogo; unsigned int transfersize; if (alsa_usemmap) return (alsamm_send_dacs()); if (!alsa_nindev && !alsa_noutdev) return (SENDDACS_NO); chansintogo = STUFF->st_inchannels; chansouttogo = STUFF->st_outchannels; transfersize = DEFDACBLKSIZE; timelast = timenow; timenow = sys_getrealtime(); #ifdef DEBUG_ALSA_XFER if (timenow - timelast > 0.050) post("long wait between calls: %d", (int)(1000 * (timenow - timelast))), fflush(stderr); callno++; #endif for (iodev = 0; iodev < alsa_nindev; iodev++) { result = snd_pcm_state(alsa_indev[iodev].a_handle); if (result == SND_PCM_STATE_XRUN) { int res2 = snd_pcm_start(alsa_indev[iodev].a_handle); fprintf(stderr, "restart alsa input\n"); if (res2 < 0) fprintf(stderr, "alsa xrun recovery apparently failed\n"); } snd_pcm_status(alsa_indev[iodev].a_handle, alsa_status); if (snd_pcm_status_get_avail(alsa_status) < transfersize) return (SENDDACS_NO); } for (iodev = 0; iodev < alsa_noutdev; iodev++) { result = snd_pcm_state(alsa_outdev[iodev].a_handle); if (result == SND_PCM_STATE_XRUN) { int res2 = snd_pcm_start(alsa_outdev[iodev].a_handle); fprintf(stderr, "restart alsa output\n"); if (res2 < 0) fprintf(stderr, "alsa xrun recovery apparently failed\n"); } snd_pcm_status(alsa_outdev[iodev].a_handle, alsa_status); if (snd_pcm_status_get_avail(alsa_status) < transfersize) return (SENDDACS_NO); } #ifdef DEBUG_ALSA_XFER post("xfer %d", transfersize); #endif /* do output */ for (iodev = 0, fp1 = STUFF->st_soundout, ch = 0; iodev < alsa_noutdev; iodev++) { int thisdevchans = alsa_outdev[iodev].a_channels; int chans = (chansouttogo < thisdevchans ? chansouttogo : thisdevchans); chansouttogo -= chans; if (alsa_outdev[iodev].a_sampwidth == 4) { for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; j += thisdevchans, fp2++) { float s1 = *fp2 * INT32_MAX; ((t_alsa_sample32 *)alsa_snd_buf)[j] = CLIP32(s1); } for (; i < thisdevchans; i++, ch++) for (j = i, k = DEFDACBLKSIZE; k--; j += thisdevchans) ((t_alsa_sample32 *)alsa_snd_buf)[j] = 0; } else if (alsa_outdev[iodev].a_sampwidth == 3) { for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; j += thisdevchans, fp2++) { int s = *fp2 * 8388352.; if (s > 8388351) s = 8388351; else if (s < -8388351) s = -8388351; #if BYTE_ORDER == LITTLE_ENDIAN ((char *)(alsa_snd_buf))[3*j] = (s & 255); ((char *)(alsa_snd_buf))[3*j+1] = ((s>>8) & 255); ((char *)(alsa_snd_buf))[3*j+2] = ((s>>16) & 255); #else fprintf(stderr, "big endian 24-bit not supported"); #endif } for (; i < thisdevchans; i++, ch++) for (j = i, k = DEFDACBLKSIZE; k--; j += thisdevchans) ((char *)(alsa_snd_buf))[3*j] = ((char *)(alsa_snd_buf))[3*j+1] = ((char *)(alsa_snd_buf))[3*j+2] = 0; } else /* 16 bit samples */ { for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) for (j = ch, k = DEFDACBLKSIZE, fp2 = fp1; k--; j += thisdevchans, fp2++) { int s = *fp2 * 32767.; if (s > 32767) s = 32767; else if (s < -32767) s = -32767; ((t_alsa_sample16 *)alsa_snd_buf)[j] = s; } for (; i < thisdevchans; i++, ch++) for (j = ch, k = DEFDACBLKSIZE; k--; j += thisdevchans) ((t_alsa_sample16 *)alsa_snd_buf)[j] = 0; } result = snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, transfersize); if (result != (int)transfersize) { #ifdef DEBUG_ALSA_XFER if (result >= 0 || errno == EAGAIN) post("ALSA: write returned %d of %d\n", result, transfersize); else post("ALSA: write: %s\n", snd_strerror(errno)); #endif sys_log_error(ERR_DATALATE); if (result == -EPIPE) { result = snd_pcm_prepare(alsa_indev[iodev].a_handle); if (result < 0) fprintf(stderr, "read reset error %d\n", result); } else fprintf(stderr, "read other error %d\n", result); resync = 1; } /* zero out the output buffer */ memset(STUFF->st_soundout, 0, DEFDACBLKSIZE * sizeof(*STUFF->st_soundout) * STUFF->st_outchannels); if (sys_getrealtime() - timenow > 0.002) { #ifdef DEBUG_ALSA_XFER post("output %d took %d msec\n", callno, (int)(1000 * (timenow - timelast))), fflush(stderr); #endif timenow = sys_getrealtime(); sys_log_error(ERR_DACSLEPT); } }
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); } }