Skip to content

Commit 0e03b42

Browse files
committed
Audio: Selector: Add support for multiple up/down-mix profiles
This patch extends the struct ipc4_selector_coeffs_config. The first 16-bit reserved field is split into to 8-bit field for source and sink channels count. The configuration is changed to array of the previous structs instead of single. When preparing for stream the array is checked for matching number of channels for source and sink and if found the coefficients for the channels counts is selected into use. The change avoids the need for user space to update the configuration in runtime if the blob used for initialization contains all the needed channels up/down-mix profiles. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
1 parent 4fd12da commit 0e03b42

3 files changed

Lines changed: 135 additions & 13 deletions

File tree

src/audio/selector/selector.c

Lines changed: 119 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -572,9 +572,9 @@ static void build_config(struct comp_data *cd, struct module_config *cfg)
572572
cd->config.out_channels_count = out_fmt->channels_count;
573573

574574
/* Build default coefficient array (unity Q10 on diagonal, i.e. pass-through mode) */
575-
memset(&cd->coeffs_config, 0, sizeof(cd->coeffs_config));
575+
memset(cd->coeffs_config, 0, sizeof(*cd->coeffs_config));
576576
for (i = 0; i < MIN(SEL_SOURCE_CHANNELS_MAX, SEL_SINK_CHANNELS_MAX); i++)
577-
cd->coeffs_config.coeffs[i][i] = 1 << 10;
577+
cd->coeffs_config->coeffs[i][i] = SEL_COEF_ONE_Q10;
578578
}
579579

580580
static int selector_init(struct processing_module *mod)
@@ -620,6 +620,18 @@ static int selector_init(struct processing_module *mod)
620620
cd->sel_ipc4_cfg.init_payload_fmt = payload_fmt;
621621
md->private = cd;
622622

