Beispiel #1
0
static void share_areas(snd_pcm_direct_t *dshare,
		      const snd_pcm_channel_area_t *src_areas,
		      const snd_pcm_channel_area_t *dst_areas,
		      snd_pcm_uframes_t src_ofs,
		      snd_pcm_uframes_t dst_ofs,
		      snd_pcm_uframes_t size)
{
	unsigned int chn, dchn, channels;
	snd_pcm_format_t format;

	channels = dshare->channels;
	format = dshare->shmptr->s.format;
	if (dshare->interleaved) {
		unsigned int fbytes = snd_pcm_format_physical_width(format) / 8;
		memcpy(((char *)dst_areas[0].addr) + (dst_ofs * channels * fbytes),
		       ((char *)src_areas[0].addr) + (src_ofs * channels * fbytes),
		       size * channels * fbytes);
	} else {
		for (chn = 0; chn < channels; chn++) {
			dchn = dshare->bindings ? dshare->bindings[chn] : chn;
			snd_pcm_area_copy(&dst_areas[dchn], dst_ofs, &src_areas[chn], src_ofs, size, format);

		}
	}
}
Beispiel #2
0
static snd_pcm_sframes_t copy_transfer(struct snd_pcm_plugin *plugin,
			     const struct snd_pcm_plugin_channel *src_channels,
			     struct snd_pcm_plugin_channel *dst_channels,
			     snd_pcm_uframes_t frames)
{
	unsigned int channel;
	unsigned int nchannels;

	snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
	if (frames == 0)
		return 0;
	nchannels = plugin->src_format.channels;
	for (channel = 0; channel < nchannels; channel++) {
		snd_assert(src_channels->area.first % 8 == 0 &&
			   src_channels->area.step % 8 == 0,
			   return -ENXIO);
		snd_assert(dst_channels->area.first % 8 == 0 &&
			   dst_channels->area.step % 8 == 0,
			   return -ENXIO);
		if (!src_channels->enabled) {
			if (dst_channels->wanted)
				snd_pcm_area_silence(&dst_channels->area, 0, frames, plugin->dst_format.format);
			dst_channels->enabled = 0;
			continue;
		}
		dst_channels->enabled = 1;
		snd_pcm_area_copy(&src_channels->area, 0, &dst_channels->area, 0, frames, plugin->src_format.format);
		src_channels++;
		dst_channels++;
	}
	return frames;
}
Beispiel #3
0
static inline void copy_area(const struct snd_pcm_plugin_channel *src_channel,
			     struct snd_pcm_plugin_channel *dst_channel,
			     snd_pcm_uframes_t frames, int format)
{
	dst_channel->enabled = 1;
	snd_pcm_area_copy(&src_channel->area, 0, &dst_channel->area, 0, frames, format);
}
Beispiel #4
0
static snd_pcm_sframes_t copy_transfer(struct snd_pcm_plugin *plugin,
			     const struct snd_pcm_plugin_channel *src_channels,
			     struct snd_pcm_plugin_channel *dst_channels,
			     snd_pcm_uframes_t frames)
{
	unsigned int channel;
	unsigned int nchannels;

	if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
		return -ENXIO;
	if (frames == 0)
		return 0;
	nchannels = plugin->src_format.channels;
	for (channel = 0; channel < nchannels; channel++) {
		if (snd_BUG_ON(src_channels->area.first % 8 ||
			       src_channels->area.step % 8))
			return -ENXIO;
		if (snd_BUG_ON(dst_channels->area.first % 8 ||
			       dst_channels->area.step % 8))
			return -ENXIO;
		if (!src_channels->enabled) {
			if (dst_channels->wanted)
				snd_pcm_area_silence(&dst_channels->area, 0, frames, plugin->dst_format.format);
			dst_channels->enabled = 0;
			continue;
		}
		dst_channels->enabled = 1;
		snd_pcm_area_copy(&src_channels->area, 0, &dst_channels->area, 0, frames, plugin->src_format.format);
		src_channels++;
		dst_channels++;
	}
	return frames;
}
Beispiel #5
0
int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_areas,
		       snd_pcm_uframes_t dst_offset,
		       const snd_pcm_channel_area_t *src_areas,
		       snd_pcm_uframes_t src_offset,
		       unsigned int channels, snd_pcm_uframes_t frames,
		       snd_pcm_format_t format)
{
	int width;
	if (!channels)
		return -EINVAL;
	if (!frames)
		return -EINVAL;
	width = snd_pcm_format_physical_width(format);
	while (channels > 0) {
		snd_pcm_area_copy(dst_areas, dst_offset,
				  src_areas, src_offset,
				  frames, format);
		src_areas++;
		dst_areas++;
		channels--;
	}
	return 0;
}
Beispiel #6
0
/* Main callback for processing audio.  This is called by CRAS when more samples
 * are needed (playback) or ready (capture).  Copies bytes between ALSA and CRAS
 * buffers. */
