@@ -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 )
@@ -618,8 +618,20 @@ static int selector_init(struct processing_module *mod)
618618 return - ENOMEM ;
619619
620620 cd -> sel_ipc4_cfg .init_payload_fmt = payload_fmt ;
621- md -> private = cd ;
622621
622+ /* Allocate space for max number of configurations. */
623+ cd -> multi_coeffs_config_size =
624+ SEL_MAX_NUM_CONFIGS * sizeof (struct ipc4_selector_coeffs_config );
625+ cd -> multi_coeffs_config = mod_zalloc (mod , cd -> multi_coeffs_config_size );
626+ if (!cd -> multi_coeffs_config ) {
627+ mod_free (mod , cd );
628+ return - ENOMEM ;
629+ }
630+
631+ /* Default configuration is set to first configuration */
632+ cd -> coeffs_config = & cd -> multi_coeffs_config [0 ];
633+
634+ md -> private = cd ;
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,13 +782,27 @@ 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+ pos != MODULE_CFG_FRAGMENT_SINGLE ) {
790+ comp_err (mod -> dev , "Failure with size %d pos %d" , data_offset_size , pos );
775791 return - EINVAL ;
792+ }
776793
777- memcpy_s (& cd -> coeffs_config , sizeof (cd -> coeffs_config ), fragment , data_offset_size );
778- return 0 ;
794+ /* The size must be N times the coefficient vectors size of one channels
795+ * up/down mix profile.
796+ */
797+ n = data_offset_size / sizeof (struct ipc4_selector_coeffs_config );
798+ if (n < 1 || data_offset_size != n * sizeof (struct ipc4_selector_coeffs_config )) {
799+ comp_err (mod -> dev , "Invalid configuration size." );
800+ return - EINVAL ;
801+ }
802+
803+ cd -> num_configs = n ;
804+ return memcpy_s (cd -> multi_coeffs_config , cd -> multi_coeffs_config_size ,
805+ fragment , data_offset_size );
779806 }
780807
781808 return - EINVAL ;
@@ -799,18 +826,124 @@ 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 Loop the array of mix coefficients sets and find a set with matching channels
855+ * in and out count.
856+ * \param[in,out] cd Selector component data.
857+ * \param[in] source_channels Number of channels in source.
858+ * \param[in] sink_channels Number of channels in sink.
859+ *
860+ * \return Boolean value set to true if match was found and cd->coeffs_config is pointed
861+ * to the coefficients.
862+ */
863+ static bool selector_config_array_search (struct comp_data * cd , int source_channels ,
864+ int sink_channels )
865+ {
866+ int i ;
867+ bool found = false;
868+
869+ for (i = 0 ; i < cd -> num_configs ; i ++ ) {
870+ if (cd -> multi_coeffs_config [i ].source_channels_count == source_channels &&
871+ cd -> multi_coeffs_config [i ].sink_channels_count == sink_channels ) {
872+ cd -> coeffs_config = & cd -> multi_coeffs_config [i ];
873+ found = true;
874+ break ;
875+ }
876+ }
877+
878+ return found ;
879+ }
880+
881+ /**
882+ * \brief Get mix coefficients set from configuration blob with multiple coefficients sets.
883+ * Also activate more efficient pass-through copy mode if the coefficients indicate 1:1
884+ * copy from source to sink.
885+ * \param[in,out] mod Selector base module device.
886+ * \param[in] source_channels Number of channels in source.
887+ * \param[in] sink_channels Number of channels in sink.
888+ *
889+ * \return Error code.
890+ */
891+ static int selector_find_coefficients (struct processing_module * mod , int source_channels ,
892+ int sink_channels )
893+ {
894+ struct comp_data * cd = module_get_private_data (mod );
895+ struct comp_dev * dev = mod -> dev ;
896+ int i , j ;
897+ int16_t coef ;
898+ bool found ;
899+
900+ /* The first config for coefficients always exists. It originates from configuration
901+ * blob for a single mix profile or from default values (1.0) from set_selector_params().
902+ */
903+ cd -> coeffs_config = cd -> multi_coeffs_config ;
904+ if (cd -> num_configs > 1 ) {
905+ found = selector_config_array_search (cd , source_channels , sink_channels );
906+ if (!found && source_channels == sink_channels ) {
907+ /* The pass-through mix is defined for the max channels count (8) */
908+ source_channels = SEL_SOURCE_CHANNELS_MAX ;
909+ sink_channels = SEL_SINK_CHANNELS_MAX ;
910+ found = selector_config_array_search (cd , source_channels , sink_channels );
911+ }
912+
913+ if (!found ) {
914+ comp_err (dev , "No mix coefficients found for %d to %d channels." ,
915+ source_channels , sink_channels );
916+ return - EINVAL ;
917+ }
918+ }
919+
920+ /* The pass-through copy function can be used if coefficients are a unit matrix for
921+ * 1:1 stream copy.
922+ */
923+ if (source_channels == sink_channels ) {
924+ cd -> passthrough = true;
925+ for (i = 0 ; i < sink_channels ; i ++ ) {
926+ for (j = 0 ; j < source_channels ; j ++ ) {
927+ coef = cd -> coeffs_config -> coeffs [i ][j ];
928+ if ((i == j && coef != SEL_COEF_ONE_Q10 ) || (i != j && coef != 0 )) {
929+ cd -> passthrough = false;
930+ break ;
931+ }
932+ }
933+ }
934+ } else {
935+ cd -> passthrough = false;
936+ }
937+
938+ if (cd -> passthrough )
939+ comp_info (dev , "Passthrough mode." );
940+ else
941+ comp_info (dev , "Using coefficients for %d to %d channels." ,
942+ source_channels , sink_channels );
943+
944+ return 0 ;
945+ }
946+
814947/**
815948 * \brief Prepares selector component for processing.
816949 * \param[in,out] mod Selector base module device.
@@ -825,6 +958,8 @@ static int selector_prepare(struct processing_module *mod,
825958 struct comp_dev * dev = mod -> dev ;
826959 struct comp_buffer * sinkb , * sourceb ;
827960 size_t sink_size ;
961+ unsigned int source_channels ;
962+ unsigned int sink_channels ;
828963 int ret ;
829964
830965 comp_dbg (dev , "entry" );
@@ -855,9 +990,9 @@ static int selector_prepare(struct processing_module *mod,
855990 * proper number of channels [1] for selector to actually
856991 * reduce channel count between source and sink
857992 */
858- comp_info ( dev , "source sink channel = %u %u" ,
859- audio_stream_get_channels (& sourceb -> stream ),
860- audio_stream_get_channels ( & sinkb -> stream ) );
993+ source_channels = audio_stream_get_channels ( & sourceb -> stream );
994+ sink_channels = audio_stream_get_channels (& sinkb -> stream );
995+ comp_dbg ( dev , "source sink channel = %u %u" , source_channels , sink_channels );
861996
862997 sink_size = audio_stream_get_size (& sinkb -> stream );
863998
@@ -891,7 +1026,7 @@ static int selector_prepare(struct processing_module *mod,
8911026 return - EINVAL ;
8921027 }
8931028
894- return 0 ;
1029+ return selector_find_coefficients ( mod , source_channels , sink_channels ) ;
8951030}
8961031
8971032/**
0 commit comments