예제 #1
0
파일: devpalsa.c 프로젝트: cynthia/ocp-osx
/* 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);
}
예제 #2
0
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;
}
예제 #3
0
파일: devpalsa.c 프로젝트: cynthia/ocp-osx
/* 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;
}
예제 #4
0
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;
}
예제 #5
0
파일: ao_alsa.c 프로젝트: C3MA/fc_mplayer
/* 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;
}
예제 #6
0
/* 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);
}
예제 #7
0
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;
}
예제 #8
0
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;
}
예제 #10
0
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);
        }
    }
예제 #11
0
파일: alsa.c 프로젝트: madnessw/thesnow
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);
}
예제 #12
0
파일: devpalsa.c 프로젝트: cynthia/ocp-osx
/* 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--;
}
예제 #13
0
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);
        }
    }
예제 #14
0
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);
  }
}