示例#1
0
static int
bytes_written(AudioDevice *ad)
{
  ALSA_data *alsa = (ALSA_data *)ad->private_data;
  snd_pcm_sframes_t delay;
  snd_pcm_state_t state;

  if (!alsa)
    return -1;

  state = snd_pcm_state(alsa->fd);
  if (state == SND_PCM_STATE_OPEN || state == SND_PCM_STATE_SETUP)
    return -1;

  if (snd_pcm_delay(alsa->fd, &delay) < 0)
    warning_fnc("snd_pcm_delay() failed.\n");

  return ad->bytes_written - snd_pcm_samples_to_bytes(alsa->fd, delay) * ad->channels;
}
示例#2
0
int AudioInputALSA::GetNumReadyBytes(void)
{
    int bytes_avail = 0;
    if (pcm_handle != NULL)
    {
        snd_pcm_sframes_t frames_avail;
        int pcm_state = snd_pcm_state(pcm_handle);
        switch (pcm_state)
        {
        case SND_PCM_STATE_PREPARED:
        case SND_PCM_STATE_RUNNING:
            if (!AlsaBad((frames_avail = snd_pcm_avail_update(pcm_handle)),
                         "GetNumReadyBytes, available update failed"))
                bytes_avail = snd_pcm_frames_to_bytes(pcm_handle,
                                                      frames_avail);
        }
    }
    return bytes_avail;
}
示例#3
0
void *write_pcmdata(void *arg)
{
	dbg("Enter write_pcmdata thread.....\n");

	int ret;
	msg_t pcm_data;
	snd_pcm_sframes_t avail;

	common_data_t *p_common_data = (common_data_t *)arg;
	dbg("PCM handle name = '%s'\n",snd_pcm_name(p_common_data->handle));
	dbg("period szie = %lu\n",p_common_data->period_size);

	while (1) {
		sem_wait(&p_common_data->queue.wait);
		if((read_item_from_queue(&p_common_data->queue, &pcm_data)) == EMPTY){
			dbg("queue is empty...\n");
			//TODO:block?
			continue;
		}
		snd_pcm_prepare(p_common_data->handle);
		ret = snd_pcm_writei(p_common_data->handle, pcm_data.pcm_msg, p_common_data->period_size);
		if (ret == -EAGAIN) { //means try again
			/* wait 1000ms for pcm device to become ready */
			dbg_alsa("EAGAIN error, Sleep for 1000ms\n");
			snd_pcm_wait(p_common_data->handle, 1000);
		}
		else if (ret == -EPIPE) {
			/* EPIPE means underrun */
			snd_pcm_prepare(p_common_data->handle);
			dbg_alsa("underrun occurred\n");
		} 
		else if(ret == -ESTRPIPE) {
			dbg_alsa("Need suspend\n");
		}
		else if (ret < 0) {
			dbg_alsa("error from writei: %s\n", snd_strerror(ret));
		}  
		ret = snd_pcm_state(p_common_data->handle);
		dbg("state is %d\n", ret);
		sem_post(&p_common_data->queue.full);
	}
}
示例#4
0
文件: pcm_dsnoop.c 项目: NieHao/R7000
/*
 *  synchronize hardware pointer (hw_ptr) with ours
 */
