C++程序  |  140行  |  3.54 KB

/* Copyright 2018 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include <syslog.h>

#include "buffer_share.h"
#include "cras_audio_area.h"
#include "cras_dsp_pipeline.h"
#include "cras_mix.h"
#include "cras_rstream.h"
#include "cras_system_state.h"
#include "dsp_util.h"
#include "input_data.h"
#include "utlist.h"

void input_data_run(struct ext_dsp_module *ext,
		    unsigned int nframes)
{
	struct input_data *data = (struct input_data *)ext;
	float *const *wp;
	int i;
	unsigned int writable;
	unsigned int offset = 0;

	while (nframes) {
		writable = float_buffer_writable(data->fbuffer);
		writable = MIN(nframes, writable);
		if (!writable) {
			syslog(LOG_ERR, "Not enough space to process input data");
			break;
		}
		wp = float_buffer_write_pointer(data->fbuffer);
		for (i = 0; i < data->fbuffer->num_channels; i++)
			memcpy(wp[i], ext->ports[i] + offset, writable * sizeof(float));

		float_buffer_written(data->fbuffer, writable);
		nframes -= writable;
		offset += writable;
	}
}

void input_data_configure(struct ext_dsp_module *ext, unsigned int buffer_size,
			  unsigned int num_channels, unsigned int rate)
{
	struct input_data *data = (struct input_data *)ext;

	if (data->fbuffer)
		float_buffer_destroy(&data->fbuffer);
	data->fbuffer = float_buffer_create(buffer_size, num_channels);
}

struct input_data *input_data_create(void *dev_ptr)
{
	struct input_data *data = (struct input_data *)calloc(1, sizeof(*data));

	data->dev_ptr = dev_ptr;

	data->ext.run = input_data_run;
	data->ext.configure = input_data_configure;

	return data;
}

void input_data_destroy(struct input_data **data)
{
	if ((*data)->fbuffer)
		float_buffer_destroy(&(*data)->fbuffer);
	free(*data);
	*data = NULL;
}

void input_data_set_all_streams_read(struct input_data *data,
				     unsigned int nframes)
{
	if (!data->fbuffer)
		return;

	if (float_buffer_level(data->fbuffer) < nframes) {
		syslog(LOG_ERR, "All streams read %u frames exceeds %u"
		       " in input_data's buffer",
		       nframes, float_buffer_level(data->fbuffer));
		float_buffer_reset(data->fbuffer);
		return;
	}
	float_buffer_read(data->fbuffer, nframes);
}

int input_data_get_for_stream(struct input_data *data,
			      struct cras_rstream *stream,
			      struct buffer_share *offsets,
			      struct cras_audio_area **area,
			      unsigned int *offset)
{
	unsigned int apm_processed;
	struct cras_apm *apm;

	/*
	 * It is possible that area buffer frames is smaller than the
	 * offset of stream. In this case, just reset the offset value
	 * to area->frames to prevent caller using these information get
	 * bad access to data.
	 */
	*area = data->area;
	*offset = MIN(buffer_share_id_offset(offsets, stream->stream_id),
		      data->area->frames);

	apm = cras_apm_list_get(stream->apm_list, data->dev_ptr);
	if (apm == NULL)
		return 0;

	apm_processed = cras_apm_list_process(apm, data->fbuffer, *offset);
	if (apm_processed < 0) {
		cras_apm_list_remove(stream->apm_list, apm);
		return 0;
	}
	buffer_share_offset_update(offsets, stream->stream_id, apm_processed);
	*area = cras_apm_list_get_processed(apm);
	*offset = 0;

	return 0;
}

int input_data_put_for_stream(struct input_data *data,
			      struct cras_rstream *stream,
			      struct buffer_share *offsets,
			      unsigned int frames)
{
	struct cras_apm *apm = cras_apm_list_get(
			stream->apm_list, data->dev_ptr);

	if (apm)
		cras_apm_list_put_processed(apm, frames);
	else
		buffer_share_offset_update(offsets, stream->stream_id, frames);

	return 0;
}