Skip to content

Commit

Permalink
ipc4: copier: Extend get_convertion_func() to support remapping
Browse files Browse the repository at this point in the history
Adds channel map parameter to get_convertion_func() to support remapping
conversion functions.

Signed-off-by: Serhiy Katsyuba <serhiy.katsyuba@intel.com>
  • Loading branch information
serhiy-katsyuba-intel authored and kv2019i committed Jul 17, 2024
1 parent eda6029 commit ffce2cb
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 38 deletions.
6 changes: 4 additions & 2 deletions src/audio/copier/copier.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ static int copier_init(struct processing_module *mod)

dev->direction_set = true;
} else {
cd->gtw_type = ipc4_gtw_none;

/* set max sink count for module copier */
mod->max_sinks = IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT;
}
Expand Down Expand Up @@ -244,7 +246,7 @@ static int copier_prepare(struct processing_module *mod,
*/
cd->converter[0] = get_converter_func(&cd->config.base.audio_fmt,
&cd->config.out_fmt, ipc4_gtw_none,
ipc4_bidirection);
ipc4_bidirection, DUMMY_CHMAP);
if (!cd->converter[0]) {
comp_err(dev, "can't support for in format %d, out format %d",
cd->config.base.audio_fmt.depth, cd->config.out_fmt.depth);
Expand Down Expand Up @@ -686,7 +688,7 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data,
cd->out_fmt[sink_fmt->sink_id] = sink_fmt->sink_fmt;
cd->converter[sink_fmt->sink_id] = get_converter_func(&sink_fmt->source_fmt,
&sink_fmt->sink_fmt, ipc4_gtw_none,
ipc4_bidirection);
ipc4_bidirection, DUMMY_CHMAP);