static int pcm_cras_process_cb(struct cras_client *client,
			       cras_stream_id_t stream_id,
			       uint8_t *capture_samples,
			       uint8_t *playback_samples,
			       unsigned int nframes,
			       const struct timespec *capture_ts,
			       const struct timespec *playback_ts,
			       void *arg)
{
	snd_pcm_ioplug_t *io;
	struct snd_pcm_cras *pcm_cras;
	const snd_pcm_channel_area_t *areas;
	snd_pcm_uframes_t copied_frames;
	char dummy_byte;
	size_t chan, frame_bytes, sample_bytes;
	int rc;
	uint8_t *samples;
	const struct timespec *sample_time;

	samples = capture_samples ? : playback_samples;
	sample_time = capture_ts ? : playback_ts;

	io = (snd_pcm_ioplug_t *)arg;
	pcm_cras = (struct snd_pcm_cras *)io->private_data;
	frame_bytes = pcm_cras->bytes_per_frame;
	sample_bytes = snd_pcm_format_physical_width(io->format) / 8;

	if (io->stream == SND_PCM_STREAM_PLAYBACK) {
		if (io->state != SND_PCM_STATE_RUNNING) {
			memset(samples, 0, nframes * frame_bytes);
			return nframes;
		}
		/* Only take one period of data at a time. */
		if (nframes > io->period_size)
			nframes = io->period_size;

		/* Keep track of the first transmitted sample index and the time
		 * it will be played. */
		pcm_cras->playback_sample_index = io->hw_ptr;
		pcm_cras->playback_sample_time = *sample_time;
	} else {
		/* Keep track of the first read sample index and the time it
		 * was captured. */
		pcm_cras->capture_sample_index = io->hw_ptr;
		pcm_cras->capture_sample_time = *sample_time;
	}

	/* CRAS always takes interleaved samples. */
	for (chan = 0; chan < io->channels; chan++) {
		pcm_cras->areas[chan].addr = samples + chan * sample_bytes;
		pcm_cras->areas[chan].first = 0;
		pcm_cras->areas[chan].step =
			snd_pcm_format_physical_width(io->format) *
			io->channels;
	}

	areas = snd_pcm_ioplug_mmap_areas(io);

	copied_frames = 0;
	while (copied_frames < nframes) {
		snd_pcm_uframes_t frames = nframes - copied_frames;
		snd_pcm_uframes_t remain = io->buffer_size - pcm_cras->hw_ptr;

		if (frames > remain)
			frames = remain;

		for (chan = 0; chan < io->channels; chan++)
			if (io->stream == SND_PCM_STREAM_PLAYBACK)
				snd_pcm_area_copy(&pcm_cras->areas[chan],
						  copied_frames,
						  &areas[chan],
						  pcm_cras->hw_ptr,
						  frames,
						  io->format);
			else
				snd_pcm_area_copy(&areas[chan],
						  pcm_cras->hw_ptr,
						  &pcm_cras->areas[chan],
						  copied_frames,
						  frames,
						  io->format);

		pcm_cras->hw_ptr += frames;
		pcm_cras->hw_ptr %= io->buffer_size;
		copied_frames += frames;
	}

	rc = write(pcm_cras->fd, &dummy_byte, 1); /* Wake up polling clients. */
	if (rc < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
		fprintf(stderr, "%s write failed %d\n", __func__, errno);

	return nframes;
}