@@ -63,7 +63,8 @@ struct userdata {
6363 pa_hook_slot * card_init_profile_slot ;
6464 pa_hook_slot * card_unlink_slot ;
6565 pa_hook_slot * profile_available_changed_slot ;
66- pa_hashmap * will_need_revert_card_map ;
66+ /** Map between cards and their previous profile. */
67+ pa_hashmap * old_profile_card_map ;
6768};
6869
6970/* When a source is created, loopback it to default sink */
@@ -146,19 +147,24 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void *
146147 return PA_HOOK_OK ;
147148}
148149
149- static void card_set_profile (struct userdata * u , pa_card * card , bool revert_to_a2dp )
150+ static void card_set_profile (struct userdata * u , pa_card * card , bool revert_to_a2dp , const char * new_profile )
150151{
151152 pa_card_profile * profile ;
152153 void * state ;
153154
155+ /* The revert_to_a2dp and profile parameter are mutually exclusive. */
156+ pa_assert (revert_to_a2dp != (!new_profile ));
157+ char * current_profile = pa_xstrdup (card -> active_profile -> name );
158+ bool switched = false;
159+
154160 /* Find available profile and activate it */
155161 PA_HASHMAP_FOREACH (profile , card -> profiles , state ) {
156162 if (profile -> available == PA_AVAILABLE_NO )
157163 continue ;
158164
159165 /* Check for correct profile based on revert_to_a2dp */
160166 if (revert_to_a2dp ) {
161- if (!pa_streq (profile -> name , "a2dp" ) && ! pa_bt_prefix_eq ( profile -> name , "a2dp_sink" ))
167+ if (!pa_streq (profile -> name , new_profile ))
162168 continue ;
163169 } else {
164170 if (!pa_streq (profile -> name , "hsp" ) && !pa_streq (profile -> name , "headset_head_unit" ))
@@ -171,48 +177,58 @@ static void card_set_profile(struct userdata *u, pa_card *card, bool revert_to_a
171177 pa_log_warn ("Could not set profile '%s'" , profile -> name );
172178 continue ;
173179 }
174-
175- /* When we are not in revert_to_a2dp phase flag this card for will_need_revert */
176- if (!revert_to_a2dp )
177- pa_hashmap_put (u -> will_need_revert_card_map , card , PA_INT_TO_PTR (1 ));
178-
180+ switched = true;
179181 break ;
180182 }
183+ /*
184+ * When we are not in revert_to_a2dp phase flag that this card will need a revert.
185+ * Save the old profile.
186+ */
187+ if (switched && !revert_to_a2dp ) {
188+ pa_hashmap_put (u -> old_profile_card_map , card , current_profile );
189+ } else {
190+ free (current_profile );
191+ }
181192}
182193
183194/* Switch profile for one card */
184195static void switch_profile (pa_card * card , bool revert_to_a2dp , void * userdata ) {
185196 struct userdata * u = userdata ;
186197 const char * s ;
198+ const char * old_profile = NULL ;
187199
188200 /* Only consider bluetooth cards */
189201 s = pa_proplist_gets (card -> proplist , PA_PROP_DEVICE_BUS );
190202 if (!s || !pa_streq (s , "bluetooth" ))
191203 return ;
192204
193205 if (revert_to_a2dp ) {
194- /* In revert_to_a2dp phase only consider cards with will_need_revert flag and remove it */
195- if (!pa_hashmap_remove ( u -> will_need_revert_card_map , card ))
196- return ;
206+ /* In revert_to_a2dp phase only consider cards with an old profile stored and remove it. */
207+ if (!( old_profile = pa_hashmap_get ( u -> old_profile_card_map , card ) ))
208+ goto fail ;
197209
198210 /* Skip card if does not have active hsp profile */
199211 if (!pa_streq (card -> active_profile -> name , "hsp" ) && !pa_streq (card -> active_profile -> name , "headset_head_unit" ))
200- return ;
212+ goto fail ;
201213
202214 /* Skip card if already has active a2dp profile */
203215 if (pa_streq (card -> active_profile -> name , "a2dp" ) || pa_strneq (card -> active_profile -> name , "a2dp_sink" , strlen ("a2dp_sink" )))
204- return ;
216+ goto fail ;
205217 } else {
206218 /* Skip card if does not have active a2dp profile */
207219 if (!pa_streq (card -> active_profile -> name , "a2dp" ) && !pa_bt_prefix_eq (card -> active_profile -> name , "a2dp_sink" ))
208- return ;
220+ goto fail ;
209221
210222 /* Skip card if already has active hsp profile */
211223 if (pa_streq (card -> active_profile -> name , "hsp" ) || pa_streq (card -> active_profile -> name , "headset_head_unit" ))
212- return ;
224+ goto fail ;
213225 }
214226
215- card_set_profile (u , card , revert_to_a2dp );
227+ card_set_profile (u , card , revert_to_a2dp , old_profile );
228+ fail :
229+ if (revert_to_a2dp ) {
230+ pa_hashmap_remove_and_free (u -> old_profile_card_map , card );
231+ }
216232}
217233
218234/* Return true if we should ignore this source output */
@@ -316,10 +332,7 @@ static pa_hook_result_t card_init_profile_hook_callback(pa_core *c, pa_card *car
316332 return PA_HOOK_OK ;
317333
318334 /* Set initial profile to hsp */
319- card_set_profile (u , card , false);
320-
321- /* Flag this card for will_need_revert */
322- pa_hashmap_put (u -> will_need_revert_card_map , card , PA_INT_TO_PTR (1 ));
335+ card_set_profile (u , card , false, NULL );
323336 return PA_HOOK_OK ;
324337}
325338
@@ -452,7 +465,7 @@ int pa__init(pa_module *m) {
452465 goto fail ;
453466 }
454467
455- u -> will_need_revert_card_map = pa_hashmap_new (pa_idxset_trivial_hash_func , pa_idxset_trivial_compare_func );
468+ u -> old_profile_card_map = pa_hashmap_new (pa_idxset_trivial_hash_func , pa_idxset_trivial_compare_func );
456469
457470 u -> source_put_slot = pa_hook_connect (& m -> core -> hooks [PA_CORE_HOOK_SOURCE_PUT ], PA_HOOK_NORMAL ,
458471 (pa_hook_cb_t ) source_put_hook_callback , u );
@@ -517,7 +530,7 @@ void pa__done(pa_module *m) {
517530 if (u -> profile_available_changed_slot )
518531 pa_hook_slot_free (u -> profile_available_changed_slot );
519532
520- pa_hashmap_free (u -> will_need_revert_card_map );
533+ pa_hashmap_free (u -> old_profile_card_map );
521534
522535 pa_xfree (u );
523536}
0 commit comments