diff --git a/posix/include/sof/lib/dma.h b/posix/include/sof/lib/dma.h index af9e4191cbbb..4b6b2ae66e01 100644 --- a/posix/include/sof/lib/dma.h +++ b/posix/include/sof/lib/dma.h @@ -254,7 +254,7 @@ struct dma_info { struct audio_stream; typedef int (*dma_process_func)(const struct audio_stream __sparse_cache *source, uint32_t ioffset, struct audio_stream __sparse_cache *sink, - uint32_t ooffset, uint32_t frames); + uint32_t ooffset, uint32_t source_samples, uint32_t chmap); /** * \brief API to initialize a platform DMA controllers. @@ -523,19 +523,15 @@ static inline uint32_t dma_sg_get_size(struct dma_sg_elem_array *ea) return size; } -struct audio_stream; -typedef void (*dma_process)(const struct audio_stream *, - struct audio_stream *, uint32_t); - /* copies data from DMA buffer using provided processing function */ int dma_buffer_copy_from(struct comp_buffer __sparse_cache *source, struct comp_buffer __sparse_cache *sink, - dma_process_func process, uint32_t source_bytes); + dma_process_func process, uint32_t source_bytes, uint32_t chmap); /* copies data to DMA buffer using provided processing function */ int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source, struct comp_buffer __sparse_cache *sink, - dma_process_func process, uint32_t sink_bytes); + dma_process_func process, uint32_t sink_bytes, uint32_t chmap); /* * Used when copying DMA buffer bytes into multiple sink buffers, one at a time using the provided @@ -544,7 +540,8 @@ int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source, */ int dma_buffer_copy_from_no_consume(struct comp_buffer __sparse_cache *source, struct comp_buffer __sparse_cache *sink, - dma_process_func process, uint32_t source_bytes); + dma_process_func process, + uint32_t source_bytes, uint32_t chmap); /* generic DMA DSP <-> Host copier */ diff --git a/src/audio/Kconfig b/src/audio/Kconfig index 9b35b0c92af8..42ca5e51f9c0 100644 --- a/src/audio/Kconfig +++ b/src/audio/Kconfig @@ -251,6 +251,13 @@ config PCM_CONVERTER_FORMAT_S32LE help Support 32 bit processing data format with sign and in little endian format +config PCM_CONVERTER_FORMAT_S16_4LE + bool "Support S16_4LE" + default y + help + Support the format of signed 16-bit little-endian in the 2 lower bytes + of a 32-bit container. This format is used, for example, by the SSP gateway. + config PCM_CONVERTER_FORMAT_FLOAT bool "Support float" default y @@ -305,6 +312,14 @@ config PCM_CONVERTER_FORMAT_CONVERT_HIFI3 help Use HIFI3 extensions for optimized format conversion (experimental). +config PCM_REMAPPING_CONVERTERS + bool "Channel remapping conversions" + default y + depends on IPC_MAJOR_4 + help + Enable conversion functions that perform both format conversion + and channel remapping simultaneously. + config TRACE_CHANNEL int "TRACE DMA Channel configuration" default 0 diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 178f7cb25846..7c8d53726d20 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -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; } @@ -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); @@ -440,7 +442,8 @@ static int do_conversion_copy(struct comp_dev *dev, buffer_stream_invalidate(src, processed_data->source_bytes); cd->converter[i](&src->stream, 0, &sink->stream, 0, - processed_data->frames * audio_stream_get_channels(&sink->stream)); + processed_data->frames * audio_stream_get_channels(&src->stream), + DUMMY_CHMAP); buffer_stream_writeback(sink, processed_data->sink_bytes); comp_update_buffer_produce(sink, processed_data->sink_bytes); @@ -509,7 +512,7 @@ static int copier_module_copy(struct processing_module *mod, sink_dev = sink_c->sink; processed_data.sink_bytes = 0; if (sink_dev->state == COMP_STATE_ACTIVE) { - uint32_t samples; + uint32_t source_samples; int sink_queue_id; sink_queue_id = IPC4_SINK_QUEUE_ID(buf_get_id(sink_c)); @@ -518,10 +521,11 @@ static int copier_module_copy(struct processing_module *mod, comp_get_copy_limits(src_c, sink_c, &processed_data); - samples = processed_data.frames * - audio_stream_get_channels(output_buffers[i].data); + source_samples = processed_data.frames * + audio_stream_get_channels(input_buffers[0].data); cd->converter[sink_queue_id](input_buffers[0].data, 0, - output_buffers[i].data, 0, samples); + output_buffers[i].data, 0, + source_samples, DUMMY_CHMAP); output_buffers[i].size = processed_data.sink_bytes; cd->output_total_data_processed += processed_data.sink_bytes; @@ -657,6 +661,7 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data, const struct ipc4_copier_config_set_sink_format *sink_fmt = data; struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); + uint32_t chmap; if (max_data_size < sizeof(*sink_fmt)) { comp_err(dev, "error: max_data_size %d should be bigger than %d", max_data_size, @@ -682,9 +687,15 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data, } cd->out_fmt[sink_fmt->sink_id] = sink_fmt->sink_fmt; + + if (cd->endpoint_num > 0 && dev->ipc_config.type == SOF_COMP_DAI) + chmap = cd->dd[0]->chmap; + else + chmap = DUMMY_CHMAP; + cd->converter[sink_fmt->sink_id] = get_converter_func(&sink_fmt->source_fmt, &sink_fmt->sink_fmt, ipc4_gtw_none, - ipc4_bidirection); + ipc4_bidirection, chmap); return 0; } @@ -724,6 +735,82 @@ static int set_attenuation(struct comp_dev *dev, uint32_t data_offset, const cha return 0; } +static int set_chmap(struct comp_dev *dev, const void *data, size_t data_size) +{ + const struct ipc4_copier_config_channel_map *chmap_cfg = data; + struct processing_module *mod = comp_mod(dev); + struct copier_data *cd = module_get_private_data(mod); + enum ipc4_direction_type dir; + struct ipc4_audio_format in_fmt = cd->config.base.audio_fmt; + struct ipc4_audio_format out_fmt = cd->config.out_fmt; + pcm_converter_func process; + pcm_converter_func converters[IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT]; + int i; + uint32_t irq_flags; + + if (data_size < sizeof(*chmap_cfg)) { + comp_err(dev, "Wrong payload size: %d", data_size); + return -EINVAL; + } + + if (cd->endpoint_num == 0 || dev->ipc_config.type != SOF_COMP_DAI) { + comp_err(dev, "Only DAI gateway supports changing chmap"); + return -EINVAL; + } + + comp_info(dev, "New chmap requested: %x", chmap_cfg->channel_map); + + if (!cd->dd[0]->dma_buffer) { + /* DMA buffer not yet created. Remember the chmap, it will be used + * later in .params() handler. + * + * The assignment should be atomic as LL thread can preempt this IPC thread. + */ + cd->dd[0]->chmap = chmap_cfg->channel_map; + return 0; + } + + copier_dai_adjust_params(cd, &in_fmt, &out_fmt); + + dir = (cd->direction == SOF_IPC_STREAM_PLAYBACK) ? + ipc4_playback : ipc4_capture; + + process = get_converter_func(&in_fmt, &out_fmt, cd->gtw_type, dir, chmap_cfg->channel_map); + + if (!process) { + comp_err(dev, "No gtw converter func found!"); + return -EINVAL; + } + + /* Channel map is same for all sinks. However, as sinks allowed to have different + * sample formats, get new convert/remap function for each sink. + */ + for (i = 0; i < IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT; i++) { + if (cd->converter[i]) { + converters[i] = get_converter_func(&in_fmt, &cd->out_fmt[i], + ipc4_gtw_none, ipc4_bidirection, + chmap_cfg->channel_map); + /* Do not report an error if converter not found as sinks could be + * bound/unbound on a fly and out_fmt[i] may contain obsolete data. + */ + } else { + converters[i] = NULL; + } + } + + /* Atomically update chmap, process and converters */ + irq_local_disable(irq_flags); + + cd->dd[0]->chmap = chmap_cfg->channel_map; + cd->dd[0]->process = process; + for (i = 0; i < IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT; i++) + cd->converter[i] = converters[i]; + + irq_local_enable(irq_flags); + + return 0; +} + static int copier_set_configuration(struct processing_module *mod, uint32_t config_id, enum module_cfg_fragment_position pos, @@ -741,6 +828,8 @@ static int copier_set_configuration(struct processing_module *mod, return copier_set_sink_fmt(dev, fragment, fragment_size); case IPC4_COPIER_MODULE_CFG_ATTENUATION: return set_attenuation(dev, fragment_size, (const char *)fragment); + case IPC4_COPIER_MODULE_CFG_PARAM_CHANNEL_MAP: + return set_chmap(dev, fragment, fragment_size); default: return -EINVAL; } diff --git a/src/audio/copier/copier.h b/src/audio/copier/copier.h index 550219a2aa83..41bca7afc287 100644 --- a/src/audio/copier/copier.h +++ b/src/audio/copier/copier.h @@ -180,7 +180,12 @@ enum ipc4_copier_module_config_params { * uint32_t. Config is only allowed when output pin is set up for 32bit and * source is connected to Gateway */ - IPC4_COPIER_MODULE_CFG_ATTENUATION = 6 + IPC4_COPIER_MODULE_CFG_ATTENUATION = 6, + /* Use LARGE_CONFIG_SET to setup new channel map, which allows to map channels + * from gateway buffer to copier with any order. + * Same mapping will be applied for all copier sinks. + */ + IPC4_COPIER_MODULE_CFG_PARAM_CHANNEL_MAP = 7 }; struct ipc4_copier_config_timestamp_init_data { @@ -201,6 +206,13 @@ struct ipc4_copier_config_set_sink_format { struct ipc4_audio_format sink_fmt; } __attribute__((packed, aligned(4))); +struct ipc4_copier_config_channel_map { + /* Each half-byte of the channel map is an index of the DMA stream channel that + * should be copied to the position determined by this half-byte index. + */ + uint32_t channel_map; +} __attribute__((packed, aligned(4))); + #define IPC4_COPIER_DATA_SEGMENT_DISABLE (0 << 0) #define IPC4_COPIER_DATA_SEGMENT_ENABLE (1 << 0) #define IPC4_COPIER_DATA_SEGMENT_RESTART (1 << 1) @@ -232,6 +244,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; @@ -267,7 +280,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, diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index e2c56b831b9c..80866f6933c1 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -164,6 +164,7 @@ static int copier_dai_init(struct comp_dev *dev, { struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); + uint32_t chmap; struct dai_data *dd; int ret; @@ -178,6 +179,7 @@ static int copier_dai_init(struct comp_dev *dev, config->frame_fmt = out_frame_fmt; pipeline->sink_comp = dev; cd->bsource_buffer = true; + chmap = copier->base.audio_fmt.ch_map; } else { enum sof_ipc_frame in_frame_fmt, in_valid_fmt; @@ -187,6 +189,7 @@ static int copier_dai_init(struct comp_dev *dev, copier->base.audio_fmt.s_type); config->frame_fmt = in_frame_fmt; pipeline->source_comp = dev; + chmap = copier->out_fmt.ch_map; } /* save the channel map and count for ALH multi-gateway */ @@ -205,6 +208,8 @@ static int copier_dai_init(struct comp_dev *dev, if (ret < 0) goto free_dd; + dd->chmap = chmap; + pipeline->sched_id = config->id; cd->dd[index] = dd; @@ -234,7 +239,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; @@ -255,13 +259,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) { @@ -275,11 +279,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); @@ -289,7 +293,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) { @@ -304,7 +308,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"); @@ -313,11 +317,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; } @@ -450,40 +454,81 @@ static int copy_single_channel_c32(const struct audio_stream *src, return 0; } +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, cd->dd[0]->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. @@ -502,10 +547,10 @@ int copier_dai_params(struct copier_data *cd, struct comp_dev *dev, switch (container_size) { case 2: - cd->dd[dai_index]->process = copy_single_channel_c16; + cd->dd[dai_index]->channel_copy = copy_single_channel_c16; break; case 4: - cd->dd[dai_index]->process = copy_single_channel_c32; + cd->dd[dai_index]->channel_copy = copy_single_channel_c32; break; default: comp_err(dev, "Unexpected container size: %d", container_size); diff --git a/src/audio/copier/copier_generic.c b/src/audio/copier/copier_generic.c index ed31fb7414e7..4cb480ebe3f9 100644 --- a/src/audio/copier/copier_generic.c +++ b/src/audio/copier/copier_generic.c @@ -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; @@ -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); diff --git a/src/audio/copier/copier_host.c b/src/audio/copier/copier_host.c index a7eafac04eaa..b61af44bfe0e 100644 --- a/src/audio/copier/copier_host.c +++ b/src/audio/copier/copier_host.c @@ -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, @@ -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; diff --git a/src/audio/copier/copier_ipcgtw.c b/src/audio/copier/copier_ipcgtw.c index cdac60e98249..b5dccbd12986 100644 --- a/src/audio/copier/copier_ipcgtw.c +++ b/src/audio/copier/copier_ipcgtw.c @@ -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) @@ -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); diff --git a/src/audio/copier/dai_copier.h b/src/audio/copier/dai_copier.h index 4694b48ff1f2..a03970288b1b 100644 --- a/src/audio/copier/dai_copier.h +++ b/src/audio/copier/dai_copier.h @@ -83,6 +83,10 @@ void copier_dai_free(struct copier_data *cd); int copier_dai_prepare(struct comp_dev *dev, struct copier_data *cd); +void copier_dai_adjust_params(const struct copier_data *cd, + struct ipc4_audio_format *in_fmt, + struct ipc4_audio_format *out_fmt); + int copier_dai_params(struct copier_data *cd, struct comp_dev *dev, struct sof_ipc_stream_params *params, int dai_index); diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 273fa5eee9d5..af28b8616d9c 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -122,10 +122,10 @@ static void dai_dma_cb(void *arg, enum notify_id type, void *data) if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer, - dd->process, bytes); + dd->process, bytes, DUMMY_CHMAP); } else { ret = dma_buffer_copy_from(dd->dma_buffer, dd->local_buffer, - dd->process, bytes); + dd->process, bytes, DUMMY_CHMAP); } /* assert dma_buffer_copy succeed */ diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 2dee890d9653..c289b517e8d2 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -269,7 +269,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer, - dd->process, bytes); + dd->process, bytes, dd->chmap); } else { audio_stream_invalidate(&dd->dma_buffer->stream, bytes); /* @@ -277,7 +277,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, * so no need to check the return value of dma_buffer_copy_from_no_consume(). */ ret = dma_buffer_copy_from_no_consume(dd->dma_buffer, dd->local_buffer, - dd->process, bytes); + dd->process, bytes, dd->chmap); #if CONFIG_IPC_MAJOR_4 struct list_item *sink_list; /* Skip in case of endpoint DAI devices created by the copier */ @@ -314,10 +314,11 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, continue; } - if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE) + if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE && + sink->hw_params_configured) ret = dma_buffer_copy_from_no_consume(dd->dma_buffer, sink, converter[j], - bytes); + bytes, dd->chmap); } } #endif @@ -379,16 +380,19 @@ dai_dma_multi_endpoint_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t fr if (dev->direction == SOF_IPC_STREAM_CAPTURE) audio_stream_invalidate(&dd->dma_buffer->stream, bytes); + assert(dd->channel_copy); + /* copy all channels one by one */ for (i = 0; i < audio_stream_get_channels(&dd->dma_buffer->stream); i++) { uint32_t multi_buf_channel = dd->dma_buffer->chmap[i]; if (dev->direction == SOF_IPC_STREAM_PLAYBACK) - dd->process(&multi_endpoint_buffer->stream, multi_buf_channel, - &dd->dma_buffer->stream, i, frames); + dd->channel_copy(&multi_endpoint_buffer->stream, multi_buf_channel, + &dd->dma_buffer->stream, i, frames); else - dd->process(&dd->dma_buffer->stream, i, &multi_endpoint_buffer->stream, - multi_buf_channel, frames); + dd->channel_copy(&dd->dma_buffer->stream, i, + &multi_endpoint_buffer->stream, multi_buf_channel, + frames); } if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { @@ -464,6 +468,8 @@ static struct comp_dev *dai_new(const struct comp_driver *drv, if (ret < 0) goto error; + dd->chmap = DUMMY_CHMAP; + dev->state = COMP_STATE_READY; return dev; @@ -790,7 +796,8 @@ static int dai_set_dma_config(struct dai_data *dd, struct comp_dev *dev) } static int dai_set_dma_buffer(struct dai_data *dd, struct comp_dev *dev, - struct sof_ipc_stream_params *params, uint32_t *pb, uint32_t *pc) + const struct sof_ipc_stream_params *params, + uint32_t *pb, uint32_t *pc) { struct sof_ipc_stream_params hw_params = *params; uint32_t frame_size; @@ -904,7 +911,6 @@ static int dai_set_dma_buffer(struct dai_data *dd, struct comp_dev *dev, */ hw_params.frame_fmt = dev->ipc_config.frame_fmt; buffer_set_params(dd->dma_buffer, &hw_params, BUFFER_UPDATE_FORCE); - dd->sampling = get_sample_bytes(hw_params.frame_fmt); } *pc = audio_stream_get_size(&dd->dma_buffer->stream) / period_bytes; @@ -913,8 +919,10 @@ static int dai_set_dma_buffer(struct dai_data *dd, struct comp_dev *dev, } int dai_common_params(struct dai_data *dd, struct comp_dev *dev, - struct sof_ipc_stream_params *params) + struct sof_ipc_stream_params *base_cfg_params) { + struct sof_ipc_stream_params params = *base_cfg_params; + struct sof_ipc_stream_params hw_params; struct dma_sg_config *config = &dd->config; uint32_t period_bytes = 0; uint32_t period_count = 0; @@ -929,13 +937,30 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, return err; } - err = dai_verify_params(dd, dev, params); + /* When the hardware is able to return a valid number of DMA buffer audio channels + * (e.g., extracted from a blob), give the returned number of channels higher precedence + * over the number supplied via the base config params. + */ + memset(&hw_params, 0, sizeof(hw_params)); + err = dai_common_get_hw_params(dd, dev, &hw_params, params.direction); + if (err < 0) { + comp_err(dev, "dai_common_get_hw_params() failed: %d", err); + return err; + } + + if (hw_params.channels != 0 && hw_params.channels != params.channels) { + params.channels = hw_params.channels; + comp_info(dev, "Replacing %d base config channels with %d hw params channels.", + base_cfg_params->channels, params.channels); + } + + err = dai_verify_params(dd, dev, ¶ms); if (err < 0) { comp_err(dev, "dai_zephyr_params(): pcm params verification failed."); return -EINVAL; } - err = dai_set_dma_buffer(dd, dev, params, &period_bytes, &period_count); + err = dai_set_dma_buffer(dd, dev, ¶ms, &period_bytes, &period_count); if (err < 0) { comp_err(dev, "dai_zephyr_params(): alloc dma buffer failed."); goto out; @@ -1389,11 +1414,10 @@ int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, frames = MIN(src_frames, sink_frames); /* limit bytes per copy to one period for the whole pipeline in order to avoid high load - * spike if FAST_MODE is enabled, then one period limitation is omitted. All dd's have the - * same period_bytes, so use the period_bytes from dd[0] + * spike if FAST_MODE is enabled, then one period limitation is omitted. */ if (!(dd[0]->ipc_config.feature_mask & BIT(IPC4_COPIER_FAST_MODE))) - frames = MIN(frames, dd[0]->period_bytes / frame_bytes); + frames = MIN(frames, dev->frames); comp_dbg(dev, "dai_zephyr_multi_endpoint_copy(), dir: %d copy frames= 0x%x", dev->direction, frames); @@ -1481,14 +1505,13 @@ static void set_new_local_buffer(struct dai_data *dd, struct comp_dev *dev) /* copy and process stream data from source to sink buffers */ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_func *converter) { - uint32_t sampling = dd->sampling; struct dma_status stat; uint32_t avail_bytes; uint32_t free_bytes; uint32_t copy_bytes; - uint32_t src_samples; - uint32_t sink_samples; - uint32_t samples = UINT32_MAX; + uint32_t src_frames; + uint32_t sink_frames; + uint32_t frames = UINT32_MAX; int ret; /* get data sizes from DMA */ @@ -1522,23 +1545,26 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun } } + assert(audio_stream_get_channels(&dd->dma_buffer->stream)); + assert(audio_stream_get_channels(&dd->local_buffer->stream)); + /* calculate minimum size to copy */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { - src_samples = audio_stream_get_avail_samples(&dd->local_buffer->stream); - sink_samples = free_bytes / sampling; - samples = MIN(src_samples, sink_samples); + src_frames = audio_stream_get_avail_frames(&dd->local_buffer->stream); + sink_frames = free_bytes / audio_stream_frame_bytes(&dd->dma_buffer->stream); + frames = MIN(src_frames, sink_frames); } else { struct list_item *sink_list; - src_samples = avail_bytes / sampling; + src_frames = avail_bytes / audio_stream_frame_bytes(&dd->dma_buffer->stream); /* * there's only one sink buffer in the case of endpoint DAI devices created by * a DAI copier and it is chosen as the dd->local buffer */ if (!converter) { - sink_samples = audio_stream_get_free_samples(&dd->local_buffer->stream); - samples = MIN(samples, sink_samples); + sink_frames = audio_stream_get_free_frames(&dd->local_buffer->stream); + frames = sink_frames; } else { /* * In the case of capture DAI's with multiple sink buffers, compute the @@ -1552,15 +1578,16 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun sink = container_of(sink_list, struct comp_buffer, source_list); sink_dev = sink->sink; - if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE) { - sink_samples = - audio_stream_get_free_samples(&sink->stream); - samples = MIN(samples, sink_samples); + if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE && + sink->hw_params_configured) { + sink_frames = + audio_stream_get_free_frames(&sink->stream); + frames = MIN(frames, sink_frames); } } } - samples = MIN(samples, src_samples); + frames = MIN(frames, src_frames); } /* limit bytes per copy to one period for the whole pipeline @@ -1568,9 +1595,9 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun * if FAST_MODE is enabled, then one period limitation is omitted */ if (!dd->fast_mode) - samples = MIN(samples, dd->period_bytes / sampling); + frames = MIN(frames, dev->frames); - copy_bytes = samples * sampling; + copy_bytes = frames * audio_stream_frame_bytes(&dd->dma_buffer->stream); comp_dbg(dev, "dai_common_copy(), dir: %d copy_bytes= 0x%x", dev->direction, copy_bytes); diff --git a/src/audio/host-legacy.c b/src/audio/host-legacy.c index 9c52c5bd85ab..5326845fe021 100644 --- a/src/audio/host-legacy.c +++ b/src/audio/host-legacy.c @@ -233,11 +233,11 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { source = hd->dma_buffer; sink = hd->local_buffer; - ret = dma_buffer_copy_from(source, sink, hd->process, bytes); + ret = dma_buffer_copy_from(source, sink, hd->process, bytes, DUMMY_CHMAP); } else { source = hd->local_buffer; sink = hd->dma_buffer; - ret = dma_buffer_copy_to(source, sink, hd->process, bytes); + ret = dma_buffer_copy_to(source, sink, hd->process, bytes, DUMMY_CHMAP); } /* assert dma_buffer_copy succeed */ diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index fa72b95557a8..d92dbd24f340 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -247,11 +247,11 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { source = hd->dma_buffer; sink = hd->local_buffer; - ret = dma_buffer_copy_from(source, sink, hd->process, bytes); + ret = dma_buffer_copy_from(source, sink, hd->process, bytes, DUMMY_CHMAP); } else { source = hd->local_buffer; sink = hd->dma_buffer; - ret = dma_buffer_copy_to(source, sink, hd->process, bytes); + ret = dma_buffer_copy_to(source, sink, hd->process, bytes, DUMMY_CHMAP); } if (ret < 0) { @@ -409,6 +409,14 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev /* dma_copy_bytes should be aligned to minimum possible chunk of * data to be copied by dma. + * + * FIXME: WARNING: For some frame sizes, this can lead to a split first and/or last frame: + * one part of the frame is processed during one LL cycle, while the remaining portion + * is processed in the subsequent LL cycle. This could be a problem for components + * that assume the first sample in the buffer belongs to the first channel. Even + * if such components consume full frames, they could be bound on a fly as additional + * copier sinks or additional mixin sources or sinks, causing them to start processing + * from the wrong channel. */ return ALIGN_DOWN(dma_copy_bytes, hd->dma_copy_align); } diff --git a/src/audio/pcm_converter/CMakeLists.txt b/src/audio/pcm_converter/CMakeLists.txt index 36fd7eafc414..4f09a5a779c7 100644 --- a/src/audio/pcm_converter/CMakeLists.txt +++ b/src/audio/pcm_converter/CMakeLists.txt @@ -4,3 +4,7 @@ add_local_sources(sof pcm_converter.c pcm_converter_generic.c pcm_converter_hifi3.c) + +if(CONFIG_PCM_REMAPPING_CONVERTERS) + add_local_sources(sof pcm_remap.c) +endif() diff --git a/src/audio/pcm_converter/pcm_converter.c b/src/audio/pcm_converter/pcm_converter.c index 5335ee295b51..b489cc6e664b 100644 --- a/src/audio/pcm_converter/pcm_converter.c +++ b/src/audio/pcm_converter/pcm_converter.c @@ -58,3 +58,9 @@ int pcm_convert_as_linear(const struct audio_stream *source, uint32_t ioffset, return samples; } + +int just_copy(const struct audio_stream *source, uint32_t ioffset, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples, uint32_t chmap) +{ + return audio_stream_copy(source, ioffset, sink, ooffset, samples); +} diff --git a/src/audio/pcm_converter/pcm_converter_generic.c b/src/audio/pcm_converter/pcm_converter_generic.c index 6de32bd52495..3d4110c57165 100644 --- a/src/audio/pcm_converter/pcm_converter_generic.c +++ b/src/audio/pcm_converter/pcm_converter_generic.c @@ -36,7 +36,7 @@ #if CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE static int pcm_convert_u8_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { uint8_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -65,7 +65,7 @@ static int pcm_convert_u8_to_s32(const struct audio_stream *source, static int pcm_convert_s32_to_u8(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); uint8_t *dst = audio_stream_get_wptr(sink); @@ -97,7 +97,7 @@ static int pcm_convert_s32_to_u8(const struct audio_stream *source, static int pcm_convert_s16_to_s24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int16_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -126,7 +126,7 @@ static int pcm_convert_s16_to_s24(const struct audio_stream *source, static int pcm_convert_s24_to_s16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int16_t *dst = audio_stream_get_wptr(sink); @@ -159,7 +159,7 @@ static int pcm_convert_s24_to_s16(const struct audio_stream *source, static int pcm_convert_s16_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int16_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -188,7 +188,7 @@ static int pcm_convert_s16_to_s32(const struct audio_stream *source, static int pcm_convert_s32_to_s16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int16_t *dst = audio_stream_get_wptr(sink); @@ -221,7 +221,7 @@ static int pcm_convert_s32_to_s16(const struct audio_stream *source, static int pcm_convert_s24_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -250,7 +250,7 @@ static int pcm_convert_s24_to_s32(const struct audio_stream *source, static int pcm_convert_s32_to_s24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -279,7 +279,7 @@ static int pcm_convert_s32_to_s24(const struct audio_stream *source, static int pcm_convert_s32_to_s24_be(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -444,7 +444,7 @@ static void pcm_convert_f_to_s16_lin(const void *psrc, void *pdst, static int pcm_convert_s16_to_f(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s16_to_f_lin); @@ -452,7 +452,7 @@ static int pcm_convert_s16_to_f(const struct audio_stream *source, static int pcm_convert_f_to_s16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_f_to_s16_lin); @@ -488,7 +488,7 @@ static void pcm_convert_f_to_s24_lin(const void *psrc, void *pdst, static int pcm_convert_s24_to_f(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s24_to_f_lin); @@ -496,7 +496,7 @@ static int pcm_convert_s24_to_f(const struct audio_stream *source, static int pcm_convert_f_to_s24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_f_to_s24_lin); @@ -532,7 +532,7 @@ static void pcm_convert_f_to_s32_lin(const void *psrc, void *pdst, static int pcm_convert_s32_to_f(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s32_to_f_lin); @@ -540,7 +540,7 @@ static int pcm_convert_s32_to_f(const struct audio_stream *source, static int pcm_convert_f_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_f_to_s32_lin); @@ -549,27 +549,27 @@ static int pcm_convert_f_to_s32(const struct audio_stream *source, const struct pcm_func_map pcm_func_map[] = { #if CONFIG_PCM_CONVERTER_FORMAT_U8 - { SOF_IPC_FRAME_U8, SOF_IPC_FRAME_U8, audio_stream_copy }, + { SOF_IPC_FRAME_U8, SOF_IPC_FRAME_U8, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 */ #if CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE { SOF_IPC_FRAME_U8, SOF_IPC_FRAME_S32_LE, pcm_convert_u8_to_s32 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_U8, pcm_convert_s32_to_u8 }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S16LE - { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, audio_stream_copy }, + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24LE - { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, audio_stream_copy }, + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24_3LE - { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, audio_stream_copy }, + { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24_3LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s16_to_s24 }, { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, pcm_convert_s24_to_s16 }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, audio_stream_copy }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s16_to_s32 }, @@ -580,7 +580,7 @@ const struct pcm_func_map pcm_func_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s32_to_s24 }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE */ #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT - { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, audio_stream_copy }, + { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_FLOAT */ #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_FLOAT, pcm_convert_s16_to_f }, @@ -601,7 +601,7 @@ const size_t pcm_func_count = ARRAY_SIZE(pcm_func_map); #if CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32 static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int16_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -630,7 +630,7 @@ static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int16_t *dst = audio_stream_get_wptr(sink); @@ -660,7 +660,7 @@ static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32 static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -689,7 +689,7 @@ static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -719,7 +719,7 @@ static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32 static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -748,7 +748,7 @@ static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream *source, static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -779,7 +779,7 @@ static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, #if CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32 static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { uint8_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -809,7 +809,7 @@ static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); uint8_t *dst = audio_stream_get_wptr(sink); @@ -843,7 +843,8 @@ static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream *source, /* 2x24bit samples are packed into 3x16bit samples for hda link dma */ static int pcm_convert_s24_c32_to_s24_c24_link_gtw(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, + uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); uint16_t *dst = audio_stream_get_wptr(sink); @@ -904,11 +905,11 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_U8, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_U8, - audio_stream_copy }, + just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - audio_stream_copy}, + just_copy}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s24_to_s32}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, @@ -930,7 +931,7 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32 { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, - audio_stream_copy }, + just_copy }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S24LE @@ -939,14 +940,14 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s32_to_s24}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE_MSB, audio_stream_copy}, + SOF_IPC_FRAME_S24_4LE_MSB, just_copy}, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, pcm_convert_s32_to_s24_be}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S32_LE, audio_stream_copy}, + SOF_IPC_FRAME_S32_LE, just_copy}, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S16LE diff --git a/src/audio/pcm_converter/pcm_converter_hifi3.c b/src/audio/pcm_converter/pcm_converter_hifi3.c index da7e2ff1c7d1..1759e66ce149 100644 --- a/src/audio/pcm_converter/pcm_converter_hifi3.c +++ b/src/audio/pcm_converter/pcm_converter_hifi3.c @@ -38,7 +38,7 @@ */ static int pcm_convert_s16_to_s24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { ae_int16x4 sample = AE_ZERO16(); uint32_t nmax, i, n, m, left, left_samples; @@ -112,7 +112,7 @@ static ae_int32x2 pcm_shift_s24_to_s16(ae_int32x2 sample) */ static int pcm_convert_s24_to_s16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { ae_int16x4 sample = AE_ZERO16(); ae_int32x2 sample_1 = AE_ZERO32(); @@ -183,7 +183,7 @@ static int pcm_convert_s24_to_s16(const struct audio_stream *source, */ static int pcm_convert_s16_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int16_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -239,7 +239,7 @@ static int pcm_convert_s16_to_s32(const struct audio_stream *source, */ static int pcm_convert_s32_to_s16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int16_t *dst = audio_stream_get_wptr(sink); @@ -305,7 +305,7 @@ static int pcm_convert_s32_to_s16(const struct audio_stream *source, */ static int pcm_convert_s24_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -370,7 +370,7 @@ static ae_int32x2 pcm_shift_s32_to_s24(ae_int32x2 sample) */ static int pcm_convert_s32_to_s24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -415,7 +415,7 @@ static int pcm_convert_s32_to_s24(const struct audio_stream *source, static int pcm_convert_s32_to_s24_be(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -543,7 +543,7 @@ static void pcm_convert_f_to_s16_lin(const void *psrc, void *pdst, */ static int pcm_convert_s16_to_f(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s16_to_f_lin); @@ -558,7 +558,7 @@ static int pcm_convert_s16_to_f(const struct audio_stream *source, */ static int pcm_convert_f_to_s16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_f_to_s16_lin); @@ -644,7 +644,7 @@ static void pcm_convert_f_to_s24_lin(const void *psrc, void *pdst, */ static int pcm_convert_s24_to_f(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s24_to_f_lin); @@ -659,7 +659,7 @@ static int pcm_convert_s24_to_f(const struct audio_stream *source, */ static int pcm_convert_f_to_s24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_f_to_s24_lin); @@ -741,7 +741,7 @@ static void pcm_convert_f_to_s32_lin(const void *psrc, void *pdst, */ static int pcm_convert_s32_to_f(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s32_to_f_lin); @@ -756,7 +756,7 @@ static int pcm_convert_s32_to_f(const struct audio_stream *source, */ static int pcm_convert_f_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_f_to_s32_lin); @@ -766,20 +766,20 @@ static int pcm_convert_f_to_s32(const struct audio_stream *source, const struct pcm_func_map pcm_func_map[] = { #if CONFIG_PCM_CONVERTER_FORMAT_S16LE - { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, audio_stream_copy }, + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24LE - { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, audio_stream_copy }, + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24_3LE - { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, audio_stream_copy }, + { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24_3LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s16_to_s24 }, { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, pcm_convert_s24_to_s16 }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, audio_stream_copy }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s16_to_s32 }, @@ -791,7 +791,7 @@ const struct pcm_func_map pcm_func_map[] = { #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE */ #if XCHAL_HAVE_FP #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT - { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, audio_stream_copy }, + { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_FLOAT */ #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_FLOAT, pcm_convert_s16_to_f }, @@ -813,7 +813,7 @@ const size_t pcm_func_count = ARRAY_SIZE(pcm_func_map); static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int16_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -863,7 +863,7 @@ static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int16_t *dst = audio_stream_get_wptr(sink); @@ -922,7 +922,7 @@ static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -965,7 +965,7 @@ static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -1010,7 +1010,7 @@ static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -1065,7 +1065,7 @@ static ae_int32x2 pcm_shift_s24_c32_to_s16(ae_int32x2 sample) static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -1112,7 +1112,7 @@ static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { uint8_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -1159,7 +1159,7 @@ static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); uint8_t *dst = audio_stream_get_wptr(sink); @@ -1227,7 +1227,7 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - audio_stream_copy}, + just_copy}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s24_to_s32}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, @@ -1249,7 +1249,7 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32 { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, - audio_stream_copy }, + just_copy }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S24LE @@ -1258,14 +1258,14 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s32_to_s24}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE_MSB, audio_stream_copy}, + SOF_IPC_FRAME_S24_4LE_MSB, just_copy}, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, pcm_convert_s32_to_s24_be}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S32_LE, audio_stream_copy}, + SOF_IPC_FRAME_S32_LE, just_copy}, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S16LE diff --git a/src/audio/pcm_converter/pcm_remap.c b/src/audio/pcm_converter/pcm_remap.c new file mode 100644 index 000000000000..9204b21ee8ab --- /dev/null +++ b/src/audio/pcm_converter/pcm_remap.c @@ -0,0 +1,477 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * (c) 2024 Intel Corporation. All rights reserved. + */ + +#include +#include + +static void mute_channel_c16(struct audio_stream *stream, int channel, int frames) +{ + int num_channels = audio_stream_get_channels(stream); + int16_t *ptr = (int16_t *)audio_stream_get_wptr(stream) + channel; + + while (frames) { + int samples_wo_wrap, n, i; + + ptr = audio_stream_wrap(stream, ptr); + + samples_wo_wrap = audio_stream_samples_without_wrap_s16(stream, ptr); + n = SOF_DIV_ROUND_UP(samples_wo_wrap, num_channels); + n = MIN(n, frames); + + for (i = 0; i < n; i++) { + *ptr = 0; + ptr += num_channels; + } + + frames -= n; + } +} + +static void mute_channel_c32(struct audio_stream *stream, int channel, int frames) +{ + int num_channels = audio_stream_get_channels(stream); + int32_t *ptr = (int32_t *)audio_stream_get_wptr(stream) + channel; + + while (frames) { + int samples_wo_wrap, n, i; + + ptr = audio_stream_wrap(stream, ptr); + + samples_wo_wrap = audio_stream_samples_without_wrap_s32(stream, ptr); + n = SOF_DIV_ROUND_UP(samples_wo_wrap, num_channels); + n = MIN(n, frames); + + for (i = 0; i < n; i++) { + *ptr = 0; + ptr += num_channels; + } + + frames -= n; + } +} + +static int remap_c16(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + int src_channel, sink_channel; + int num_src_channels = audio_stream_get_channels(source); + int num_sink_channels = audio_stream_get_channels(sink); + int frames = source_samples / num_src_channels; + + for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { + int16_t *src, *dst; + int frames_left; + + src_channel = chmap & 0xf; + chmap >>= 4; + + if (src_channel == 0xf) { + mute_channel_c16(sink, sink_channel, frames); + continue; + } + + assert(src_channel < num_src_channels); + + src = (int16_t *)audio_stream_get_rptr(source) + src_channel; + dst = (int16_t *)audio_stream_get_wptr(sink) + sink_channel; + + frames_left = frames; + + while (frames_left) { + int src_samples_wo_wrap, dst_samples_wo_wrap; + int src_loops, dst_loops, n, i; + + src = audio_stream_wrap(source, src); + dst = audio_stream_wrap(sink, dst); + + src_samples_wo_wrap = audio_stream_samples_without_wrap_s16(source, src); + src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + + dst_samples_wo_wrap = audio_stream_samples_without_wrap_s16(sink, dst); + dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + + n = MIN(src_loops, dst_loops); + n = MIN(n, frames_left); + + for (i = 0; i < n; i++) { + *dst = *src; + src += num_src_channels; + dst += num_sink_channels; + } + + frames_left -= n; + } + } + + return source_samples; +} + +static inline int remap_c32_left_shift(const struct audio_stream *source, + struct audio_stream *sink, + uint32_t source_samples, uint32_t chmap, + int shift) +{ + int src_channel, sink_channel; + int num_src_channels = audio_stream_get_channels(source); + int num_sink_channels = audio_stream_get_channels(sink); + int frames = source_samples / num_src_channels; + + for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { + int32_t *src, *dst; + int frames_left; + + src_channel = chmap & 0xf; + chmap >>= 4; + + if (src_channel == 0xf) { + mute_channel_c32(sink, sink_channel, frames); + continue; + } + + assert(src_channel < num_src_channels); + + src = (int32_t *)audio_stream_get_rptr(source) + src_channel; + dst = (int32_t *)audio_stream_get_wptr(sink) + sink_channel; + + frames_left = frames; + + while (frames_left) { + int src_samples_wo_wrap, dst_samples_wo_wrap; + int src_loops, dst_loops, n, i; + + src = audio_stream_wrap(source, src); + dst = audio_stream_wrap(sink, dst); + + src_samples_wo_wrap = audio_stream_samples_without_wrap_s32(source, src); + src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + + dst_samples_wo_wrap = audio_stream_samples_without_wrap_s32(sink, dst); + dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + + n = MIN(src_loops, dst_loops); + n = MIN(n, frames_left); + + for (i = 0; i < n; i++) { + *dst = *src << shift; + src += num_src_channels; + dst += num_sink_channels; + } + + frames_left -= n; + } + } + + return source_samples; +} + +static inline int remap_c32_right_shift(const struct audio_stream *source, + struct audio_stream *sink, + uint32_t source_samples, uint32_t chmap, + int shift) +{ + int src_channel, sink_channel; + int num_src_channels = audio_stream_get_channels(source); + int num_sink_channels = audio_stream_get_channels(sink); + int frames = source_samples / num_src_channels; + + for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { + int32_t *src, *dst; + int frames_left; + + src_channel = chmap & 0xf; + chmap >>= 4; + + if (src_channel == 0xf) { + mute_channel_c32(sink, sink_channel, frames); + continue; + } + + assert(src_channel < num_src_channels); + + src = (int32_t *)audio_stream_get_rptr(source) + src_channel; + dst = (int32_t *)audio_stream_get_wptr(sink) + sink_channel; + + frames_left = frames; + + while (frames_left) { + int src_samples_wo_wrap, dst_samples_wo_wrap; + int src_loops, dst_loops, n, i; + + src = audio_stream_wrap(source, src); + dst = audio_stream_wrap(sink, dst); + + src_samples_wo_wrap = audio_stream_samples_without_wrap_s32(source, src); + src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + + dst_samples_wo_wrap = audio_stream_samples_without_wrap_s32(sink, dst); + dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + + n = MIN(src_loops, dst_loops); + n = MIN(n, frames_left); + + for (i = 0; i < n; i++) { + *dst = *src >> shift; + src += num_src_channels; + dst += num_sink_channels; + } + + frames_left -= n; + } + } + + return source_samples; +} + +static inline int remap_c16_to_c32(const struct audio_stream *source, + struct audio_stream *sink, + uint32_t source_samples, uint32_t chmap, + int shift) +{ + int src_channel, sink_channel; + int num_src_channels = audio_stream_get_channels(source); + int num_sink_channels = audio_stream_get_channels(sink); + int frames = source_samples / num_src_channels; + + for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { + int16_t *src; + int32_t *dst; + int frames_left; + + src_channel = chmap & 0xf; + chmap >>= 4; + + if (src_channel == 0xf) { + mute_channel_c32(sink, sink_channel, frames); + continue; + } + + assert(src_channel < num_src_channels); + + src = (int16_t *)audio_stream_get_rptr(source) + src_channel; + dst = (int32_t *)audio_stream_get_wptr(sink) + sink_channel; + + frames_left = frames; + + while (frames_left) { + int src_samples_wo_wrap, dst_samples_wo_wrap; + int src_loops, dst_loops, n, i; + + src = audio_stream_wrap(source, src); + dst = audio_stream_wrap(sink, dst); + + src_samples_wo_wrap = audio_stream_samples_without_wrap_s16(source, src); + src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + + dst_samples_wo_wrap = audio_stream_samples_without_wrap_s32(sink, dst); + dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + + n = MIN(src_loops, dst_loops); + n = MIN(n, frames_left); + + for (i = 0; i < n; i++) { + *dst = (int32_t)*src << shift; + src += num_src_channels; + dst += num_sink_channels; + } + + frames_left -= n; + } + } + + return source_samples; +} + +static inline int remap_c32_to_c16(const struct audio_stream *source, + struct audio_stream *sink, + uint32_t source_samples, uint32_t chmap, + int shift) +{ + int src_channel, sink_channel; + int num_src_channels = audio_stream_get_channels(source); + int num_sink_channels = audio_stream_get_channels(sink); + int frames = source_samples / num_src_channels; + + for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { + int32_t *src; + int16_t *dst; + int frames_left; + + src_channel = chmap & 0xf; + chmap >>= 4; + + if (src_channel == 0xf) { + mute_channel_c16(sink, sink_channel, frames); + continue; + } + + assert(src_channel < num_src_channels); + + src = (int32_t *)audio_stream_get_rptr(source) + src_channel; + dst = (int16_t *)audio_stream_get_wptr(sink) + sink_channel; + + frames_left = frames; + + while (frames_left) { + int src_samples_wo_wrap, dst_samples_wo_wrap; + int src_loops, dst_loops, n, i; + + src = audio_stream_wrap(source, src); + dst = audio_stream_wrap(sink, dst); + + src_samples_wo_wrap = audio_stream_samples_without_wrap_s32(source, src); + src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + + dst_samples_wo_wrap = audio_stream_samples_without_wrap_s16(sink, dst); + dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + + n = MIN(src_loops, dst_loops); + n = MIN(n, frames_left); + + for (i = 0; i < n; i++) { + *dst = *src >> shift; + src += num_src_channels; + dst += num_sink_channels; + } + + frames_left -= n; + } + } + + return source_samples; +} + +static int remap_c32(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_left_shift(source, sink, source_samples, chmap, 0); +} + +static int remap_c32_to_c16_right_shift_16(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_to_c16(source, sink, source_samples, chmap, 16); +} + +static int remap_c16_to_c32_left_shift_16(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c16_to_c32(source, sink, source_samples, chmap, 16); +} + +static int remap_c32_to_c16_right_shift_8(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_to_c16(source, sink, source_samples, chmap, 8); +} + +static int remap_c16_to_c32_left_shift_8(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c16_to_c32(source, sink, source_samples, chmap, 8); +} + +static int remap_c32_right_shift_8(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_right_shift(source, sink, source_samples, chmap, 8); +} + +static int remap_c32_left_shift_8(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_left_shift(source, sink, source_samples, chmap, 8); +} + +static int remap_c32_right_shift_16(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_right_shift(source, sink, source_samples, chmap, 16); +} + +static int remap_c32_left_shift_16(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_left_shift(source, sink, source_samples, chmap, 16); +} + +static int remap_c32_to_c16_no_shift(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_to_c16(source, sink, source_samples, chmap, 0); +} + +static int remap_c16_to_c32_no_shift(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c16_to_c32(source, sink, source_samples, chmap, 0); +} + +/* Unfortunately, all these nice "if"s were commented out to suppress + * CI "defined but not used" warnings. + */ +const struct pcm_func_map pcm_remap_func_map[] = { +/* #if CONFIG_PCM_CONVERTER_FORMAT_S16LE */ + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, remap_c16}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE */ + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, remap_c16_to_c32_left_shift_8}, + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, remap_c32_to_c16_right_shift_8}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB */ + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE_MSB, remap_c16_to_c32_left_shift_16}, + { SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S16_LE, remap_c32_to_c16_right_shift_16}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, remap_c16_to_c32_left_shift_16}, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, remap_c32_to_c16_right_shift_16}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S16_4LE */ + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_4LE, remap_c16_to_c32_no_shift}, + { SOF_IPC_FRAME_S16_4LE, SOF_IPC_FRAME_S16_LE, remap_c32_to_c16_no_shift}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE */ + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, remap_c32}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB */ + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE_MSB, remap_c32_left_shift_8}, + { SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S24_4LE, remap_c32_right_shift_8}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, remap_c32_left_shift_8}, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, remap_c32_right_shift_8}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE && CONFIG_PCM_CONVERTER_FORMAT_S16_4LE */ + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_4LE, remap_c32_right_shift_8}, + { SOF_IPC_FRAME_S16_4LE, SOF_IPC_FRAME_S24_4LE, remap_c32_left_shift_8}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ + { SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, remap_c32}, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, remap_c32}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S32LE */ + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, remap_c32}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S16_4LE */ + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_4LE, remap_c32_right_shift_16}, + { SOF_IPC_FRAME_S16_4LE, SOF_IPC_FRAME_S32_LE, remap_c32_left_shift_16}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S16_4LE */ + { SOF_IPC_FRAME_S16_4LE, SOF_IPC_FRAME_S16_4LE, remap_c32}, +/* #endif */ +}; + +const size_t pcm_remap_func_count = ARRAY_SIZE(pcm_remap_func_map); diff --git a/src/include/module/ipc/stream.h b/src/include/module/ipc/stream.h index 86837d7ea302..c3d05d903075 100644 --- a/src/include/module/ipc/stream.h +++ b/src/include/module/ipc/stream.h @@ -20,6 +20,7 @@ enum sof_ipc_frame { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_U8, + SOF_IPC_FRAME_S16_4LE /* 16-bit in 32-bit container */ }; #endif /* __MODULE_IPC_STREAM_H__ */ diff --git a/src/include/sof/audio/pcm_converter.h b/src/include/sof/audio/pcm_converter.h index a06dc79f632a..3563a0d6557e 100644 --- a/src/include/sof/audio/pcm_converter.h +++ b/src/include/sof/audio/pcm_converter.h @@ -42,12 +42,16 @@ struct audio_stream; * \param ioffset offset to first sample in source stream * \param sink output buffer, write pointer is not modified * \param ooffset offset to first sample in sink stream - * \param samples number of samples to convert - * \return error code or number of processed samples. + * \param source_samples number of samples to convert, for remapping -- number of source samples + * \param chmap channel map for remapping, ignored by non-remapping conversion func + * \return error code or number of processed samples (source samples in case of remapping). */ typedef int (*pcm_converter_func)(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples); + uint32_t ooffset, uint32_t source_samples, uint32_t chmap); + +/* A channel map that does not perform any remapping. */ +#define DUMMY_CHMAP 0x76543210 /** * \brief PCM conversion function interface for data in linear buffer @@ -71,6 +75,14 @@ extern const struct pcm_func_map pcm_func_map[]; /** \brief Number of conversion functions. */ extern const size_t pcm_func_count; +#if CONFIG_PCM_REMAPPING_CONVERTERS +/** \brief Map of formats with dedicated remap with conversion functions. */ +extern const struct pcm_func_map pcm_remap_func_map[]; + +/** \brief Number of remap with conversion functions. */ +extern const size_t pcm_remap_func_count; +#endif + /** * \brief Retrieves PCM conversion function. * \param[in] in Source frame format. @@ -94,6 +106,30 @@ pcm_get_conversion_function(enum sof_ipc_frame in, return NULL; } +#if CONFIG_PCM_REMAPPING_CONVERTERS +/** + * \brief Retrieves PCM remap with conversion function. + * \param[in] in Source frame format. + * \param[in] out Sink frame format. + */ +static inline pcm_converter_func +pcm_get_remap_function(enum sof_ipc_frame in, enum sof_ipc_frame out) +{ + int i; + + for (i = 0; i < pcm_remap_func_count; i++) { + if (in != pcm_remap_func_map[i].source) + continue; + if (out != pcm_remap_func_map[i].sink) + continue; + + return pcm_remap_func_map[i].func; + } + + return NULL; +} +#endif + /** \brief PCM conversion functions mapfor different size of valid bit and container. */ struct pcm_func_vc_map { enum sof_ipc_frame source; /**< source frame container format */ @@ -160,4 +196,8 @@ int pcm_convert_as_linear(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples, pcm_converter_lin_func converter); +/* Copy stream without conversion. chmap parameter is ignored. */ +int just_copy(const struct audio_stream *source, uint32_t ioffset, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples, uint32_t chmap); + #endif /* __SOF_AUDIO_PCM_CONVERTER_H__ */ diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index 98e174a43c8d..b7f2f0f5c6f1 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -106,6 +106,10 @@ struct llp_slot_info { uint32_t reg_offset; }; +typedef int (*channel_copy_func)(const struct audio_stream *src, unsigned int src_channel, + struct audio_stream *dst, unsigned int dst_channel, + unsigned int frames); + /** * \brief DAI runtime data */ @@ -125,8 +129,14 @@ struct dai_data { int xrun; /* true if we are doing xrun recovery */ pcm_converter_func process; /* processing function */ + uint32_t chmap; + + channel_copy_func channel_copy; /* channel copy func used by multi-endpoint + * gateway to mux/demux stream from/to multiple + * DMA buffers + */ - uint32_t period_bytes; /* number of bytes per one period */ + uint32_t period_bytes; /* number of DMA bytes per one period */ uint64_t total_data_processed; struct ipc_config_dai ipc_config; /* generic common config */ @@ -145,8 +155,6 @@ struct dai_data { /* llp slot info in memory windows */ struct llp_slot_info slot_info; - /* save current sampling for current dai device */ - uint32_t sampling; /* fast mode, use one byte memory to save repreated cycles */ bool fast_mode; }; diff --git a/src/lib/dma.c b/src/lib/dma.c index 185e9b72694c..d889d1e3da47 100644 --- a/src/lib/dma.c +++ b/src/lib/dma.c @@ -321,20 +321,55 @@ void dma_sg_free(struct dma_sg_elem_array *elem_array) int dma_buffer_copy_from(struct comp_buffer *source, struct comp_buffer *sink, - dma_process_func process, uint32_t source_bytes) + dma_process_func process, uint32_t source_bytes, uint32_t chmap) { + int source_channels = audio_stream_get_channels(&source->stream); + int sink_channels = audio_stream_get_channels(&sink->stream); + int source_samples; + int sink_bytes; struct audio_stream *istream = &source->stream; - uint32_t samples = source_bytes / - audio_stream_sample_bytes(istream); - uint32_t sink_bytes = audio_stream_sample_bytes(&sink->stream) * - samples; int ret; + /* WORKAROUND: Given that remapping conversion can alter the number of channels, it's + * necessary to use frames, not samples, to calculate sink_bytes for writeback/produce. + * Unfortunately, the Host DMA imposes size alignment requirement for chunks of data + * being copied. For certain frame sizes, this alignment constraint results in splitting + * the first and/or last frame in the buffer. Consequently, frame-based calculations + * cannot be used with Host DMA. Fortunately, remapping conversion is specifically + * designed for use with IPC4 DAI gateway's device posture feature. IPC4 DAI gateway + * does not have the same size alignment limitations. Therefore, frame-based calculations + * are employed only when necessary —- in the case of IPC4 DAI gateway with remapping + * conversion that modifies number of channels. + */ + if (source_channels == sink_channels) { + /* Sample-based calculations can be used here since the source and sink have + * the same number of samples. Frame-based calculations, however, cannot be used + * in this scenario, as it might involve a gateway that does not supply full frames + * (e.g., the Host gateway). + */ + source_samples = source_bytes / audio_stream_sample_bytes(istream); + sink_bytes = source_samples * audio_stream_sample_bytes(&sink->stream); + } else { + int frames; + + /* Sample-based calculations cannot be used here since source and sink have + * different number of samples. Fortunately, only IPC4 DAI gateway supports + * remapping conversion -- it's safe to use frame-based calculations in this + * context. + */ + assert(source_channels); + assert(sink_channels); + + frames = source_bytes / audio_stream_frame_bytes(istream); + sink_bytes = audio_stream_frame_bytes(&sink->stream) * frames; + source_samples = frames * source_channels; + } + /* source buffer contains data copied by DMA */ audio_stream_invalidate(istream, source_bytes); /* process data */ - ret = process(istream, 0, &sink->stream, 0, samples); + ret = process(istream, 0, &sink->stream, 0, source_samples, chmap); buffer_stream_writeback(sink, sink_bytes); @@ -350,19 +385,54 @@ int dma_buffer_copy_from(struct comp_buffer *source, int dma_buffer_copy_to(struct comp_buffer *source, struct comp_buffer *sink, - dma_process_func process, uint32_t sink_bytes) + dma_process_func process, uint32_t sink_bytes, uint32_t chmap) { + int source_channels = audio_stream_get_channels(&source->stream); + int sink_channels = audio_stream_get_channels(&sink->stream); + int source_samples; + int source_bytes; struct audio_stream *ostream = &sink->stream; - uint32_t samples = sink_bytes / - audio_stream_sample_bytes(ostream); - uint32_t source_bytes = audio_stream_sample_bytes(&source->stream) * - samples; int ret; + /* WORKAROUND: Given that remapping conversion can alter the number of channels, it's + * necessary to use frames, not samples, to calculate source_bytes for invalidate/consume. + * Unfortunately, the Host DMA imposes size alignment requirement for chunks of data + * being copied. For certain frame sizes, this alignment constraint results in splitting + * the first and/or last frame in the buffer. Consequently, frame-based calculations + * cannot be used with Host DMA. Fortunately, remapping conversion is specifically + * designed for use with IPC4 DAI gateway's device posture feature. IPC4 DAI gateway + * does not have the same size alignment limitations. Therefore, frame-based calculations + * are employed only when necessary —- in the case of IPC4 DAI gateway with remapping + * conversion that modifies number of channels. + */ + if (source_channels == sink_channels) { + /* Sample-based calculations can be used here since the source and sink have + * the same number of samples. Frame-based calculations, however, cannot be used + * in this scenario, as it might involve a gateway that does not supply full frames + * (e.g., the Host gateway). + */ + source_samples = sink_bytes / audio_stream_sample_bytes(ostream); + source_bytes = source_samples * audio_stream_sample_bytes(&source->stream); + } else { + int frames; + + /* Sample-based calculations cannot be used here since source and sink have + * different number of samples. Fortunately, only IPC4 DAI gateway supports + * remapping conversion -- it's safe to use frame-based calculations in this + * context. + */ + assert(source_channels); + assert(sink_channels); + + frames = sink_bytes / audio_stream_frame_bytes(ostream); + source_bytes = audio_stream_frame_bytes(&source->stream) * frames; + source_samples = frames * source_channels; + } + buffer_stream_invalidate(source, source_bytes); /* process data */ - ret = process(&source->stream, 0, ostream, 0, samples); + ret = process(&source->stream, 0, ostream, 0, source_samples, chmap); /* sink buffer contains data meant to copied to DMA */ audio_stream_writeback(ostream, sink_bytes); @@ -379,17 +449,52 @@ int dma_buffer_copy_to(struct comp_buffer *source, int dma_buffer_copy_from_no_consume(struct comp_buffer *source, struct comp_buffer *sink, - dma_process_func process, uint32_t source_bytes) + dma_process_func process, uint32_t source_bytes, uint32_t chmap) { + int source_channels = audio_stream_get_channels(&source->stream); + int sink_channels = audio_stream_get_channels(&sink->stream); + int source_samples; + int sink_bytes; struct audio_stream *istream = &source->stream; - uint32_t samples = source_bytes / - audio_stream_sample_bytes(istream); - uint32_t sink_bytes = audio_stream_sample_bytes(&sink->stream) * - samples; int ret; + /* WORKAROUND: Given that remapping conversion can alter the number of channels, it's + * necessary to use frames, not samples, to calculate sink_bytes for writeback/produce. + * Unfortunately, the Host DMA imposes size alignment requirement for chunks of data + * being copied. For certain frame sizes, this alignment constraint results in splitting + * the first and/or last frame in the buffer. Consequently, frame-based calculations + * cannot be used with Host DMA. Fortunately, remapping conversion is specifically + * designed for use with IPC4 DAI gateway's device posture feature. IPC4 DAI gateway + * does not have the same size alignment limitations. Therefore, frame-based calculations + * are employed only when necessary —- in the case of IPC4 DAI gateway with remapping + * conversion that modifies number of channels. + */ + if (source_channels == sink_channels) { + /* Sample-based calculations can be used here since the source and sink have + * the same number of samples. Frame-based calculations, however, cannot be used + * in this scenario, as it might involve a gateway that does not supply full frames + * (e.g., the Host gateway). + */ + source_samples = source_bytes / audio_stream_sample_bytes(istream); + sink_bytes = source_samples * audio_stream_sample_bytes(&sink->stream); + } else { + int frames; + + /* Sample-based calculations cannot be used here since source and sink have + * different number of samples. Fortunately, only IPC4 DAI gateway supports + * remapping conversion -- it's safe to use frame-based calculations in this + * context. + */ + assert(source_channels); + assert(sink_channels); + + frames = source_bytes / audio_stream_frame_bytes(istream); + sink_bytes = audio_stream_frame_bytes(&sink->stream) * frames; + source_samples = frames * source_channels; + } + /* process data */ - ret = process(istream, 0, &sink->stream, 0, samples); + ret = process(istream, 0, &sink->stream, 0, source_samples, chmap); buffer_stream_writeback(sink, sink_bytes); diff --git a/test/cmocka/src/audio/pcm_converter/pcm_float.c b/test/cmocka/src/audio/pcm_converter/pcm_float.c index acd98a7f35b6..70ccd3621758 100644 --- a/test/cmocka/src/audio/pcm_converter/pcm_float.c +++ b/test/cmocka/src/audio/pcm_converter/pcm_float.c @@ -99,7 +99,7 @@ static struct comp_buffer *_test_pcm_convert(enum sof_ipc_frame frm_in, enum sof /* run conversion */ fun = pcm_get_conversion_function(frm_in, frm_out); assert_non_null(fun); - fun(&source->stream, 0, &sink->stream, 0, samples); + fun(&source->stream, 0, &sink->stream, 0, samples, DUMMY_CHMAP); /* assert last value in sink is untouched */ assert_int_equal(((uint8_t *)sink->stream.w_ptr)[outbytes - 1], fillval); diff --git a/xtos/include/sof/lib/dma.h b/xtos/include/sof/lib/dma.h index 6ae18f24a1bd..bf333d198d39 100644 --- a/xtos/include/sof/lib/dma.h +++ b/xtos/include/sof/lib/dma.h @@ -259,7 +259,7 @@ struct dma_info { struct audio_stream; typedef int (*dma_process_func)(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t frames); + uint32_t ooffset, uint32_t source_samples, uint32_t chmap); /** * \brief API to initialize a platform DMA controllers. @@ -528,14 +528,10 @@ static inline uint32_t dma_sg_get_size(struct dma_sg_elem_array *ea) return size; } -struct audio_stream; -typedef void (*dma_process)(const struct audio_stream *, - struct audio_stream *, uint32_t); - /* copies data from DMA buffer using provided processing function */ int dma_buffer_copy_from(struct comp_buffer *source, struct comp_buffer *sink, - dma_process_func process, uint32_t source_bytes); + dma_process_func process, uint32_t source_bytes, uint32_t chmap); /* * Used when copying DMA buffer bytes into multiple sink buffers, one at a time using the provided @@ -544,12 +540,13 @@ int dma_buffer_copy_from(struct comp_buffer *source, */ int dma_buffer_copy_from_no_consume(struct comp_buffer *source, struct comp_buffer *sink, - dma_process_func process, uint32_t source_bytes); + dma_process_func process, + uint32_t source_bytes, uint32_t chmap); /* copies data to DMA buffer using provided processing function */ int dma_buffer_copy_to(struct comp_buffer *source, struct comp_buffer *sink, - dma_process_func process, uint32_t sink_bytes); + dma_process_func process, uint32_t sink_bytes, uint32_t chmap); /* generic DMA DSP <-> Host copier */ diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index c9de5f9b5cbb..0caa462c39d3 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -412,9 +412,6 @@ zephyr_library_sources( # SOF mandatory audio processing ${SOF_AUDIO_PATH}/channel_map.c - ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter_hifi3.c - ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter.c - ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter_generic.c ${SOF_AUDIO_PATH}/buffer.c ${SOF_AUDIO_PATH}/source_api_helper.c ${SOF_AUDIO_PATH}/sink_api_helper.c @@ -704,6 +701,15 @@ zephyr_library_sources_ifdef(CONFIG_COMP_COPIER ${SOF_AUDIO_PATH}/copier/copier_dai.c ) +zephyr_library_sources( + ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter_hifi3.c + ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter.c + ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter_generic.c +) +zephyr_library_sources_ifdef(CONFIG_PCM_REMAPPING_CONVERTERS + ${SOF_AUDIO_PATH}/pcm_converter/pcm_remap.c +) + zephyr_library_sources_ifdef(CONFIG_MAXIM_DSM ${SOF_AUDIO_PATH}/smart_amp/smart_amp.c ${SOF_AUDIO_PATH}/smart_amp/smart_amp_generic.c