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; }
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 ); } }
void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource, int encoding, float sampleRate, int sampleSizeInBits, int frameSize, int channels, int isSigned, int isBigEndian, int bufferSizeInBytes) { snd_pcm_format_mask_t* formatMask; snd_pcm_format_t format; int dir; int ret = 0; AlsaPcmInfo* info = NULL; /* snd_pcm_uframes_t is 64 bit on 64-bit systems */ snd_pcm_uframes_t alsaPeriodSize = 0; snd_pcm_uframes_t alsaBufferSizeInFrames = 0; TRACE0("> DAUDIO_Open\n"); #ifdef USE_TRACE // for using ALSA debug dump methods if (ALSA_OUTPUT == NULL) { snd_output_stdio_attach(&ALSA_OUTPUT, stdout, 0); } #endif info = (AlsaPcmInfo*) malloc(sizeof(AlsaPcmInfo)); if (!info) { ERROR0("Out of memory\n"); return NULL; } memset(info, 0, sizeof(AlsaPcmInfo)); ret = openPCMfromDeviceID(deviceID, &(info->handle), isSource, FALSE /* do open device*/); if (ret == 0) { // set to blocking mode snd_pcm_nonblock(info->handle, 0); ret = snd_pcm_hw_params_malloc(&(info->hwParams)); if (ret != 0) { ERROR1(" snd_pcm_hw_params_malloc returned error %d\n", ret); } else { ret = -1; if (getAlsaFormatFromFormat(&format, frameSize / channels, sampleSizeInBits, isSigned, isBigEndian, encoding)) { if (setHWParams(info, sampleRate, channels, bufferSizeInBytes / frameSize, format)) { info->frameSize = frameSize; #ifdef ALSA_PCM_NEW_HW_PARAMS_API ret = snd_pcm_hw_params_get_period_size(info->hwParams, &alsaPeriodSize, &dir); info->periodSize = (int) alsaPeriodSize; if (ret < 0) { ERROR1("ERROR: snd_pcm_hw_params_get_period: %s\n", snd_strerror(ret)); } snd_pcm_hw_params_get_periods(info->hwParams, &(info->periods), &dir); snd_pcm_hw_params_get_buffer_size(info->hwParams, &alsaBufferSizeInFrames); info->bufferSizeInBytes = (int) alsaBufferSizeInFrames * frameSize; #else info->periodSize = snd_pcm_hw_params_get_period_size(info->hwParams, &dir); info->periods = snd_pcm_hw_params_get_periods(info->hwParams, &dir); info->bufferSizeInBytes = snd_pcm_hw_params_get_buffer_size(info->hwParams) * frameSize; ret = 0; #endif TRACE3(" DAUDIO_Open: period size = %d frames, periods = %d. Buffer size: %d bytes.\n", (int) info->periodSize, info->periods, info->bufferSizeInBytes); } } } if (ret == 0) { // set software parameters ret = snd_pcm_sw_params_malloc(&(info->swParams)); if (ret != 0) { ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret); } else { if (!setSWParams(info)) { ret = -1; } } } if (ret == 0) { // prepare device ret = snd_pcm_prepare(info->handle); if (ret < 0) { ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret)); } } #ifdef GET_POSITION_METHOD2 if (ret == 0) { ret = snd_pcm_status_malloc(&(info->positionStatus)); if (ret != 0) { ERROR1("ERROR in snd_pcm_status_malloc: %s\n", snd_strerror(ret)); } } #endif } if (ret != 0) { DAUDIO_Close((void*) info, isSource); info = NULL; } else { // set to non-blocking mode snd_pcm_nonblock(info->handle, 1); TRACE1("< DAUDIO_Open: Opened device successfully. Handle=%p\n", (void*) info->handle); } return (void*) info; }
/* return 0 on success */ int alsa_open_audio(int naudioindev, int *audioindev, int nchindev, int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, int rate) { int err, inchans = 0, outchans = 0, subunitdir; char devname[512]; snd_output_t* out; int frag_size = (sys_blocksize ? sys_blocksize : ALSA_DEFFRAGSIZE); int nfrags, i, iodev, dev2; int wantinchans, wantoutchans, device; nfrags = sys_schedadvance * (float)rate / (1e6 * frag_size); /* save our belief as to ALSA's buffer size for later */ alsa_buf_samps = nfrags * frag_size; alsa_nindev = alsa_noutdev = 0; alsa_jittermax = ALSA_DEFJITTERMAX; if (sys_verbose) post("audio buffer set to %d", (int)(0.001 * sys_schedadvance)); for (iodev = 0; iodev < naudioindev; iodev++) { alsa_numbertoname(audioindev[iodev], devname, 512); err = snd_pcm_open(&alsa_indev[alsa_nindev].a_handle, devname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); check_error(err, "snd_pcm_open (input)"); if (err < 0) continue; alsa_indev[alsa_nindev].a_devno = audioindev[iodev]; snd_pcm_nonblock(alsa_indev[alsa_nindev].a_handle, 1); if (sys_verbose) post("opened input device name %s", devname); alsa_nindev++; } for (iodev = 0; iodev < naudiooutdev; iodev++) { alsa_numbertoname(audiooutdev[iodev], devname, 512); err = snd_pcm_open(&alsa_outdev[alsa_noutdev].a_handle, devname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); check_error(err, "snd_pcm_open (output)"); if (err < 0) continue; alsa_outdev[alsa_noutdev].a_devno = audiooutdev[iodev]; snd_pcm_nonblock(alsa_outdev[alsa_noutdev].a_handle, 1); alsa_noutdev++; } if (!alsa_nindev && !alsa_noutdev) goto blewit; /* If all the open devices support mmap_noninterleaved, let's call Wini's code in s_audio_alsamm.c */ alsa_usemmap = 1; for (iodev = 0; iodev < alsa_nindev; iodev++) if (!alsaio_canmmap(&alsa_indev[iodev])) alsa_usemmap = 0; for (iodev = 0; iodev < alsa_noutdev; iodev++) if (!alsaio_canmmap(&alsa_outdev[iodev])) alsa_usemmap = 0; if (alsa_usemmap) { post("using mmap audio interface"); if (alsamm_open_audio(rate)) goto blewit; else return (0); } for (iodev = 0; iodev < alsa_nindev; iodev++) { int channels = chindev[iodev]; if (alsaio_setup(&alsa_indev[iodev], 0, &channels, &rate, nfrags, frag_size) < 0) goto blewit; inchans += channels; } for (iodev = 0; iodev < alsa_noutdev; iodev++) { int channels = choutdev[iodev]; if (alsaio_setup(&alsa_outdev[iodev], 1, &channels, &rate, nfrags, frag_size) < 0) goto blewit; outchans += channels; } if (!inchans && !outchans) goto blewit; for (iodev = 0; iodev < alsa_nindev; iodev++) snd_pcm_prepare(alsa_indev[iodev].a_handle); for (iodev = 0; iodev < alsa_noutdev; iodev++) snd_pcm_prepare(alsa_outdev[iodev].a_handle); /* if duplex we can link the channels so they start together */ for (iodev = 0; iodev < alsa_nindev; iodev++) for (dev2 = 0; dev2 < alsa_noutdev; dev2++) { if (alsa_indev[iodev].a_devno == alsa_outdev[iodev].a_devno) { snd_pcm_link(alsa_indev[iodev].a_handle, alsa_outdev[iodev].a_handle); } } /* allocate the status variables */ if (!alsa_status) { err = snd_pcm_status_malloc(&alsa_status); check_error(err, "snd_pcm_status_malloc"); } /* fill the buffer with silence */ memset(alsa_snd_buf, 0, alsa_snd_bufsize); if (outchans) { i = (frag_size * nfrags)/DEFDACBLKSIZE + 1; while (i--) { for (iodev = 0; iodev < alsa_noutdev; iodev++) snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, DEFDACBLKSIZE); } } else if (inchans) { for (iodev = 0; iodev < alsa_nindev; iodev++) if ((err = snd_pcm_start(alsa_indev[iodev].a_handle)) < 0) check_error(err, "input start failed\n"); } return (0); blewit: sys_inchannels = 0; sys_outchannels = 0; alsa_close_audio(); return (1); }