static int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dsnoop = pcm->private_data;
	snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
	snd_pcm_sframes_t diff;
	
	switch (snd_pcm_state(dsnoop->spcm)) {
	case SND_PCM_STATE_DISCONNECTED:
		dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED;
		return -ENODEV;
	default:
		break;
	}
	if (dsnoop->slowptr)
		snd_pcm_hwsync(dsnoop->spcm);
	old_slave_hw_ptr = dsnoop->slave_hw_ptr;
	snoop_timestamp(pcm);
	slave_hw_ptr = dsnoop->slave_hw_ptr;
	diff = slave_hw_ptr - old_slave_hw_ptr;
	if (diff == 0)		/* fast path */
		return 0;
	if (diff < 0) {
		slave_hw_ptr += dsnoop->slave_boundary;
		diff = slave_hw_ptr - old_slave_hw_ptr;
	}
	snd_pcm_dsnoop_sync_area(pcm, old_slave_hw_ptr, diff);
	dsnoop->hw_ptr += diff;
	dsnoop->hw_ptr %= pcm->boundary;
	// printf("sync ptr diff = %li\n", diff);
	if (pcm->stop_threshold >= pcm->boundary)	/* don't care */
		return 0;
	if ((avail = snd_pcm_mmap_capture_hw_avail(pcm)) >= pcm->stop_threshold) {
		gettimestamp(&dsnoop->trigger_tstamp, pcm->monotonic);
		dsnoop->state = SND_PCM_STATE_XRUN;
		dsnoop->avail_max = avail;
		return -EPIPE;
	}
	if (avail > dsnoop->avail_max)
		dsnoop->avail_max = avail;
	return 0;
}
示例#5
0
文件: dscapture.c 项目: mikekap/wine
static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetPosition(PIDSCDRIVERBUFFER iface, LPDWORD lpdwCappos, LPDWORD lpdwReadpos)
{
    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
    snd_pcm_uframes_t hw_pptr, hw_wptr;

    EnterCriticalSection(&This->pcm_crst);

    if (!This->pcm)
    {
        FIXME("Bad pointer for pcm: %p\n", This->pcm);
        LeaveCriticalSection(&This->pcm_crst);
        return DSERR_GENERIC;
    }

    if (snd_pcm_state(This->pcm) != SND_PCM_STATE_RUNNING)
    {
        CheckXRUN(This);
        hw_pptr = This->mmap_pos;
    }
    else
    {
        /* FIXME: Unused at the moment */
        snd_pcm_uframes_t used = CommitAll(This, FALSE);

        if (This->mmap_pos > used)
            hw_pptr = This->mmap_pos - used;
        else
            hw_pptr = This->mmap_buflen_frames - used + This->mmap_pos;
    }
    hw_wptr = This->mmap_pos;

    if (lpdwCappos)
        *lpdwCappos = realpos_to_fakepos(This, hw_pptr);
    if (lpdwReadpos)
        *lpdwReadpos = realpos_to_fakepos(This, hw_wptr);

    LeaveCriticalSection(&This->pcm_crst);

    TRACE("hw_pptr=%u, hw_wptr=%u playpos=%u(%p), writepos=%u(%p)\n", (unsigned int)hw_pptr, (unsigned int)hw_wptr, realpos_to_fakepos(This, hw_pptr), lpdwCappos, realpos_to_fakepos(This, hw_wptr), lpdwReadpos);
    return DS_OK;
}
示例#6
0
double CAESinkALSA::GetCacheTime()
{
  if (!m_pcm)
    return 0.0;

  int space = snd_pcm_avail_update(m_pcm);
  if (space == 0)
  {
    snd_pcm_state_t state = snd_pcm_state(m_pcm);
    if (state < 0)
    {
      HandleError("snd_pcm_state", state);
      space = m_bufferSize;
    }

    if (state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED)
      space = m_bufferSize;
  }

  return (double)(m_bufferSize - space) * m_formatSampleRateMul;
}
示例#7
0
static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
{
	snd_pcm_direct_t *dshare = pcm->private_data;

	switch (dshare->state) {
	case SNDRV_PCM_STATE_DRAINING:
	case SNDRV_PCM_STATE_RUNNING:
		snd_pcm_dshare_sync_ptr(pcm);
		break;
	default:
		break;
	}
	memset(status, 0, sizeof(*status));
	status->state = snd_pcm_state(dshare->spcm);
	status->trigger_tstamp = dshare->trigger_tstamp;
	status->tstamp = snd_pcm_hw_fast_tstamp(dshare->spcm);
	status->avail = snd_pcm_mmap_playback_avail(pcm);
	status->avail_max = status->avail > dshare->avail_max ? status->avail : dshare->avail_max;
	dshare->avail_max = 0;
	return 0;
}
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;
}
示例#9
0
int
AlsaLayer::read(SFLAudioSample* buffer, int frames)
{
    if (snd_pcm_state(captureHandle_) == SND_PCM_STATE_XRUN) {
        prepareCaptureStream();
        startCaptureStream();
    }

    int err = snd_pcm_readi(captureHandle_, (void*)buffer, frames);

    if (err >= 0)
        return err;

    switch (err) {
        case -EPIPE:
        case -ESTRPIPE:
        case -EIO: {
            snd_pcm_status_t* status;
            snd_pcm_status_alloca(&status);

            if (ALSA_CALL(snd_pcm_status(captureHandle_, status), "Get status failed") >= 0)
                if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
                    stopCaptureStream();
                    prepareCaptureStream();
                    startCaptureStream();
                }

            ERROR("XRUN capture ignored (%s)", snd_strerror(err));
            break;
        }

        case -EPERM:
            ERROR("Can't capture, EPERM (%s)", snd_strerror(err));
            prepareCaptureStream();
            startCaptureStream();
            break;
    }

    return 0;
}
示例#10
0
void SoundOutput_alsa::write_fragment(float *data)
{
	snd_pcm_sframes_t rc;

	if (handle == nullptr) return;

	switch(snd_pcm_state(handle)) {
		case SND_PCM_STATE_XRUN:
		case SND_PCM_STATE_SUSPENDED:
			snd_pcm_prepare(handle);
			break;
		case SND_PCM_STATE_PAUSED:
			snd_pcm_pause(handle, 0);
			break;
		default:
			break;
	}

	rc = snd_pcm_writei(handle, data, frames_in_period);
	if (rc < 0)
		log_event("debug", "ClanSound: snd_pcm_writei() failed!");
}
示例#11
0
文件: dscapture.c 项目: mikekap/wine
static HRESULT WINAPI IDsCaptureDriverBufferImpl_GetStatus(PIDSCDRIVERBUFFER iface, LPDWORD lpdwStatus)
{
    IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface;
    snd_pcm_state_t state;
    TRACE("(%p,%p)\n",iface,lpdwStatus);

    state = snd_pcm_state(This->pcm);
    switch (state)
    {
    case SND_PCM_STATE_XRUN:
    case SND_PCM_STATE_SUSPENDED:
    case SND_PCM_STATE_RUNNING:
        *lpdwStatus = DSCBSTATUS_CAPTURING | (This->play_looping ? DSCBSTATUS_LOOPING : 0);
        break;
    default:
        *lpdwStatus = 0;
        break;
    }

    TRACE("State: %d, flags: 0x%08x\n", state, *lpdwStatus);
    return DS_OK;
}
示例#12
0
    void alsa_print_info(snd_pcm_t * handle, snd_pcm_hw_params_t * hwp) {
        printf("device [%s] opened with\n",
               snd_pcm_name(handle));
        printf("\tstate=%s\n",
               snd_pcm_state_name(snd_pcm_state(handle)));
        unsigned int val, val2;
        snd_pcm_hw_params_get_access(hwp,
                                     (snd_pcm_access_t *) &val);
        printf("\taccess_type=%s\n",
               snd_pcm_access_name((snd_pcm_access_t)val));

        snd_pcm_hw_params_get_format(hwp, (snd_pcm_format_t *) &val);
        printf("\tformat=%s\n",
               snd_pcm_format_name((snd_pcm_format_t) val)
               );

        snd_pcm_hw_params_get_channels(hwp, &val);
        printf("\tchannels=%d\n", val);

        snd_pcm_hw_params_get_rate(hwp, &val, (int *) &val2);
        printf("\trate=%d fps\n", val);

        snd_pcm_hw_params_get_period_time(hwp,
                                          &val, (int *) &val2);
        printf("\tperiod_time=%d us\n", val);

        snd_pcm_uframes_t frames;
        snd_pcm_hw_params_get_period_size(hwp,
                                          &frames, (int *) &val2);
        printf("\tperiod_size=%d frames\n", (int)frames);

        snd_pcm_hw_params_get_buffer_size(hwp,
                                          (snd_pcm_uframes_t *) &val);
        printf("\tbuffer_size=%d frames\n", val);

        snd_pcm_hw_params_get_periods(hwp, &val, (int *) &val2);
        printf("\tperiods_per_buffer=%d periods\n", val);
    }
示例#13
0
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;
}
示例#14
0
static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dmix = pcm->private_data;
	int err;

	switch (snd_pcm_state(dmix->spcm)) {
	case SND_PCM_STATE_DISCONNECTED:
		dmix->state = SND_PCM_STATE_DISCONNECTED;
		return -ENODEV;
	case SND_PCM_STATE_XRUN:
		if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
			return err;
		break;
	default:
		break;
	}
	if (snd_pcm_direct_client_chk_xrun(dmix, pcm))
		return -EPIPE;
	if (dmix->slowptr)
		snd_pcm_hwsync(dmix->spcm);

	return snd_pcm_dmix_sync_ptr0(pcm, *dmix->spcm->hw.ptr);
}
示例#15
0
static void audio_resume(void)
{
    int err;

    if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_SUSPENDED) {
        mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_PcmInSuspendModeTryingResume);
        while ((err = snd_pcm_resume(alsa_handler)) == -EAGAIN) sleep(1);
    }
    if (alsa_can_pause) {
        if ((err = snd_pcm_pause(alsa_handler, 0)) < 0)
        {
            mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmResumeError, snd_strerror(err));
            return;
        }
          mp_msg(MSGT_AO,MSGL_V,"alsa-resume: resume supported by hardware\n");
    } else {
        if ((err = snd_pcm_prepare(alsa_handler)) < 0)
        {
           mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPrepareError, snd_strerror(err));
            return;
        }
    }
}
示例#16
0
static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dmix = pcm->private_data;
	int err;
	snd_pcm_state_t state;
	state = snd_pcm_state(dmix->spcm);
	switch (state) {
	case SND_PCM_STATE_SUSPENDED:
	case SND_PCM_STATE_DISCONNECTED:
		dmix->state = state;
		return state;
	case SND_PCM_STATE_XRUN:
		if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
			return err;
		break;
	default:
		break;
	}
	snd_pcm_direct_client_chk_xrun(dmix, pcm);
	if (dmix->state == STATE_RUN_PENDING)
		return SNDRV_PCM_STATE_RUNNING;
	return dmix->state;
}
示例#17
0
文件: pcm_dsnoop.c 项目: NieHao/R7000
static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
{
	snd_pcm_direct_t *dsnoop = pcm->private_data;
	snd_pcm_state_t state;

	switch(dsnoop->state) {
	case SNDRV_PCM_STATE_DRAINING:
	case SNDRV_PCM_STATE_RUNNING:
		snd_pcm_dsnoop_sync_ptr(pcm);
		break;
	default:
		break;
	}
	memset(status, 0, sizeof(*status));
	state = snd_pcm_state(dsnoop->spcm);
	status->state = state == SND_PCM_STATE_RUNNING ? dsnoop->state : state;
	status->trigger_tstamp = dsnoop->trigger_tstamp;
	status->tstamp = dsnoop->update_tstamp;
	status->avail = snd_pcm_mmap_capture_avail(pcm);
	status->avail_max = status->avail > dsnoop->avail_max ? status->avail : dsnoop->avail_max;
	dsnoop->avail_max = 0;
	return 0;
}
示例#18
0
static int async_loop(snd_pcm_t *handle)
{
	struct async_private_data data;
	snd_async_handler_t *ahandler;
	int err, count;
	err = snd_async_add_pcm_handler(&ahandler, handle, async_callback, &data);
	if (err < 0) 
	{
		printf("Unable to register async handler\n");
		exit(EXIT_FAILURE);
	}
	if (snd_pcm_state(handle) == SND_PCM_STATE_PREPARED)
	 {
		err = snd_pcm_start(handle);
		if (err < 0) 
		{
			printf("Start error: %s\n", snd_strerror(err));
			exit(EXIT_FAILURE);
		}
	}	
	file_capture = fopen("file_capture","w");
	
}
int DAUDIO_GetAvailable(void* id, int isSource) {
    AlsaPcmInfo* info = (AlsaPcmInfo*) id;
    snd_pcm_sframes_t availableInFrames;
    snd_pcm_state_t state;
    int ret;

    state = snd_pcm_state(info->handle);
    if (state == SND_PCM_STATE_XRUN) {
        // if in xrun state then we have the entire buffer available,
        // not 0 as alsa reports
        ret = info->bufferSizeInBytes;
    } else {
        availableInFrames = snd_pcm_avail_update(info->handle);
        if (availableInFrames < 0) {
            ret = 0;
        } else {
            //ret = snd_pcm_frames_to_bytes(info->handle, availableInFrames);
            ret = (int) (availableInFrames * info->frameSize);
        }
    }
    TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret);
    return ret;
}
示例#20
0
/* alsa_mix
 *  Mix and send some samples to ALSA.
 */
