Exemplo n.º 1
0
/*
 * Might be called from signal handlers.
 */
int alsa_hook_writen(alsa_hook_t alsa_hook, snd_pcm_t *pcm,
		     void **bufs, snd_pcm_uframes_t size)
{
	struct alsa_hook_stream_s *stream;
	int c, ret = 0;
	int savedErrno = errno;

	if (!(alsa_hook->flags & ALSA_HOOK_CAPTURING))
		goto leave;

	alsa_hook_get_stream(alsa_hook, pcm, &stream);

	if (unlikely(!stream->initialized)) {
		ret = EINVAL;
		goto leave;
	}

	if (unlikely((ret = alsa_hook_lock_write(alsa_hook, stream))))
		goto leave;

	if (unlikely(stream->flags & GLC_AUDIO_INTERLEAVED)) {
		if (!(stream->mode & SND_PCM_ASYNC))
			glc_log(alsa_hook->glc, GLC_ERROR, "alsa_hook",
				 "stream format (interleaved) incompatible with snd_pcm_writen()");
		ret = EINVAL;
		goto unlock;
	}

	if (unlikely((ret = alsa_hook_wait_for_thread(alsa_hook, stream))))
		goto unlock;

	if (unlikely((ret = alsa_hook_set_data_size(stream,
				snd_pcm_frames_to_bytes(pcm, size)))))
		goto unlock;

	stream->capture_time = glc_state_time(alsa_hook->glc);
	for (c = 0; c < stream->channels; c++)
		memcpy(&stream->capture_data[c * snd_pcm_samples_to_bytes(pcm, size)], bufs[c],
		       snd_pcm_samples_to_bytes(pcm, size));

	sem_post(&stream->capture_full);

unlock:
	alsa_hook_unlock_write(alsa_hook, stream);
leave:
	errno = savedErrno;
	return ret;
}
Exemplo n.º 2
0
static int
write_device(AudioDevice *ad, unsigned char *data, int size)
{
  ALSA_data *alsa = (ALSA_data *)ad->private_data;
  snd_pcm_sframes_t r;
  ssize_t unit = snd_pcm_samples_to_bytes(alsa->fd, 1) * ad->channels;
  snd_pcm_uframes_t count = size / unit;

  while (count > 0) {
    if ((r = snd_pcm_writei(alsa->fd, data, count)) == -EAGAIN) {
      //debug_message_fnc(" EAGAIN\n");
      snd_pcm_wait(alsa->fd, 1000);
    } else if (r > 0) {
      //debug_message_fnc(" wrote %d bytes\n", (int)(r * unit));
      ad->bytes_written += r * unit;
      count -= r;
      data += r * unit;
    } else if (r == -EPIPE) {
      debug_message_fnc("EPIPE: ");
      if (snd_pcm_state(alsa->fd) == SND_PCM_STATE_XRUN) {
	if ((r = snd_pcm_prepare(alsa->fd)) < 0) {
	  debug_message("failed\n");
	  warning_fnc("snd_pcm_prepare() failed.");
	} else {
	  debug_message("OK\n");
	}
      }
    } else {
      warning_fnc(" r = %d < 0...\n", (int)r);
    }
  }

  return 1;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
0
int alsa_hook_complex_to_interleaved(struct alsa_hook_stream_s *stream, const snd_pcm_channel_area_t *areas,
				snd_pcm_uframes_t offset, snd_pcm_uframes_t frames, char *to)
{
	/** \todo test this... :D */
	/** \note this is quite expensive operation */
	unsigned int c;
	size_t s, off, add, ssize;

	add = snd_pcm_frames_to_bytes(stream->pcm, 1);
	ssize = snd_pcm_samples_to_bytes(stream->pcm, 1);

	for (c = 0; c < stream->channels; c++) {
		off = add * c;
		for (s = 0; s < frames; s++) {
			memcpy(&to[off], alsa_hook_mmap_pos(&areas[c], offset + s), ssize);
			off += add;
		}
	}

	return 0;
}
Exemplo n.º 5
0
int alsa_play_play(alsa_play_t alsa_play, glc_audio_data_header_t *audio_hdr, char *data)
{
	snd_pcm_uframes_t frames, rem;
	snd_pcm_sframes_t ret = 0;
	unsigned int c;

	if (audio_hdr->id != alsa_play->id)
		return 0;

	if (!alsa_play->pcm) {
		glc_log(alsa_play->glc, GLC_ERROR, "alsa_play", "broken stream %d",
			 alsa_play->id);
		return EINVAL;
	}

	frames = snd_pcm_bytes_to_frames(alsa_play->pcm, audio_hdr->size);
	glc_utime_t time = glc_state_time(alsa_play->glc);
	glc_utime_t duration = ((glc_utime_t) 1000000000 * (glc_utime_t) frames) /
			       (glc_utime_t) alsa_play->rate;

	if (time + alsa_play->silence_threshold + duration < audio_hdr->time) {
		struct timespec ts = {
		.tv_sec = (audio_hdr->time - time - duration - alsa_play->silence_threshold)/1000000000,
		.tv_nsec = (audio_hdr->time - time - duration - alsa_play->silence_threshold)%1000000000 };
		nanosleep(&ts,NULL);
	}
	/*
	 * This condition determine what will be the initial audio packet.
	 * it is preferable to be ahead by < duration/2 than behind
	 * the video by > duration/2
	 */
	else if (time > audio_hdr->time + duration/2) {
		glc_log(alsa_play->glc, GLC_DEBUG, "alsa_play",
			"dropped packet. now %" PRId64 " ts %" PRId64,
			time, audio_hdr->time);
		return 0;
	}

	rem = frames;

	while (rem > 0) {
		/* alsa is horrible... */
		/*snd_pcm_wait(alsa_play->pcm, duration);*/

		if (alsa_play->flags & GLC_AUDIO_INTERLEAVED)
			ret = snd_pcm_writei(alsa_play->pcm,
					    &data[snd_pcm_frames_to_bytes(alsa_play->pcm, frames - rem)],
					    rem);
		else {
			for (c = 0; c < alsa_play->channels; c++)
				alsa_play->bufs[c] =
					&data[snd_pcm_samples_to_bytes(alsa_play->pcm, frames)
					      * c + snd_pcm_samples_to_bytes(alsa_play->pcm, frames - rem)];
			ret = snd_pcm_writen(alsa_play->pcm, alsa_play->bufs, rem);
		}

		if (ret == 0)
			break;

		if ((ret == -EBUSY) || (ret == -EAGAIN))
			break;
		else if (ret < 0) {
			if ((ret = alsa_play_xrun(alsa_play, ret))) {
				glc_log(alsa_play->glc, GLC_ERROR, "alsa_play",
					 "xrun recovery failed: %s", snd_strerror(-ret));
				return ret;
			}
		} else
			rem -= ret;
	}

	return 0;
}
Exemplo n.º 6
0
/*
 * Might be called from signal handlers.
 */
int alsa_hook_mmap_commit(alsa_hook_t alsa_hook, snd_pcm_t *pcm,
				snd_pcm_uframes_t offset, snd_pcm_uframes_t frames)
{
	struct alsa_hook_stream_s *stream;
	unsigned int c;
	int ret = 0;
	int savedErrno = errno;

	if (!(alsa_hook->flags & ALSA_HOOK_CAPTURING))
		goto leave;

	alsa_hook_get_stream(alsa_hook, pcm, &stream);

	if (unlikely((ret = alsa_hook_lock_write(alsa_hook, stream))))
		goto leave;

	if (unlikely(stream->channels == 0))
		goto unlock; /* 0 channels :P */

	if (unlikely(!stream->mmap_areas)) {
		/* this might actually happen */
		if (!(stream->mode & SND_PCM_ASYNC))
			glc_log(alsa_hook->glc, GLC_WARN, "alsa_hook",
				 "snd_pcm_mmap_commit() before snd_pcm_mmap_begin()");
		goto unlock;
	}

	if (unlikely(offset != stream->offset))
		if (!(stream->mode & SND_PCM_ASYNC))
			glc_log(alsa_hook->glc, GLC_WARN, "alsa_hook",
				 "offset=%lu != stream->offset=%lu", offset, stream->offset);

	if (unlikely((ret = alsa_hook_wait_for_thread(alsa_hook, stream))))
		goto unlock;

	if (unlikely((ret = alsa_hook_set_data_size(stream,
			snd_pcm_frames_to_bytes(pcm, frames)))))
		goto unlock;

	stream->capture_time = glc_state_time(alsa_hook->glc);

	if (stream->flags & GLC_AUDIO_INTERLEAVED) {
		memcpy(stream->capture_data,
		       alsa_hook_mmap_pos(stream->mmap_areas, offset),
		       stream->capture_size);
	} else if (stream->complex) {
		alsa_hook_complex_to_interleaved(stream, stream->mmap_areas, offset,
		                                  frames, stream->capture_data);
	} else {
		for (c = 0; c < stream->channels; c++)
			memcpy(&stream->capture_data[c * snd_pcm_samples_to_bytes(stream->pcm, frames)],
			       alsa_hook_mmap_pos(&stream->mmap_areas[c], offset),
			       snd_pcm_samples_to_bytes(stream->pcm, frames));
	}

	sem_post(&stream->capture_full);

unlock:
	alsa_hook_unlock_write(alsa_hook, stream);
leave:
	errno = savedErrno;
	return ret;
}
Exemplo n.º 7
0
static int
set_params(AudioDevice *ad, AudioFormat *format_p, int *ch_p, unsigned int *rate_p)
{
  ALSA_data *alsa = (ALSA_data *)ad->private_data;
  int r, err;
  snd_pcm_format_t f;
  AudioFormat format = *format_p;
  snd_pcm_hw_params_t *hwparams;
  snd_pcm_sw_params_t *swparams;
  int ch = *ch_p;
  unsigned int rate = *rate_p;
  unsigned int buffer, period;

  snd_pcm_hw_params_alloca(&hwparams);
  snd_pcm_sw_params_alloca(&swparams);

  ad->format = _AUDIO_FORMAT_UNSET;
  *format_p = _AUDIO_FORMAT_UNSET;
  *ch_p = 0;
  *rate_p = 0;

  /* format part */
  switch (format) {
  case _AUDIO_FORMAT_MU_LAW:
    f = SND_PCM_FORMAT_MU_LAW;
    break;
  case _AUDIO_FORMAT_A_LAW:
    f = SND_PCM_FORMAT_A_LAW;
    break;
  case _AUDIO_FORMAT_ADPCM:
    f = SND_PCM_FORMAT_IMA_ADPCM;
    break;
  case _AUDIO_FORMAT_U8:
    f = SND_PCM_FORMAT_U8;
    break;
  case _AUDIO_FORMAT_S8:
    f = SND_PCM_FORMAT_S8;
    break;
  case _AUDIO_FORMAT_U16_LE:
    f = SND_PCM_FORMAT_U16_LE;
    break;
  case _AUDIO_FORMAT_U16_BE:
    f = SND_PCM_FORMAT_U16_BE;
    break;
  case _AUDIO_FORMAT_S16_LE:
    f = SND_PCM_FORMAT_S16_LE;
    break;
  case _AUDIO_FORMAT_S16_BE:
    f = SND_PCM_FORMAT_S16_BE;
    break;
#if 0
  case _AUDIO_FORMAT_S32_LE:
    f = SND_PCM_FORMAT_U32_LE;
    break;
  case _AUDIO_FORMAT_S32_BE:
    f = SND_PCM_FORMAT_S32_BE;
    break;
#endif
  default:
    show_message_fnc("format %d is invalid.\n", format);
    return 0;
  }

  if ((err = snd_pcm_hw_params_any(alsa->fd, hwparams)) < 0) {
    show_message_fnc("snd_pcm_hw_params_any() failed.\n");
    return 0;
  }

  if ((err = snd_pcm_hw_params_set_access(alsa->fd, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
    show_message_fnc("snd_pcm_hw_params_set_access() failed.\n");
    return 0;
  }

  if ((err = snd_pcm_hw_params_set_format(alsa->fd, hwparams, f)) < 0) {
    show_message_fnc("snd_pcm_hw_params_set_format() failed.\n");
    return 0;
  }
  ad->format = format;
  *format_p = format;

  /* channel part */
  if ((err = snd_pcm_hw_params_set_channels(alsa->fd, hwparams, ch)) < 0) {
    show_message_fnc("snd_pcm_hw_params_set_channels() failed.\n");
    return 0;
  }
  *ch_p = ch;

  /* rate part */
  if ((err = snd_pcm_hw_params_set_rate_near(alsa->fd, hwparams, &rate, 0)) < 0) {
    show_message_fnc("snd_pcm_hw_params_set_rate_near() failed.\n");
    return 0;
  }
  *rate_p = rate;

  /* buffer & period */
  buffer = 500000;
  period = 500000 / 4;
  if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa->fd, hwparams, &buffer, 0)) < 0) {
    show_message_fnc("snd_pcm_hw_params_set_buffer_near() failed.\n");
    return 0;
  }
  r = snd_pcm_hw_params_get_buffer_size(hwparams, &alsa->buffer_size);
  if ((err = snd_pcm_hw_params_set_period_time_near(alsa->fd, hwparams, &period, 0)) < 0) {
    show_message_fnc("snd_pcm_hw_params_set_period_near() failed.\n");
    return 0;
  }
  r = snd_pcm_hw_params_get_period_size(hwparams, &alsa->period_size, 0);

  if ((err = snd_pcm_hw_params(alsa->fd, hwparams)) < 0) {
    perror("snd_pcm_hw_params");
    err_message_fnc("snd_pcm_hw_params() failed.\n");
    snd_pcm_hw_params_dump(hwparams, alsa->log);
    return 0;
  }

  r = snd_pcm_hw_params_get_channels(hwparams, &ad->channels);
  r = snd_pcm_hw_params_get_rate(hwparams, &ad->speed, 0);
  r = r; // dummy

#ifdef DEBUG
  {
    snd_pcm_format_t form;

    debug_message_fnc("format ");
    r = snd_pcm_hw_params_get_format(hwparams, &form);
    switch (form) {
    case SND_PCM_FORMAT_MU_LAW:    debug_message("MU_LAW "); break;
    case SND_PCM_FORMAT_A_LAW:     debug_message("A_LAW "); break;
    case SND_PCM_FORMAT_IMA_ADPCM: debug_message("ADPCM "); break;
    case SND_PCM_FORMAT_U8:        debug_message("U8 "); break;
    case SND_PCM_FORMAT_S8:        debug_message("S8 "); break;
    case SND_PCM_FORMAT_U16_LE:    debug_message("U16LE "); break;
    case SND_PCM_FORMAT_U16_BE:    debug_message("U16BE "); break;
    case SND_PCM_FORMAT_S16_LE:    debug_message("S16LE "); break;
    case SND_PCM_FORMAT_S16_BE:    debug_message("S16BE "); break;
#if 0
    case SND_PCM_FORMAT_U32_LE:    debug_message("U32LE "); break;
    case SND_PCM_FORMAT_S32_BE:    debug_message("S32BE "); break;
#endif
    default:                       debug_message("UNKNOWN "); break;
    }

    debug_message("%d ch %d Hz buffer %ld period %ld OK\n", ad->channels, ad->speed, alsa->buffer_size, alsa->period_size);
  }
#endif

  /* sw_params */
  if ((err = snd_pcm_sw_params_current(alsa->fd, swparams)) < 0) {
    show_message_fnc("snd_pcm_sw_params_any() failed.\n");
    return 0;
  }
  if ((err = snd_pcm_sw_params(alsa->fd, swparams)) < 0) {
    show_message_fnc("snd_pcm_sw_params() failed.\n");
    return 0;
  }

  debug_message_fnc("1 sample -> %ld bytes\n", snd_pcm_samples_to_bytes(alsa->fd, 1));

  return 1;
}