return 0;
}
Expand Down
4 changes: 3 additions & 1 deletion src/audio/copier/copier.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ struct copier_data {
*/
struct ipc4_copier_module_cfg config;
void *gtw_cfg;
enum ipc4_gateway_type gtw_type;
struct comp_dev *endpoint[IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT];
struct comp_buffer *endpoint_buffer[IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT];
uint32_t endpoint_num;
Expand Down Expand Up @@ -267,7 +268,8 @@ int apply_attenuation(struct comp_dev *dev, struct copier_data *cd,
pcm_converter_func get_converter_func(const struct ipc4_audio_format *in_fmt,
const struct ipc4_audio_format *out_fmt,
enum ipc4_gateway_type type,
enum ipc4_direction_type dir);
enum ipc4_direction_type dir,
uint32_t chmap);

struct comp_ipc_config;
int create_endpoint_buffer(struct comp_dev *dev,
Expand Down
104 changes: 72 additions & 32 deletions src/audio/copier/copier_dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,6 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd,
struct comp_ipc_config *config = &dev->ipc_config;
int dai_index[IPC4_ALH_MAX_NUMBER_OF_GTW];
union ipc4_connector_node_id node_id;
enum ipc4_gateway_type type;
struct ipc_config_dai dai;
int dai_count;
int i, ret;
Expand All @@ -255,13 +254,13 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd,
case ipc4_hda_link_input_class:
dai.type = SOF_DAI_INTEL_HDA;
dai.is_config_blob = true;
type = ipc4_gtw_link;
cd->gtw_type = ipc4_gtw_link;
break;
case ipc4_i2s_link_output_class:
case ipc4_i2s_link_input_class:
dai.type = SOF_DAI_INTEL_SSP;
dai.is_config_blob = true;
type = ipc4_gtw_ssp;
cd->gtw_type = ipc4_gtw_ssp;
ret = ipc4_find_dma_config(&dai, (uint8_t *)cd->gtw_cfg,
copier->gtw_cfg.config_length * 4);
if (ret != 0) {
Expand All @@ -275,11 +274,11 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd,
#if ACE_VERSION > ACE_VERSION_1_5
dai.type = SOF_DAI_INTEL_HDA;
dai.is_config_blob = true;
type = ipc4_gtw_link;
cd->gtw_type = ipc4_gtw_link;
#else
dai.type = SOF_DAI_INTEL_ALH;
dai.is_config_blob = true;
type = ipc4_gtw_alh;
cd->gtw_type = ipc4_gtw_alh;
#endif /* ACE_VERSION > ACE_VERSION_1_5 */
ret = copier_alh_assign_dai_index(dev, cd->gtw_cfg, node_id,
&dai, dai_index, &dai_count);
Expand All @@ -289,7 +288,7 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd,
case ipc4_dmic_link_input_class:
dai.type = SOF_DAI_INTEL_DMIC;
dai.is_config_blob = true;
type = ipc4_gtw_dmic;
cd->gtw_type = ipc4_gtw_dmic;
ret = ipc4_find_dma_config(&dai, (uint8_t *)cd->gtw_cfg,
copier->gtw_cfg.config_length * 4);
if (ret != 0) {
Expand All @@ -304,7 +303,7 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd,

for (i = 0; i < dai_count; i++) {
dai.dai_index = dai_index[i];
ret = copier_dai_init(dev, config, copier, pipeline, &dai, type, i,
ret = copier_dai_init(dev, config, copier, pipeline, &dai, cd->gtw_type, i,
dai_count);
if (ret) {
comp_err(dev, "failed to create dai");
Expand All @@ -313,11 +312,11 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd,
}

cd->converter[IPC4_COPIER_GATEWAY_PIN] =
get_converter_func(&copier->base.audio_fmt, &copier->out_fmt, type,
IPC4_DIRECTION(dai.direction));
get_converter_func(&copier->base.audio_fmt, &copier->out_fmt, cd->gtw_type,
IPC4_DIRECTION(dai.direction), DUMMY_CHMAP);
if (!cd->converter[IPC4_COPIER_GATEWAY_PIN]) {
comp_err(dev, "failed to get converter type %d, dir %d",
type, dai.direction);
cd->gtw_type, dai.direction);
return -EINVAL;
}

Expand Down Expand Up @@ -450,40 +449,81 @@ static int copy_single_channel_c32(const struct audio_stream *src,
return 0;
}

static void copier_dai_adjust_params(const struct copier_data *cd,
struct ipc4_audio_format *in_fmt,
struct ipc4_audio_format *out_fmt)
{
struct comp_buffer *dma_buf;
int dma_buf_channels;
int dma_buf_container_bits, dma_buf_valid_bits;

/* Call this func only for DAI gateway with already setup DMA buffer */
assert(cd->dd[0] && cd->dd[0]->dma_buffer);
dma_buf = cd->dd[0]->dma_buffer;

/* Unfortunately, configuring the gateway DMA buffer format is somewhat confusing.
* The number of channels can come from hardware parameters (extracted from a blob?)
* and also appears in the copier's input/output format. In case the value returned
* by the hardware looks valid, it should take precedence over the value from the
* copier's input/output format.
*
* The frame format comes from the topology as dev->ipc_config.frame_fmt and also
* comes as the copier's input/output format. The logic is confusing: the format
* from the topology takes priority, except when the copier's format container and
* valid sample size are different. Perhaps this is to support the 16-bit valid
* in the 32-bit container format used by SSP, as such a format cannot be specified
* in the topology?
*/
dma_buf_channels = audio_stream_get_channels(&dma_buf->stream);
dma_buf_container_bits = audio_stream_sample_bytes(&dma_buf->stream) * 8;
dma_buf_valid_bits = get_sample_bitdepth(audio_stream_get_frm_fmt(&dma_buf->stream));

if (cd->direction == SOF_IPC_STREAM_PLAYBACK) {
out_fmt->channels_count = dma_buf_channels;

if (!(dma_buf_container_bits == out_fmt->depth &&
out_fmt->depth != out_fmt->valid_bit_depth)) {
out_fmt->depth = dma_buf_container_bits;
out_fmt->valid_bit_depth = dma_buf_valid_bits;
}
} else {
in_fmt->channels_count = dma_buf_channels;

if (!(dma_buf_container_bits == in_fmt->depth &&
in_fmt->depth != in_fmt->valid_bit_depth)) {
in_fmt->depth = dma_buf_container_bits;
in_fmt->valid_bit_depth = dma_buf_valid_bits;
}
}
}

int copier_dai_params(struct copier_data *cd, struct comp_dev *dev,
struct sof_ipc_stream_params *params, int dai_index)
{
struct sof_ipc_stream_params demuxed_params = *params;
const struct ipc4_audio_format *in_fmt = &cd->config.base.audio_fmt;
const struct ipc4_audio_format *out_fmt = &cd->config.out_fmt;
enum sof_ipc_frame in_bits, in_valid_bits, out_bits, out_valid_bits;
int container_size;
int j, ret;

if (cd->endpoint_num == 1) {
struct ipc4_audio_format in_fmt = cd->config.base.audio_fmt;
struct ipc4_audio_format out_fmt = cd->config.out_fmt;
enum ipc4_direction_type dir;

ret = dai_common_params(cd->dd[0], dev, params);
if (ret < 0)
return ret;

copier_dai_adjust_params(cd, &in_fmt, &out_fmt);

dir = (cd->direction == SOF_IPC_STREAM_PLAYBACK) ?
ipc4_playback : ipc4_capture;

cd->dd[0]->process =
get_converter_func(&in_fmt, &out_fmt, cd->gtw_type, dir, DUMMY_CHMAP);

/*
* dai_zephyr_params assigns the conversion function
* based on the input/output formats but does not take
* the valid bits into account. So change the conversion
* function if the valid bits are different from the
* container size.
*/
audio_stream_fmt_conversion(in_fmt->depth,
in_fmt->valid_bit_depth,
&in_bits, &in_valid_bits,
in_fmt->s_type);
audio_stream_fmt_conversion(out_fmt->depth,
out_fmt->valid_bit_depth,
&out_bits, &out_valid_bits,
out_fmt->s_type);

if (in_bits != in_valid_bits || out_bits != out_valid_bits)
cd->dd[0]->process =
cd->converter[IPC4_COPIER_GATEWAY_PIN];
return ret;
}

/* For ALH multi-gateway case, params->channels is a total multiplexed
* number of channels. Demultiplexed number of channels for each individual
* gateway comes in blob's struct ipc4_alh_multi_gtw_cfg.
Expand Down
28 changes: 27 additions & 1 deletion src/audio/copier/copier_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,26 @@ static bool use_no_container_convert_function(enum sof_ipc_frame in,
return false;
}

static bool is_remapping_chmap(uint32_t chmap, size_t out_channel_count)
{
size_t i;

assert(out_channel_count <= 8);

for (i = 0; i < out_channel_count; i++) {
if ((chmap & 0xf) != i)
return true;
chmap >>= 4;
}

return false;
}

pcm_converter_func get_converter_func(const struct ipc4_audio_format *in_fmt,
const struct ipc4_audio_format *out_fmt,
enum ipc4_gateway_type type,
enum ipc4_direction_type dir)
enum ipc4_direction_type dir,
uint32_t chmap)
{
enum sof_ipc_frame in, in_valid, out, out_valid;

Expand Down Expand Up @@ -301,6 +317,16 @@ pcm_converter_func get_converter_func(const struct ipc4_audio_format *in_fmt,
}
}

if (in_fmt->channels_count != out_fmt->channels_count ||
is_remapping_chmap(chmap, out_fmt->channels_count)) {
if (in_valid == SOF_IPC_FRAME_S16_LE && in == SOF_IPC_FRAME_S32_LE)
in = SOF_IPC_FRAME_S16_4LE;
if (out_valid == SOF_IPC_FRAME_S16_LE && out == SOF_IPC_FRAME_S32_LE)
out = SOF_IPC_FRAME_S16_4LE;

return pcm_get_remap_function(in, out);
}

/* check container & sample size */
if (use_no_container_convert_function(in, in_valid, out, out_valid))
return pcm_get_conversion_function(in, out);
Expand Down
3 changes: 2 additions & 1 deletion src/audio/copier/copier_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ int copier_host_create(struct comp_dev *dev, struct copier_data *cd,
enum sof_ipc_frame in_valid_fmt, out_valid_fmt;

config->type = SOF_COMP_HOST;
cd->gtw_type = ipc4_gtw_host;

audio_stream_fmt_conversion(copier_cfg->base.audio_fmt.depth,
copier_cfg->base.audio_fmt.valid_bit_depth,
Expand Down Expand Up @@ -195,7 +196,7 @@ int copier_host_create(struct comp_dev *dev, struct copier_data *cd,
cd->converter[IPC4_COPIER_GATEWAY_PIN] =
get_converter_func(&copier_cfg->base.audio_fmt,
&copier_cfg->out_fmt,
ipc4_gtw_host, IPC4_DIRECTION(dir));
ipc4_gtw_host, IPC4_DIRECTION(dir), DUMMY_CHMAP);
if (!cd->converter[IPC4_COPIER_GATEWAY_PIN]) {
comp_err(dev, "failed to get converter for host, dir %d", dir);
ret = -EINVAL;
Expand Down
3 changes: 2 additions & 1 deletion src/audio/copier/copier_ipcgtw.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd,
* IPC gateway should be handled similarly as host gateway.
*/
config->type = SOF_COMP_HOST;
cd->gtw_type = ipc4_gtw_host;

ret = create_endpoint_buffer(dev, cd, copier, false);
if (ret < 0)
Expand All @@ -255,7 +256,7 @@ int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd,
cd->converter[IPC4_COPIER_GATEWAY_PIN] =
get_converter_func(&copier->base.audio_fmt,
&copier->out_fmt,
ipc4_gtw_host, IPC4_DIRECTION(cd->direction));
ipc4_gtw_host, IPC4_DIRECTION(cd->direction), DUMMY_CHMAP);
if (!cd->converter[IPC4_COPIER_GATEWAY_PIN]) {
comp_err(dev, "failed to get converter for IPC gateway, dir %d",
cd->direction);
Expand Down

0 comments on commit ffce2cb

Please sign in to comment.