static void alsa_mix(void)
{
   int ret, samples = alsa_bufsize;
   unsigned char *ptr = alsa_bufdata;

   while (samples > 0) {
      ret = snd_pcm_writei(pcm_handle, ptr, samples);
      if (ret == -EAGAIN)
	 continue;

      if (ret < 0) {
	 if (xrun_recovery(pcm_handle, ret) < 0)
	    fprintf(stderr, "Write error: %s\n", snd_strerror(ret));
	 poll_next = 0;
	 break;  /* skip one period */
      }
      if (snd_pcm_state(pcm_handle) == SND_PCM_STATE_RUNNING)
	 poll_next = 1;
      samples -= ret;
      ptr += ret * alsa_sample_size;
   }

   _mix_some_samples((uintptr_t)alsa_bufdata, 0, alsa_signed);
}
示例#21
0
int
sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) {
  snd_pcm_sframes_t delay;
  
  if (s == NULL || s->output_unit == NULL) {
    return SA_ERROR_NO_INIT;
  }

  if (position != SA_POSITION_WRITE_SOFTWARE) {
    return SA_ERROR_NOT_SUPPORTED;
  }

  if (snd_pcm_state(s->output_unit) != SND_PCM_STATE_RUNNING) {
    *pos = s->last_position;
    return SA_SUCCESS;
  }

  if (snd_pcm_delay(s->output_unit, &delay) != 0) {
    return SA_ERROR_SYSTEM;
  }

  /* delay means audio is 'x' frames behind what we've written. We need to
     subtract the delay from the data written to return the actual bytes played.

     due to buffering, the delay can be larger than the amount we've
     written--in this case, report position as zero. */
  *pos = s->bytes_written;
  if (*pos >= snd_pcm_frames_to_bytes(s->output_unit, delay)) {
    *pos -= snd_pcm_frames_to_bytes(s->output_unit, delay);
  } else {
    *pos = 0;
  }
  s->last_position = *pos;

  return SA_SUCCESS;
}
示例#22
0
snd_pcm_sframes_t snd_pcm_avail_update(snd_pcm_t *pcm)
{
	snd_pcm_uframes_t avail;

	_snd_pcm_sync_ptr(pcm, 0);
	avail = snd_pcm_mmap_avail(pcm);
	switch (snd_pcm_state(pcm)) {
	case SNDRV_PCM_STATE_RUNNING:
		if (avail >= pcm->sw_params.stop_threshold) {
			if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_XRUN) < 0)
				return -errno;
			/* everything is ok,
			 * state == SND_PCM_STATE_XRUN at the moment
			 */
			return -EPIPE;
		}
		break;
	case SNDRV_PCM_STATE_XRUN:
		return -EPIPE;
	default:
		break;
	}
	return avail;
}
示例#23
0
文件: alsa.c 项目: sailfish009/vlc
static void *Thread (void *data)
{
    demux_t *demux = data;
    demux_sys_t *sys = demux->p_sys;
    snd_pcm_t *pcm = sys->pcm;
    size_t bytes;
    int canc, val;

    canc = vlc_savecancel ();
    bytes = snd_pcm_frames_to_bytes (pcm, sys->period_size);
    val = snd_pcm_start (pcm);
    if (val)
    {
        msg_Err (demux, "cannot prepare device: %s", snd_strerror (val));
        return NULL;
    }

    for (;;)
    {
        block_t *block = block_Alloc (bytes);
        if (unlikely(block == NULL))
            break;

        /* Wait for data */
        Poll (pcm, canc);

        /* Read data */
        snd_pcm_sframes_t frames, delay;
        mtime_t pts;

        frames = snd_pcm_readi (pcm, block->p_buffer, sys->period_size);
        pts = mdate ();
        if (frames < 0)
        {
            block_Release (block);
            if (frames == -EAGAIN)
                continue;

            val = snd_pcm_recover (pcm, frames, 1);
            if (val == 0)
            {
                msg_Warn (demux, "cannot read samples: %s",
                          snd_strerror (frames));
                snd_pcm_state_t state = snd_pcm_state (pcm);
                switch (state)
                {
                case SND_PCM_STATE_PREPARED:
                    val = snd_pcm_start (pcm);
                    if (val < 0)
                    {
                        msg_Err (demux, "cannot prepare device: %s",
                                 snd_strerror (val));
                        return NULL;
                    }
                    continue;
                case SND_PCM_STATE_RUNNING:
                    continue;
                default:
                    break;
                }
            }
            msg_Err (demux, "cannot recover record stream: %s",
                     snd_strerror (val));
            DumpDeviceStatus (demux, pcm);
            break;
        }

        /* Compute time stamp */
        if (snd_pcm_delay (pcm, &delay))
            delay = 0;
        delay += frames;
        pts -= (CLOCK_FREQ * delay) / sys->rate;

        block->i_buffer = snd_pcm_frames_to_bytes (pcm, frames);
        block->i_nb_samples = frames;
        block->i_pts = pts;
        block->i_length = (CLOCK_FREQ * frames) / sys->rate;

        es_out_SetPCR(demux->out, block->i_pts);
        es_out_Send (demux->out, sys->es, block);
    }
    return NULL;
}
static DECLCALLBACK(int) drvHostALSAAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
                                                   uint32_t *pcSamplesCaptured)
{
    NOREF(pInterface);
    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);

    PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;

    snd_pcm_sframes_t cAvail;
    int rc = drvHostALSAAudioGetAvail(pThisStrmIn->phPCM, &cAvail);
    if (RT_FAILURE(rc))
    {
        LogFunc(("Error getting number of captured frames, rc=%Rrc\n", rc));
        return rc;
    }

    if (!cAvail) /* No data yet? */
    {
        snd_pcm_state_t state = snd_pcm_state(pThisStrmIn->phPCM);
        switch (state)
        {
            case SND_PCM_STATE_PREPARED:
                cAvail = AudioMixBufFree(&pHstStrmIn->MixBuf);
                break;

            case SND_PCM_STATE_SUSPENDED:
            {
                rc = drvHostALSAAudioResume(pThisStrmIn->phPCM);
                if (RT_FAILURE(rc))
                    break;

                LogFlow(("Resuming suspended input stream\n"));
                break;
            }

            default:
                LogFlow(("No frames available, state=%d\n", state));
                break;
        }

        if (!cAvail)
        {
            if (pcSamplesCaptured)
                *pcSamplesCaptured = 0;
            return VINF_SUCCESS;
        }
    }

    /*
     * Check how much we can read from the capture device without overflowing
     * the mixer buffer.
     */
    Assert(cAvail);
    size_t cbMixFree = AudioMixBufFreeBytes(&pHstStrmIn->MixBuf);
    size_t cbToRead = RT_MIN((size_t)AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cAvail), cbMixFree);

    LogFlowFunc(("cbToRead=%zu, cAvail=%RI32\n", cbToRead, cAvail));

    uint32_t cWrittenTotal = 0;
    snd_pcm_uframes_t cToRead;
    snd_pcm_sframes_t cRead;

    while (   cbToRead
           && RT_SUCCESS(rc))
    {
        cToRead = RT_MIN(AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cbToRead),
                         AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, pThisStrmIn->cbBuf));
        AssertBreakStmt(cToRead, rc = VERR_NO_DATA);
        cRead = snd_pcm_readi(pThisStrmIn->phPCM, pThisStrmIn->pvBuf, cToRead);
        if (cRead <= 0)
        {
            switch (cRead)
            {
                case 0:
                {
                    LogFunc(("No input frames available\n"));
                    rc = VERR_ACCESS_DENIED;
                    break;
                }

                case -EAGAIN:
                    /*
                     * Don't set error here because EAGAIN means there are no further frames
                     * available at the moment, try later. As we might have read some frames
                     * already these need to be processed instead.
                     */
                    cbToRead = 0;
                    break;

                case -EPIPE:
                {
                    rc = drvHostALSAAudioRecover(pThisStrmIn->phPCM);
                    if (RT_FAILURE(rc))
                        break;

                    LogFlowFunc(("Recovered from capturing\n"));
                    continue;
                }

                default:
                    LogFunc(("Failed to read input frames: %s\n", snd_strerror(cRead)));
                    rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
                    break;
            }
        }
        else
        {
            uint32_t cWritten;
            rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf,
                                      pThisStrmIn->pvBuf, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cRead),
                                      &cWritten);
            if (RT_FAILURE(rc))
                break;

            /*
             * We should not run into a full mixer buffer or we loose samples and
             * run into an endless loop if ALSA keeps producing samples ("null"
             * capture device for example).
             */
            AssertLogRelMsgBreakStmt(cWritten > 0, ("Mixer buffer shouldn't be full at this point!\n"),
                                     rc = VERR_INTERNAL_ERROR);
            uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);

            Assert(cbToRead >= cbWritten);
            cbToRead -= cbWritten;
            cWrittenTotal += cWritten;
        }
    }

    if (RT_SUCCESS(rc))
    {
        uint32_t cProcessed = 0;
        if (cWrittenTotal)
            rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
                                        &cProcessed);

        if (pcSamplesCaptured)
            *pcSamplesCaptured = cWrittenTotal;

        LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
                     cWrittenTotal, cProcessed, rc));
    }

    LogFlowFuncLeaveRC(rc);
    return rc;
}
示例#25
0
/**************************************************************************
 * 				widRecorder			[internal]
 */