623+
/* Allocate space for max number of configurations. */
624+
cd->multi_coeffs_config_size =
625+
SEL_MAX_NUM_CONFIGS * sizeof(struct ipc4_selector_coeffs_config);
626+
cd->multi_coeffs_config = mod_zalloc(mod, cd->multi_coeffs_config_size);
627+
if (!cd->multi_coeffs_config) {
628+
mod_free(mod, cd);
629+
return -ENOMEM;
630+
}
631+
632+
/* Default configuration is set to first configuration */
633+
cd->coeffs_config = &cd->multi_coeffs_config[0];
634+
623635
if (payload_fmt == IPC4_SEL_INIT_PAYLOAD_BASE_WITH_EXT) {
624636
size_t size = sizeof(struct sof_selector_ipc4_pin_config);
625637

@@ -733,6 +745,7 @@ static int selector_free(struct processing_module *mod)
733745

734746
comp_dbg(mod->dev, "entry");
735747

748+
mod_free(mod, cd->multi_coeffs_config);
736749
mod_free(mod, cd);
737750

738751
return 0;
@@ -769,12 +782,26 @@ static int selector_set_config(struct processing_module *mod, uint32_t config_id
769782
size_t response_size)
770783
{
771784
struct comp_data *cd = module_get_private_data(mod);
785+
int n;
772786

773787
if (config_id == IPC4_SELECTOR_COEFFS_CONFIG_ID) {
774-
if (data_offset_size != sizeof(cd->coeffs_config))
788+
if (data_offset_size > cd->multi_coeffs_config_size) {
789+
comp_err(mod->dev, "The configuration blob is too large");
775790
return -EINVAL;
791+
}
776792

777-
memcpy_s(&cd->coeffs_config, sizeof(cd->coeffs_config), fragment, data_offset_size);
793+
/* The size must be N times the coefficient vectors size of one channels
794+
* up/down mix profile.
795+
*/
796+
n = data_offset_size / sizeof(struct ipc4_selector_coeffs_config);
797+
if (data_offset_size != n * sizeof(struct ipc4_selector_coeffs_config)) {
798+
comp_err(mod->dev, "Invalid configuration size.");
799+
return -EINVAL;
800+
}
801+
802+
memcpy_s(cd->multi_coeffs_config, cd->multi_coeffs_config_size,
803+
fragment, data_offset_size);
804+
cd->num_configs = n;
778805
return 0;
779806
}
780807

@@ -799,18 +826,100 @@ static int selector_process(struct processing_module *mod,
799826
struct output_stream_buffer *output_buffers,
800827
int num_output_buffers)
801828
{
829+
struct audio_stream *source;
830+
struct audio_stream *sink;
802831
struct comp_data *cd = module_get_private_data(mod);
803832
uint32_t avail_frames = input_buffers[0].size;
833+
uint32_t samples;
804834

805835
comp_dbg(mod->dev, "entry");
806836

837+
if (cd->passthrough) {
838+
source = input_buffers->data;
839+
sink = output_buffers->data;
840+
samples = avail_frames * audio_stream_get_channels(source);
841+
audio_stream_copy(source, 0, sink, 0, samples);
842+
module_update_buffer_position(input_buffers, output_buffers, avail_frames);
843+
return 0;
844+
}
845+
807846
if (avail_frames)
808847
/* copy selected channels from in to out */
809848
cd->sel_func(mod, input_buffers, output_buffers, avail_frames);
810849

811850
return 0;
812851
}
813852

853+
/**
854+
* \brief Get mix coefficients set from configuration blob with multiple coefficients sets.
855+
* Also activate more efficient pass-through copy mode if the coefficients indicate 1:1
856+
* copy from source to sink.
857+
* \param[in,out] mod Selector base module device.
858+
* \param[in] source_channels Number of channels in source.
859+
* \param[in] sink_channels Number of channels in sink.
860+
*
861+
* \return Error code.
862+
*/
863+
static int selector_find_coefficients(struct processing_module *mod, int source_channels,
864+
int sink_channels)
865+
{
866+
struct comp_data *cd = module_get_private_data(mod);
867+
struct comp_dev *dev = mod->dev;
868+
int i, j;
869+
int16_t coef;
870+
bool found;
871+
872+
/* The first config for coefficients always exists. It originates from configuration
873+
* blob for a single mix profille or from default values (1.0) from set_selector_params().
874+
*/
875+
cd->coeffs_config = cd->multi_coeffs_config;
876+
877+
if (cd->num_configs > 1) {
878+
/* A pass-through blob with two or more configurations is for the max
879+
* channels (8) amount.
880+
*/
881+
if (source_channels == sink_channels) {
882+
source_channels = SEL_SOURCE_CHANNELS_MAX;
883+
sink_channels = SEL_SINK_CHANNELS_MAX;
884+
}
885+
886+
found = false;
887+
for (i = 0; i < cd->num_configs; i++) {
888+
if (cd->multi_coeffs_config[i].source_channels_count == source_channels &&
889+
cd->multi_coeffs_config[i].sink_channels_count == sink_channels) {
890+
cd->coeffs_config = &cd->multi_coeffs_config[i];
891+
found = true;
892+
}
893+
}
894+
895+
if (!found) {
896+
comp_err(dev, "No mix coefficients found for %d to %d channels.",
897+
source_channels, sink_channels);
898+
return -EINVAL;
899+
}
900+
}
901+
902+
/* The pass-through copy function can be used if coefficients are a unit matrix for
903+
* 1:1 stream copy.
904+
*/
905+
cd->passthrough = true;
906+
for (i = 0; i < sink_channels; i++) {
907+
for (j = 0; j < source_channels; j++) {
908+
coef = cd->coeffs_config->coeffs[i][j];
909+
if ((i == j && coef != SEL_COEF_ONE_Q10) || (i != j && coef != 0))
910+
cd->passthrough = false;
911+
}
912+
}
913+
914+
if (cd->passthrough)
915+
comp_info(dev, "Passthrough mode.");
916+
else
917+
comp_info(dev, "Using coefficients for %d to %d channels.",
918+
source_channels, sink_channels);
919+
920+
return 0;
921+
}
922+
814923
/**
815924
* \brief Prepares selector component for processing.
816925
* \param[in,out] mod Selector base module device.
@@ -825,6 +934,8 @@ static int selector_prepare(struct processing_module *mod,
825934
struct comp_dev *dev = mod->dev;
826935
struct comp_buffer *sinkb, *sourceb;
827936
size_t sink_size;
937+
unsigned int source_channels;
938+
unsigned int sink_channels;
828939
int ret;
829940

830941
comp_dbg(dev, "entry");
@@ -855,9 +966,9 @@ static int selector_prepare(struct processing_module *mod,
855966
* proper number of channels [1] for selector to actually
856967
* reduce channel count between source and sink
857968
*/
858-
comp_info(dev, "source sink channel = %u %u",
859-
audio_stream_get_channels(&sourceb->stream),
860-
audio_stream_get_channels(&sinkb->stream));
969+
source_channels = audio_stream_get_channels(&sourceb->stream);
970+
sink_channels = audio_stream_get_channels(&sinkb->stream);
971+
comp_dbg(dev, "source sink channel = %u %u", source_channels, sink_channels);
861972

862973
sink_size = audio_stream_get_size(&sinkb->stream);
863974

@@ -891,7 +1002,7 @@ static int selector_prepare(struct processing_module *mod,
8911002
return -EINVAL;
8921003
}
8931004

894-
return 0;
1005+
return selector_find_coefficients(mod, source_channels, sink_channels);
8951006
}
8961007

8971008
/**

src/audio/selector/selector_generic.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ static void sel_s16le(struct processing_module *mod, struct input_stream_buffer
228228
n = MIN(n, nmax);
229229
for (i = 0; i < n; i++) {
230230
process_frame_s16le(dest, n_chan_sink, src, n_chan_source,
231-
&cd->coeffs_config);
231+
cd->coeffs_config);
232232
src += audio_stream_get_channels(source);
233233
dest += audio_stream_get_channels(sink);
234234
}
@@ -301,7 +301,7 @@ static void sel_s24le(struct processing_module *mod, struct input_stream_buffer
301301
n = MIN(n, nmax);
302302
for (i = 0; i < n; i++) {
303303
process_frame_s24le(dest, n_chan_sink, src, n_chan_source,
304-
&cd->coeffs_config);
304+
cd->coeffs_config);
305305
src += audio_stream_get_channels(source);
306306
dest += audio_stream_get_channels(sink);
307307
}
@@ -372,7 +372,7 @@ static void sel_s32le(struct processing_module *mod, struct input_stream_buffer
372372
n = MIN(n, nmax);
373373
for (i = 0; i < n; i++) {
374374
process_frame_s32le(dest, n_chan_sink, src, n_chan_source,
375-
&cd->coeffs_config);
375+
cd->coeffs_config);
376376
src += audio_stream_get_channels(source);
377377
dest += audio_stream_get_channels(sink);
378378
}

src/include/sof/audio/selector.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
struct comp_buffer;
2828
struct comp_dev;
2929

30+
/** \brief Default mix gain. */
31+
#define SEL_COEF_ONE_Q10 1024 /* int16(1 * 2^10) */
32+
3033
#if CONFIG_IPC_MAJOR_3
3134
/** \brief Supported channel count on input. */
3235
#define SEL_SOURCE_2CH 2
@@ -43,6 +46,9 @@ struct comp_dev;
4346
/** \brief Maximum supported channel count on output. */
4447
#define SEL_SINK_CHANNELS_MAX 8
4548

49+
/** \brief Maximum number of configurations in the blob received with set_config() */
50+
#define SEL_MAX_NUM_CONFIGS 8
51+
4652
#define SEL_NUM_IN_PIN_FMTS 1
4753
#define SEL_NUM_OUT_PIN_FMTS 1
4854

@@ -60,7 +66,8 @@ enum ipc4_selector_config_id {
6066

6167
/** \brief IPC4 mixing coefficients configuration. */
6268
struct ipc4_selector_coeffs_config {
63-
uint16_t rsvd0; /**< Unused field, keeps the structure aligned with common layout */
69+
uint8_t source_channels_count; /**< source channels count when num_configs != 0 */
70+
uint8_t sink_channels_count; /**< sink channels count when num_configs != 0 */
6471
uint16_t rsvd1; /**< Unused field, keeps the structure aligned with common layout */
6572

6673
/** Mixing coefficients in Q10 fixed point format */
@@ -108,7 +115,9 @@ typedef void (*sel_func)(struct comp_dev *dev, struct audio_stream *sink,
108115
struct comp_data {
109116
#if CONFIG_IPC_MAJOR_4
110117
struct sof_selector_ipc4_config sel_ipc4_cfg;
111-
struct ipc4_selector_coeffs_config coeffs_config;
118+
struct ipc4_selector_coeffs_config *coeffs_config;
119+
struct ipc4_selector_coeffs_config *multi_coeffs_config;
120+
size_t multi_coeffs_config_size;
112121
#endif
113122

114123
uint32_t source_period_bytes; /**< source number of period bytes */
@@ -117,6 +126,8 @@ struct comp_data {
117126
enum sof_ipc_frame sink_format; /**< sink frame format */
118127
struct sof_sel_config config; /**< component configuration data */
119128
sel_func sel_func; /**< channel selector processing function */
129+
int num_configs; /**< two or more if multiple mix blobs received */
130+
bool passthrough; /**< Use a passthrough copy function when no up/down mix */
120131
};
121132

122133
/** \brief Selector processing functions map. */

0 commit comments

Comments
 (0)