@@ -580,17 +580,34 @@ static int bluealsa_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params)
580580 debug2 ("Changing BlueALSA PCM configuration: %u ch, %u Hz -> %u ch, %u Hz" ,
581581 pcm -> ba_pcm .channels , pcm -> ba_pcm .sampling , channels , sampling );
582582
583- if (ba_dbus_pcm_select_codec (& pcm -> dbus_ctx , pcm -> ba_pcm .pcm_path ,
584- pcm -> ba_pcm .codec .name , pcm -> ba_pcm_codec_config , pcm -> ba_pcm_codec_config_len ,
583+ const char * codec_name = pcm -> ba_pcm .codec .name ;
584+ if (!ba_dbus_pcm_select_codec (& pcm -> dbus_ctx , pcm -> ba_pcm .pcm_path ,
585+ codec_name , pcm -> ba_pcm_codec_config , pcm -> ba_pcm_codec_config_len ,
585586 channels , sampling , BA_PCM_SELECT_CODEC_FLAG_NONE , & err )) {
586- pcm -> ba_pcm .channels = channels ;
587- pcm -> ba_pcm .sampling = sampling ;
588- }
589- else {
590587 SNDERR ("Couldn't change BlueALSA PCM configuration: %s" , err .message );
591588 return - dbus_error_to_errno (& err );
592589 }
593590
591+ /* After new codec selection, it is necessary to update the PCM data.
592+ * We will do it the off-line manner (without server interaction) to
593+ * speed up the process. */
594+
595+ pcm -> ba_pcm .channels = channels ;
596+ pcm -> ba_pcm .sampling = sampling ;
597+
598+ for (size_t i = 0 ; i < pcm -> ba_pcm_codecs .codecs_len ; i ++ ) {
599+ const struct ba_pcm_codec * codec = & pcm -> ba_pcm_codecs .codecs [i ];
600+ if (strcmp (codec -> name , codec_name ) == 0 ) {
601+ for (size_t j = 0 ; j < ARRAYSIZE (codec -> channel_maps ); j ++ )
602+ if (codec -> channels [j ] == channels ) {
603+ memcpy (pcm -> ba_pcm .channel_map , codec -> channel_maps [j ],
604+ sizeof (pcm -> ba_pcm .channel_map ));
605+ break ;
606+ }
607+ break ;
608+ }
609+ }
610+
594611 }
595612
596613#if BLUEALSA_HW_PARAMS_FIX
@@ -1133,6 +1150,76 @@ static int bluealsa_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd,
11331150 return - ENODEV ;
11341151}
11351152
1153+ static enum snd_pcm_chmap_position ba_channel_map_to_position (const char * tag ) {
1154+
1155+ static const struct {
1156+ const char * tag ;
1157+ enum snd_pcm_chmap_position pos ;
1158+ } mapping [] = {
1159+ { "MONO" , SND_CHMAP_MONO },
1160+ { "FL" , SND_CHMAP_FL },
1161+ { "FR" , SND_CHMAP_FR },
1162+ { "RL" , SND_CHMAP_RL },
1163+ { "RR" , SND_CHMAP_RR },
1164+ { "FC" , SND_CHMAP_FC },
1165+ { "LFE" , SND_CHMAP_LFE },
1166+ { "SL" , SND_CHMAP_SL },
1167+ { "SR" , SND_CHMAP_SR },
1168+ };
1169+
1170+ for (size_t i = 0 ; i < ARRAYSIZE (mapping ); i ++ )
1171+ if (strcmp (tag , mapping [i ].tag ) == 0 )
1172+ return mapping [i ].pos ;
1173+ return SND_CHMAP_UNKNOWN ;
1174+ }
1175+
1176+ static snd_pcm_chmap_query_t * * bluealsa_query_chmaps (snd_pcm_ioplug_t * io ) {
1177+ struct bluealsa_pcm * pcm = io -> private_data ;
1178+
1179+ const struct ba_pcm_codec * codec = & pcm -> ba_pcm .codec ;
1180+ for (size_t i = 0 ; i < pcm -> ba_pcm_codecs .codecs_len ; i ++ )
1181+ if (strcmp (pcm -> ba_pcm_codecs .codecs [i ].name , codec -> name ) == 0 ) {
1182+ codec = & pcm -> ba_pcm_codecs .codecs [i ];
1183+ break ;
1184+ }
1185+
1186+ snd_pcm_chmap_query_t * * maps ;
1187+ if ((maps = malloc (sizeof (* maps ) * (ARRAYSIZE (codec -> channel_maps ) + 1 ))) == NULL )
1188+ return NULL ;
1189+
1190+ maps [ARRAYSIZE (codec -> channel_maps )] = NULL ;
1191+ for (size_t i = 0 ; i < ARRAYSIZE (codec -> channel_maps ); i ++ ) {
1192+
1193+ unsigned int channels ;
1194+ if ((channels = codec -> channels [i ]) == 0 )
1195+ break ;
1196+
1197+ maps [i ] = malloc (sizeof (* maps [i ]) + (channels * sizeof (* maps [i ]-> map .pos )));
1198+ maps [i ]-> type = SND_CHMAP_TYPE_FIXED ;
1199+ maps [i ]-> map .channels = channels ;
1200+
1201+ for (size_t j = 0 ; j < channels ; j ++ )
1202+ maps [i ]-> map .pos [j ] = ba_channel_map_to_position (codec -> channel_maps [i ][j ]);
1203+
1204+ }
1205+
1206+ return maps ;
1207+ }
1208+
1209+ static snd_pcm_chmap_t * bluealsa_get_chmap (snd_pcm_ioplug_t * io ) {
1210+ struct bluealsa_pcm * pcm = io -> private_data ;
1211+
1212+ snd_pcm_chmap_t * map ;
1213+ if ((map = malloc (sizeof (* map ) + (io -> channels * sizeof (* map -> pos )))) == NULL )
1214+ return NULL ;
1215+
1216+ map -> channels = io -> channels ;
1217+ for (size_t i = 0 ; i < io -> channels ; i ++ )
1218+ map -> pos [i ] = ba_channel_map_to_position (pcm -> ba_pcm .channel_map [i ]);
1219+
1220+ return map ;
1221+ }
1222+
11361223static const snd_pcm_ioplug_callback_t bluealsa_callback = {
11371224 .start = bluealsa_start ,
11381225 .stop = bluealsa_stop ,
@@ -1149,6 +1236,8 @@ static const snd_pcm_ioplug_callback_t bluealsa_callback = {
11491236 .poll_descriptors_count = bluealsa_poll_descriptors_count ,
11501237 .poll_descriptors = bluealsa_poll_descriptors ,
11511238 .poll_revents = bluealsa_poll_revents ,
1239+ .query_chmaps = bluealsa_query_chmaps ,
1240+ .get_chmap = bluealsa_get_chmap ,
11521241};
11531242
11541243static int str2bdaddr (const char * str , bdaddr_t * ba ) {
0 commit comments