static	DWORD	CALLBACK	widRecorder(LPVOID pmt)
{
    WORD		uDevID = (DWORD_PTR)pmt;
    WINE_WAVEDEV*	wwi = &WInDev[uDevID];
    WAVEHDR*		lpWaveHdr;
    DWORD		dwSleepTime;
    DWORD		bytesRead;
    enum win_wm_message msg;
    DWORD_PTR		param;
    HANDLE		ev;
    DWORD               frames_per_period;

    wwi->state = WINE_WS_STOPPED;
    InterlockedExchange((LONG*)&wwi->dwTotalRecorded, 0);
    wwi->lpQueuePtr = NULL;

    SetEvent(wwi->hStartUpEvent);

    /* make sleep time to be # of ms to output a period */
    dwSleepTime = (wwi->dwPeriodSize * 1000) / wwi->format.Format.nAvgBytesPerSec;
    frames_per_period = snd_pcm_bytes_to_frames(wwi->pcm, wwi->dwPeriodSize);
    TRACE("sleeptime=%d ms, total buffer length=%d ms (%d bytes)\n", dwSleepTime, wwi->dwBufferSize * 1000 / wwi->format.Format.nAvgBytesPerSec, wwi->dwBufferSize);

    for (;;) {
	/* wait for dwSleepTime or an event in thread's queue */
	if (wwi->lpQueuePtr != NULL && wwi->state == WINE_WS_PLAYING)
        {
            DWORD frames;
            DWORD bytes;
            DWORD read;

            lpWaveHdr = wwi->lpQueuePtr;
            /* read all the fragments accumulated so far */
            frames = snd_pcm_avail_update(wwi->pcm);
            bytes = snd_pcm_frames_to_bytes(wwi->pcm, frames);

            TRACE("frames = %d  bytes = %d state=%d\n", frames, bytes, snd_pcm_state(wwi->pcm));
            if (snd_pcm_state(wwi->pcm) == SND_PCM_STATE_XRUN)
            {
                FIXME("Recovering from XRUN!\n");
                snd_pcm_prepare(wwi->pcm);
                frames = snd_pcm_avail_update(wwi->pcm);
                bytes = snd_pcm_frames_to_bytes(wwi->pcm, frames);
                snd_pcm_start(wwi->pcm);
                snd_pcm_forward(wwi->pcm, frames - snd_pcm_bytes_to_frames(wwi->pcm, wwi->dwPeriodSize));
                continue;
            }
            while (frames > 0 && wwi->lpQueuePtr)
            {
                TRACE("bytes = %d\n", bytes);
                if (lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded < bytes)
                {
                    bytes = lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded;
                    frames = snd_pcm_bytes_to_frames(wwi->pcm, bytes);
                }
                /* directly read fragment in wavehdr */
                read = wwi->read(wwi->pcm, lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded, frames);
                bytesRead = snd_pcm_frames_to_bytes(wwi->pcm, read);

                TRACE("bytesRead=(%d(%d)/(%d)) -> (%d/%d)\n", bytesRead, read, frames, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded);
                if (read != (DWORD) -1)
                {
                    /* update number of bytes recorded in current buffer and by this device */
                    lpWaveHdr->dwBytesRecorded += bytesRead;
                    InterlockedExchangeAdd((LONG*)&wwi->dwTotalRecorded, bytesRead);
                    frames -= read;
                    bytes -= bytesRead;

                    /* buffer is full. notify client */
                    if (!snd_pcm_bytes_to_frames(wwi->pcm, lpWaveHdr->dwBytesRecorded - lpWaveHdr->dwBufferLength))
                    {
                        /* must copy the value of next waveHdr, because we have no idea of what
                         * will be done with the content of lpWaveHdr in callback
                         */
                        LPWAVEHDR	lpNext = lpWaveHdr->lpNext;

                        lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
                        lpWaveHdr->dwFlags |=  WHDR_DONE;

                        wwi->lpQueuePtr = lpNext;
                        widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
                        lpWaveHdr = lpNext;
                    }
                } else {
                    WARN("read(%s, %p, %d) failed (%d/%s)\n", wwi->pcmname,
                        lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
                        frames, frames, snd_strerror(read));
                }
            }
        }

        ALSA_WaitRingMessage(&wwi->msgRing, dwSleepTime);

	while (ALSA_RetrieveRingMessage(&wwi->msgRing, &msg, &param, &ev))
	{
            TRACE("msg=%s param=0x%lx\n", ALSA_getCmdString(msg), param);
	    switch (msg) {
	    case WINE_WM_PAUSING:
		wwi->state = WINE_WS_PAUSED;
                /*FIXME("Device should stop recording\n");*/
		SetEvent(ev);
		break;
	    case WINE_WM_STARTING:
		wwi->state = WINE_WS_PLAYING;
		snd_pcm_start(wwi->pcm);
		SetEvent(ev);
		break;
	    case WINE_WM_HEADER:
		lpWaveHdr = (LPWAVEHDR)param;
		lpWaveHdr->lpNext = 0;

		/* insert buffer at the end of queue */
		{
		    LPWAVEHDR*	wh;
		    for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
		    *wh = lpWaveHdr;
		}
		break;
	    case WINE_WM_STOPPING:
		if (wwi->state != WINE_WS_STOPPED)
		{
		    snd_pcm_drain(wwi->pcm);

		    /* read any headers in queue */
		    widRecorder_ReadHeaders(wwi);

		    /* return current buffer to app */
		    lpWaveHdr = wwi->lpQueuePtr;
		    if (lpWaveHdr)
		    {
		        LPWAVEHDR	lpNext = lpWaveHdr->lpNext;
		        TRACE("stop %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
		        lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
		        lpWaveHdr->dwFlags |= WHDR_DONE;
		        wwi->lpQueuePtr = lpNext;
		        widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
		    }
		}
		wwi->state = WINE_WS_STOPPED;
		SetEvent(ev);
		break;
	    case WINE_WM_RESETTING:
		if (wwi->state != WINE_WS_STOPPED)
		{
		    snd_pcm_drain(wwi->pcm);
		}
		wwi->state = WINE_WS_STOPPED;
		wwi->dwTotalRecorded = 0;

		/* read any headers in queue */
		widRecorder_ReadHeaders(wwi);

		/* return all buffers to the app */
		while (wwi->lpQueuePtr) {
		    lpWaveHdr = wwi->lpQueuePtr;
		    TRACE("reset %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
                    wwi->lpQueuePtr = lpWaveHdr->lpNext;
		    lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
		    lpWaveHdr->dwFlags |= WHDR_DONE;
		    widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
		}

		SetEvent(ev);
		break;
	    case WINE_WM_CLOSING:
		wwi->hThread = 0;
		wwi->state = WINE_WS_CLOSED;
		SetEvent(ev);
		ExitThread(0);
		/* shouldn't go here */
	    default:
		FIXME("unknown message %d\n", msg);
		break;
	    }
	}
    }
    ExitThread(0);
    /* just for not generating compilation warnings... should never be executed */
    return 0;
}
示例#26
0
int main( int argc, char *argv[] )
{
    struct structArgs cmdArgs;
	unsigned int val, val2;
	int dir;
    int errNum;
	cmdArgs.card = 0;		// Default card.
	cmdArgs.control = 1;	// Default control.


    // ************************************************************************
    //  ALSA control elements.
    // ************************************************************************
    snd_pcm_t *pcmp;
    snd_pcm_hw_params_t *params;
//	snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
	snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
    snd_pcm_uframes_t frames;


    // ************************************************************************
    //  Get command line parameters.
    // ************************************************************************
    argp_parse( &argp, argc, argv, 0, 0, &cmdArgs );

    printf( "Card = %i\n", cmdArgs.card );
    printf( "Control = %i\n", cmdArgs.control );
    sprintf( cmdArgs.deviceID, "hw:%i,%i", cmdArgs.card, cmdArgs.control );
	printf( "Using device %s :", cmdArgs.deviceID );

    /* Allocate a hardware parameters object. */
    if ( snd_pcm_hw_params_alloca( &params ) < 0 )
    {
    	fprintf( stderr, "Unable to allocate.\n" );
    	return -1;
   	}
    /* Open PCM device for playback. */
//    if ( snd_pcm_open( &pcmp, cmdArgs.deviceID, stream, 0 ) < 0 )
//    {
//        fprintf( stderr, "Unable to open pcm device.\n" );
//    	return -1;
//    }
    /* Fill it in with default values. */
//    if ( snd_pcm_hw_params_any( pcmp, params ) < 0
//    {
//    	fprintf( stderr, "Unable to set default values.\n" );
//    	return -1;
//    }
    /* Interleaved mode */
//    snd_pcm_hw_params_set_access( pcmp, params,
//    		SND_PCM_ACCESS_RW_INTERLEAVED );

    /* Signed 16-bit little-endian format */
    snd_pcm_hw_params_set_format( pcmp, params,
        	SND_PCM_FORMAT_S16_LE );

    /* Two channels (stereo) */
    snd_pcm_hw_params_set_channels( pcmp, params, 2 );

    /* 44100 bits/second sampling rate (CD quality) */
    val = 44100;
    snd_pcm_hw_params_set_rate_near( pcmp, params, &val, &dir );

    /* Write the parameters to the driver */
    errNum = snd_pcm_hw_params( pcmp, params );
    if ( errNum < 0 )
    {
        fprintf(stderr, "unable to set hw parameters: %s\n",
            snd_strerror( errNum ));
        exit( 1 );
    }

    /* Display information about the PCM interface */

    printf( "PCM handle name = '%s'\n", snd_pcm_name( pcmp ));

    printf("PCM state = %s\n", snd_pcm_state_name( snd_pcm_state( pcmp )));

    snd_pcm_hw_params_get_access( params, ( snd_pcm_access_t * ) &val );
    printf( "access type = %s\n",
        snd_pcm_access_name(( snd_pcm_access_t ) val ));

    snd_pcm_hw_params_get_format( params, ( snd_pcm_format_t * ) &val );
    printf( "format = '%s' (%s)\n",
        snd_pcm_format_name(( snd_pcm_format_t ) val ),
        snd_pcm_format_description(( snd_pcm_format_t ) val ));

    snd_pcm_hw_params_get_subformat( params,
        ( snd_pcm_subformat_t * ) &val );
    printf( "subformat = '%s' (%s)\n",
        snd_pcm_subformat_name(( snd_pcm_subformat_t ) val ),
        snd_pcm_subformat_description((
        snd_pcm_subformat_t ) val ));

    snd_pcm_hw_params_get_channels( params, &val );
    printf( "channels = %d\n", val );

    snd_pcm_hw_params_get_rate( params, &val, &dir );
    printf( "rate = %d bps\n", val );

    snd_pcm_hw_params_get_period_time( params, &val, &dir );
    printf( "period time = %d us\n", val );

    snd_pcm_hw_params_get_period_size( params, &frames, &dir );
    printf( "period size = %d frames\n", ( int ) frames );

    snd_pcm_hw_params_get_buffer_time( params, &val, &dir );
    printf( "buffer time = %d us\n", val );

    snd_pcm_hw_params_get_buffer_size( params,
        ( snd_pcm_uframes_t * ) &val );
    printf( "buffer size = %d frames\n", val );

    snd_pcm_hw_params_get_periods( params, &val, &dir );
    printf( "periods per buffer = %d frames\n", val );

    snd_pcm_hw_params_get_rate_numden( params, &val, &val2 );
    printf( "exact rate = %d/%d bps\n", val, val2 );

    val = snd_pcm_hw_params_get_sbits( params );
    printf( "significant bits = %d\n", val );

//    snd_pcm_hw_params_get_tick_time( params, &val, &dir );
//    printf( "tick time = %d us\n", val );

    val = snd_pcm_hw_params_is_batch( params );
    printf( "is batch = %d\n", val );

    val = snd_pcm_hw_params_is_block_transfer( params );
    printf( "is block transfer = %d\n", val );

    val = snd_pcm_hw_params_is_double( params );
    printf( "is double = %d\n", val );

    val = snd_pcm_hw_params_is_half_duplex( params );
    printf( "is half duplex = %d\n", val );

    val = snd_pcm_hw_params_is_joint_duplex( params );
    printf( "is joint duplex = %d\n", val );

    val = snd_pcm_hw_params_can_overrange( params );
    printf( "can overrange = %d\n", val );

    val = snd_pcm_hw_params_can_mmap_sample_resolution( params );
    printf( "can mmap = %d\n", val );

    val = snd_pcm_hw_params_can_pause( params );
    printf( "can pause = %d\n", val );

    val = snd_pcm_hw_params_can_resume( params );
    printf( "can resume = %d\n", val );

    val = snd_pcm_hw_params_can_sync_start( params );
    printf( "can sync start = %d\n", val );
    snd_pcm_close( pcmp );

    return 0;
}
示例#27
0
snd_pcm_state_t snd_pcm_generic_state(snd_pcm_t *pcm)
{
    snd_pcm_generic_t *generic = pcm->private_data;
    return snd_pcm_state(generic->slave);
}
示例#28
0
int alsamm_send_dacs(void)
{

  static double timenow,timelast;

  t_sample *fpo, *fpi, *fp1, *fp2;
  int i, err, devno;

  const snd_pcm_channel_area_t *my_areas;
  snd_pcm_sframes_t size;
  snd_pcm_sframes_t commitres;
  snd_pcm_state_t state;
  snd_pcm_sframes_t ooffset, oavail;
  snd_pcm_sframes_t ioffset, iavail;

  /*
     unused channels should be zeroed out on startup (open) and stay this
  */
  int inchannels = STUFF->st_inchannels;
  int outchannels = STUFF->st_outchannels;

  timelast = sys_getrealtime();

#ifdef ALSAMM_DEBUG
  if(dac_send++ < 0)
    post("dac send called in %d, out %d, xrun %d",inchannels,outchannels, alsamm_xruns);

  if(alsamm_xruns && (alsamm_xruns % 1000) == 0)
    post("1000 xruns accoured");

  if(dac_send < WATCH_PERIODS){
    out_cm[dac_send] = -1;
    in_avail[dac_send] = out_avail[dac_send] = -1;
    in_offset[dac_send] = out_offset[dac_send] = -1;
    outaddr[dac_send] = inaddr[dac_send] = NULL;
    xruns_watch[dac_send] = alsamm_xruns;
  }
#endif

  if (!inchannels && !outchannels)
    {
      return SENDDACS_NO;
    }

  /* here we should check if in and out samples are here.
     but, the point is if out samples available also in sample should,
     so we don't make a precheck of insamples here and let outsample check be the
     the first of the forst card.
  */


  /* OUTPUT Transfer */
  fpo = STUFF->st_soundout;
  for(devno = 0;devno < alsa_noutdev;devno++){

    t_alsa_dev *dev = &alsa_outdev[devno];
    snd_pcm_t *out = dev->a_handle;
    int ochannels =dev->a_channels;



    /* how much samples available ??? */
    oavail = snd_pcm_avail_update(out);

    /* only one reason i can think about,
       the driver stopped and says broken pipe
       so this should not happen if we have enough stopthreshhold
       but if try to restart with next commit
    */
    if (oavail < 0) {

#ifdef ALSAMM_DEBUG
      broken_opipe++;
#endif
      err = xrun_recovery(out, -EPIPE);
      if (err < 0) {
        check_error(err,"otavail<0 recovery failed");
        return SENDDACS_NO;
      }
      oavail = snd_pcm_avail_update(out);
    }

    /* check if we are late and have to (able to) catch up */
    /* xruns will be ignored since you cant do anything since already happened */
    state = snd_pcm_state(out);
    if (state == SND_PCM_STATE_XRUN) {
      err = xrun_recovery(out, -EPIPE);
      if (err < 0) {
        check_error(err,"DAC XRUN recovery failed");
        return SENDDACS_NO;
      }
      oavail = snd_pcm_avail_update(out);

    } else if (state == SND_PCM_STATE_SUSPENDED) {
      err = xrun_recovery(out, -ESTRPIPE);
      if (err < 0) {
        check_error(err,"DAC SUSPEND recovery failed");
        return SENDDACS_NO;
      }
      oavail = snd_pcm_avail_update(out);
    }

#ifdef ALSAMM_DEBUG
    if(dac_send < WATCH_PERIODS){
      out_avail[dac_send] = oavail;
    }
#endif

    /* we only transfer transfersize of bytes request,
       this should only happen on first card otherwise we got a problem :-(()*/

    if(oavail < alsamm_transfersize){
      return SENDDACS_NO;
    }

    /* transfer now */
    size = alsamm_transfersize;
    fp1 = fpo;
    ooffset = 0;

    /* since this can go over a buffer boundery we maybe need two steps to
       transfer (normally when buffersize is a multiple of transfersize
       this should never happen) */

    while (size > 0) {

      int chn;
      snd_pcm_sframes_t oframes;

      oframes = size;

      err =  alsamm_get_channels(out, (unsigned long *)&oframes,
        (unsigned long *)&ooffset,ochannels,dev->a_addr);

#ifdef ALSAMM_DEBUG
      if(dac_send < WATCH_PERIODS){
        out_offset[dac_send] = ooffset;
        outaddr[dac_send] = (char *) dev->a_addr[0];
      }
#endif

      if (err < 0){
        if ((err = xrun_recovery(out, err)) < 0) {
          check_error(err,"MMAP begins avail error");
          break; /* next card please */
        }
      }

      /* transfer into memory */
      for (chn = 0; chn < ochannels; chn++) {

        t_alsa_sample32 *buf = (t_alsa_sample32 *)dev->a_addr[chn];

        /*
        osc(buf, oframes, (dac_send%1000 < 500)?-100.0:-10.0,440,&(indexes[chn]));
        */

        for (i = 0, fp2 = fp1 + chn*alsamm_transfersize; i < oframes; i++,fp2++)
          {
            float s1 = *fp2 * F32MAX;
            /* better but slower, better never clip ;-)
               buf[i]= CLIP32(s1); */
            buf[i]= ((int) s1 & 0xFFFFFF00);
            *fp2 = 0.0;
          }
      }

      commitres = snd_pcm_mmap_commit(out, ooffset, oframes);
      if (commitres < 0 || commitres != oframes) {
        if ((err = xrun_recovery(out, commitres >= 0 ? -EPIPE : commitres)) < 0) {
          check_error(err,"MMAP commit error");
          return SENDDACS_NO;
        }
      }

#ifdef ALSAMM_DEBUG
      if(dac_send < WATCH_PERIODS)
        out_cm[dac_send] = oframes;
#endif

      fp1 += oframes;
      size -= oframes;
    } /* while size */
    fpo += ochannels*alsamm_transfersize;

  }/* for devno */


  fpi = STUFF->st_soundin; /* star first card first channel */

  for(devno = 0;devno < alsa_nindev;devno++){

    t_alsa_dev *dev = &alsa_indev[devno];
    snd_pcm_t *in = dev->a_handle;
    int ichannels = dev->a_channels;

    iavail = snd_pcm_avail_update(in);

    if (iavail < 0) {
      err = xrun_recovery(in, iavail);
      if (err < 0) {
        check_error(err,"input avail update failed");
        return SENDDACS_NO;
      }
      iavail=snd_pcm_avail_update(in);
    }

    state = snd_pcm_state(in);

    if (state == SND_PCM_STATE_XRUN) {
      err = xrun_recovery(in, -EPIPE);
      if (err < 0) {
        check_error(err,"ADC XRUN recovery failed");
        return SENDDACS_NO;
      }
      iavail=snd_pcm_avail_update(in);

    } else if (state == SND_PCM_STATE_SUSPENDED) {
      err = xrun_recovery(in, -ESTRPIPE);
      if (err < 0) {
        check_error(err,"ADC SUSPEND recovery failed");
        return SENDDACS_NO;
      }
      iavail=snd_pcm_avail_update(in);
    }

    /* only transfer full transfersize or nothing */
    if(iavail < alsamm_transfersize){
      return SENDDACS_NO;
    }
    size = alsamm_transfersize;
    fp1 = fpi;
    ioffset = 0;

    /* since sysdata can go over a driver buffer boundery we maybe need two steps to
       transfer (normally when buffersize is a multiple of transfersize
       this should never happen) */

    while(size > 0){
      int chn;
      snd_pcm_sframes_t iframes = size;

      err =  alsamm_get_channels(in,
        (unsigned long *)&iframes, (unsigned long *)&ioffset,ichannels,dev->a_addr);
      if (err < 0){
        if ((err = xrun_recovery(in, err)) < 0) {
          check_error(err,"MMAP begins avail error");
          return SENDDACS_NO;
        }
      }

#ifdef ALSAMM_DEBUG
      if(dac_send < WATCH_PERIODS){
        in_avail[dac_send] = iavail;
        in_offset[dac_send] = ioffset;
        inaddr[dac_send] = dev->a_addr[0];
      }
#endif
      /* transfer into memory */

      for (chn = 0; chn < ichannels; chn++) {

        t_alsa_sample32 *buf = (t_alsa_sample32 *) dev->a_addr[chn];

        for (i = 0, fp2 = fp1 + chn*alsamm_transfersize; i < iframes; i++,fp2++)
          {
            /* mask the lowest bits, since subchannels info can make zero samples nonzero */
            *fp2 = (float) ((t_alsa_sample32) (buf[i] & 0xFFFFFF00))
              * (1.0 / (float) INT32_MAX);
          }
      }

      commitres = snd_pcm_mmap_commit(in, ioffset, iframes);
      if (commitres < 0 || commitres != iframes) {
        post("please never");
        if ((err = xrun_recovery(in, commitres >= 0 ? -EPIPE : commitres)) < 0) {
          check_error(err,"MMAP synced in commit error");
          return SENDDACS_NO;
        }
      }
      fp1 += iframes;
      size -= iframes;
    }
    fpi += ichannels*alsamm_transfersize;
  } /* for out devno < alsamm_outcards*/


  if ((timenow = sys_getrealtime()) > (timelast + sleep_time))
    {

#ifdef ALSAMM_DEBUG
      if(dac_send < 10 && sys_verbose)
        post("slept %f > %f + %f (=%f)",
             timenow,timelast,sleep_time,(timelast + sleep_time));
#endif
      return (SENDDACS_SLEPT);
    }

  return SENDDACS_YES;
}
示例#29
0
/* locked version */
static int __snd_pcm_dmix_drain(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dmix = pcm->private_data;
	snd_pcm_uframes_t stop_threshold;
	int err = 0;

	switch (snd_pcm_state(dmix->spcm)) {
	case SND_PCM_STATE_SUSPENDED:
		return -ESTRPIPE;
	default:
		break;
	}

	if (dmix->state == SND_PCM_STATE_OPEN)
		return -EBADFD;
	if (dmix->state == SND_PCM_STATE_PREPARED) {
		if (snd_pcm_mmap_playback_hw_avail(pcm) > 0)
			snd_pcm_dmix_start(pcm);
		else {
			snd_pcm_dmix_drop(pcm);
			return 0;
		}
	}

	if (dmix->state == SND_PCM_STATE_XRUN) {
		snd_pcm_dmix_drop(pcm);
		return 0;
	}

	stop_threshold = pcm->stop_threshold;
	if (pcm->stop_threshold > pcm->buffer_size)
		pcm->stop_threshold = pcm->buffer_size;
	dmix->state = SND_PCM_STATE_DRAINING;
	do {
		err = snd_pcm_dmix_sync_ptr(pcm);
		if (err < 0) {
			snd_pcm_dmix_drop(pcm);
			goto done;
		}
		if (dmix->state == SND_PCM_STATE_DRAINING) {
			snd_pcm_dmix_sync_area(pcm);
			if ((pcm->mode & SND_PCM_NONBLOCK) == 0) {
				snd_pcm_wait_nocheck(pcm, -1);
				snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */
			}

			switch (snd_pcm_state(dmix->spcm)) {
			case SND_PCM_STATE_SUSPENDED:
				err = -ESTRPIPE;
				goto done;
			default:
				break;
			}
		}
		if (pcm->mode & SND_PCM_NONBLOCK) {
			if (dmix->state == SND_PCM_STATE_DRAINING) {
				err = -EAGAIN;
				goto done;
			}
		}
	} while (dmix->state == SND_PCM_STATE_DRAINING);
done:
	pcm->stop_threshold = stop_threshold;
	return err;
}
示例#30
0
    bool open()
    {
        // Open the Alsa playback device.
        int err=-1,count=0;
        unsigned int        freakuency = frequency;

        while((count < 5) && (err < 0)) {
            err = snd_pcm_open
                  ( &handle,  ALSA_OUTPUT_NAME, SND_PCM_STREAM_PLAYBACK, 0 );

            if(err < 0) {
                count++;
                qWarning()<<"QAudioOutput::open() err="<<err<<", count="<<count;
            }
        }
        if (( err < 0)||(handle == 0)) {
            qWarning( "QAudioOuput: snd_pcm_open: error %d", err );
            return false;
        }
        snd_pcm_nonblock( handle, 0 );

        // Set the desired HW parameters.
        snd_pcm_hw_params_t *hwparams;
        snd_pcm_hw_params_alloca( &hwparams );

        err = snd_pcm_hw_params_any( handle, hwparams );
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_any: err %d", err);
            return false;
        }

        err = snd_pcm_hw_params_set_access( handle, hwparams, access );
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_access: err %d", err);
            return false;
        }

        err = snd_pcm_hw_params_set_format( handle, hwparams,
             ( bitsPerSample == 16 ? SND_PCM_FORMAT_S16
                                   : SND_PCM_FORMAT_U8 ) );
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_format: err %d", err);
            return false;
        }

        err = snd_pcm_hw_params_set_channels
            ( handle, hwparams, (unsigned int)channels );
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_channels: err %d", err);
            return false;
        }

        err = snd_pcm_hw_params_set_rate_near
            ( handle, hwparams, &freakuency, 0 );
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_rate_near: err %d", err);
            return false;
        }

