@@ -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
580580static 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,107 @@ 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 profile 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+ break ;
893+ }
894+ }
895+
896+ if (!found ) {
897+ comp_err (dev , "No mix coefficients found for %d to %d channels." ,
898+ source_channels , sink_channels );
899+ return - EINVAL ;
900+ }
901+ }
902+
903+ /* The pass-through copy function can be used if coefficients are a unit matrix for
904+ * 1:1 stream copy.
905+ */
906+ if (source_channels == sink_channels ) {
907+ cd -> passthrough = true;
908+ for (i = 0 ; i < sink_channels ; i ++ ) {
909+ for (j = 0 ; j < source_channels ; j ++ ) {
910+ coef = cd -> coeffs_config -> coeffs [i ][j ];
911+ if ((i == j && coef != SEL_COEF_ONE_Q10 ) || (i != j && coef != 0 )) {
912+ cd -> passthrough = false;
913+ break ;
914+ }
915+ }
916+ }
917+ } else {
918+ cd -> passthrough = false;
919+ }
920+
921+ if (cd -> passthrough )
922+ comp_info (dev , "Passthrough mode." );
923+ else
924+ comp_info (dev , "Using coefficients for %d to %d channels." ,
925+ source_channels , sink_channels );
926+
927+ return 0 ;
928+ }
929+
814930/**
815931 * \brief Prepares selector component for processing.
816932 * \param[in,out] mod Selector base module device.
@@ -825,6 +941,8 @@ static int selector_prepare(struct processing_module *mod,
825941 struct comp_dev * dev = mod -> dev ;
826942 struct comp_buffer * sinkb , * sourceb ;
827943 size_t sink_size ;
944+ unsigned int source_channels ;
945+ unsigned int sink_channels ;
828946 int ret ;
829947
830948 comp_dbg (dev , "entry" );
@@ -855,9 +973,9 @@ static int selector_prepare(struct processing_module *mod,
855973 * proper number of channels [1] for selector to actually
856974 * reduce channel count between source and sink
857975 */
858- comp_info ( dev , "source sink channel = %u %u" ,
859- audio_stream_get_channels (& sourceb -> stream ),
860- audio_stream_get_channels ( & sinkb -> stream ) );
976+ source_channels = audio_stream_get_channels ( & sourceb -> stream );
977+ sink_channels = audio_stream_get_channels (& sinkb -> stream );
978+ comp_dbg ( dev , "source sink channel = %u %u" , source_channels , sink_channels );
861979
862980 sink_size = audio_stream_get_size (& sinkb -> stream );
863981
@@ -891,7 +1009,7 @@ static int selector_prepare(struct processing_module *mod,
8911009 return - EINVAL ;
8921010 }
8931011
894- return 0 ;
1012+ return selector_find_coefficients ( mod , source_channels , sink_channels ) ;
8951013}
8961014
8971015/**
0 commit comments