#ifndef ALSA_BUFFER_SIZE
        err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err %d",err);
        }
        err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_get_buffer_size: err %d",err);
        }
#else
        buffer_size = ALSA_BUFFER_SIZE;
        err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err %d",err);
        }
#endif

#ifndef ALSA_PERIOD_SIZE
        period_time = buffer_time/4;
        err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_period_time_near: err %d",err);
        }
#else
        period_size = ALSA_PERIOD_SIZE;
        err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, 0);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params_set_period_size_near: err %d",err);
        }
#endif

        err = snd_pcm_hw_params(handle, hwparams);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_hw_params: err %d", err);
            return false;
        }

        int                  dir;
        unsigned int         vval, vval2;
        snd_pcm_access_t     val;
        snd_pcm_format_t     fval;
        snd_pcm_subformat_t  sval;


        qLog(QAudioOutput) << "PCM handle name =" << snd_pcm_name(handle);
        qLog(QAudioOutput) << "PCM state =" << snd_pcm_state_name(snd_pcm_state(handle));
        snd_pcm_hw_params_get_access(hwparams,&val);
        vval = (unsigned int)val;
        if ( (int)vval != (int)access ) {
            qWarning( "QAudioInput: access type not set, want %s got %s",
                    snd_pcm_access_name((snd_pcm_access_t)access),
                    snd_pcm_access_name((snd_pcm_access_t)vval) );
            access = (snd_pcm_access_t)vval;
        }
        qLog(QAudioOutput) << "access type =" << snd_pcm_access_name((snd_pcm_access_t)vval);
        snd_pcm_hw_params_get_format(hwparams, &fval);
        vval = (unsigned int)fval;
        if ( (int)vval != (int)format ) {
            qWarning( "QAudioInput: format type not set, want %s got %s",
                    snd_pcm_format_name((snd_pcm_format_t)format),
                    snd_pcm_format_name((snd_pcm_format_t)vval) );
            format = (snd_pcm_format_t)vval;
        }
        qLog(QAudioOutput) << QString("format = '%1' (%2)").arg(snd_pcm_format_name((snd_pcm_format_t)vval))
            .arg(snd_pcm_format_description((snd_pcm_format_t)vval))
            .toLatin1().constData();
        snd_pcm_hw_params_get_subformat(hwparams,&sval);
        vval = (unsigned int)sval;
        qLog(QAudioOutput) << QString("subformat = '%1' (%2)").arg(snd_pcm_subformat_name((snd_pcm_subformat_t)vval))
            .arg(snd_pcm_subformat_description((snd_pcm_subformat_t)vval))
            .toLatin1().constData();
        snd_pcm_hw_params_get_channels(hwparams, &vval);
        if ( (int)vval != (int)channels ) {
            qWarning( "QAudioInput: channels type not set, want %d got %d",channels,vval);
            channels = vval;
        }
        qLog(QAudioOutput) << "channels =" << vval;
        snd_pcm_hw_params_get_rate(hwparams, &vval, &dir);
        if ( (int)vval != (int)frequency ) {
            qWarning( "QAudioInput: frequency type not set, want %d got %d",frequency,vval);
            frequency = vval;
        }
        qLog(QAudioOutput) << "rate =" << vval << "bps";
        snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);
        qLog(QAudioOutput) << "period time =" << period_time << "us";
        snd_pcm_hw_params_get_period_size(hwparams,&period_size, &dir);
        qLog(QAudioOutput) << "period size =" << (int)period_size << "frames";
        qLog(QAudioOutput) << "buffer time =" << (int)buffer_time << "us";
        qLog(QAudioOutput) << "buffer size =" << (int)buffer_size << "frames";
        snd_pcm_hw_params_get_periods(hwparams, &vval, &dir);
        periods = vval;
        qLog(QAudioOutput) << "periods per buffer =" << vval << "frames";
        snd_pcm_hw_params_get_rate_numden(hwparams, &vval, &vval2);
        qLog(QAudioOutput) << QString("exact rate = %1/%2 bps").arg(vval).arg(vval2).toLatin1().constData();
        vval = snd_pcm_hw_params_get_sbits(hwparams);
        qLog(QAudioOutput) << "significant bits =" << vval;
        vval = snd_pcm_hw_params_is_batch(hwparams);
        qLog(QAudioOutput) << "is batch =" << vval;
        vval = snd_pcm_hw_params_is_block_transfer(hwparams);
        qLog(QAudioOutput) << "is block transfer =" << vval;
        vval = snd_pcm_hw_params_is_double(hwparams);
        qLog(QAudioOutput) << "is double =" << vval;
        vval = snd_pcm_hw_params_is_half_duplex(hwparams);
        qLog(QAudioOutput) << "is half duplex =" << vval;
        vval = snd_pcm_hw_params_is_joint_duplex(hwparams);
        qLog(QAudioOutput) << "is joint duplex =" << vval;
        vval = snd_pcm_hw_params_can_overrange(hwparams);
        qLog(QAudioOutput) << "can overrange =" << vval;
        vval = snd_pcm_hw_params_can_mmap_sample_resolution(hwparams);
        qLog(QAudioOutput) << "can mmap =" << vval;
        vval = snd_pcm_hw_params_can_pause(hwparams);
        qLog(QAudioOutput) << "can pause =" << vval;
        vval = snd_pcm_hw_params_can_resume(hwparams);
        qLog(QAudioOutput) << "can resume =" << vval;
        vval = snd_pcm_hw_params_can_sync_start(hwparams);
        qLog(QAudioOutput) << "can sync start =" << vval;

        // Set the desired SW parameters.
        snd_pcm_sw_params_t *swparams;
        snd_pcm_sw_params_alloca(&swparams);
        err = snd_pcm_sw_params_current(handle, swparams);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_sw_params_current: err %d",err);
        }
        err = snd_pcm_sw_params_set_start_threshold(handle,swparams,buffer_size);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_sw_params_set_start_threshold: err %d",err);
        }
        err = snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_size);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_sw_params_set_stop_threshold: err %d",err);
        }
        err = snd_pcm_sw_params_set_avail_min(handle, swparams,period_size);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_sw_params_set_avail_min: err %d",err);
        }
        err = snd_pcm_sw_params(handle, swparams);
        if ( err < 0 ) {
            qWarning( "QAudioOutput: snd_pcm_sw_params: err %d",err);
        }

        // Prepare for audio output.
        snd_pcm_prepare( handle );

        return true;
    }