bluez5: hfp-hf: Remove disconnected calls from call list

After AT+CLCC command completion, the calls which has not been listed
should be removed.
This list the calls returned by AT+CLCC to be able to find the ones which
has not been listed but still in the call_list.
This commit is contained in:
Frédéric Danis 2025-06-11 09:32:07 +02:00
parent 931b6d9ad8
commit 2cb678edb3

View file

@ -145,7 +145,8 @@ enum hfp_hf_state {
hfp_hf_nrec,
hfp_hf_clcc,
hfp_hf_vgs,
hfp_hf_vgm
hfp_hf_done,
hfp_hf_clcc_update
};
enum hsp_hs_state {
@ -175,6 +176,11 @@ struct codec_item {
const struct media_codec *codec;
};
struct updated_call {
struct spa_list link;
int id;
};
struct rfcomm {
struct spa_list link;
struct spa_source source;
@ -215,6 +221,7 @@ struct rfcomm {
char *hf_indicators[MAX_HF_INDICATORS];
struct spa_bt_telephony_ag *telephony_ag;
struct spa_list hfp_hf_commands;
struct spa_list updated_call_list;
#endif
};
@ -392,6 +399,13 @@ static void volume_sync_stop_timer(struct rfcomm *rfcomm);
static void rfcomm_free(struct rfcomm *rfcomm)
{
struct updated_call *updated_call;
spa_list_consume(updated_call, &rfcomm->updated_call_list, link) {
spa_list_remove(&updated_call->link);
free(updated_call);
}
codec_switch_stop_timer(rfcomm);
if (rfcomm->telephony_ag) {
telephony_ag_destroy(rfcomm->telephony_ag);
@ -457,6 +471,9 @@ static ssize_t rfcomm_send_cmd(struct rfcomm *rfcomm, const char *format, ...)
return 0;
}
if (rfcomm->hf_state == hfp_hf_done && spa_streq(message, "AT+CLCC"))
rfcomm->hf_state = hfp_hf_clcc_update;
spa_log_debug(backend->log, "RFCOMM >> %s", message);
/*
@ -2064,6 +2081,34 @@ static const struct spa_bt_telephony_ag_callbacks telephony_ag_callbacks = {
.set_microphone_volume = hfp_hf_set_microphone_volume,
};
static void hfp_hf_remove_disconnected_calls(struct rfcomm *rfcomm)
{
struct spa_bt_telephony_call *call, *call_tmp;
struct updated_call *updated_call;
bool found;
spa_list_for_each_safe(call, call_tmp, &rfcomm->telephony_ag->call_list, link) {
found = false;
spa_list_for_each(updated_call, &rfcomm->updated_call_list, link) {
if (call->id == updated_call->id) {
found = true;
break;
}
}
if (!found) {
call->state = CALL_STATE_DISCONNECTED;
telephony_call_notify_updated_props(call);
telephony_call_destroy(call);
}
}
spa_list_consume(updated_call, &rfcomm->updated_call_list, link) {
spa_list_remove(&updated_call->link);
free(updated_call);
}
}
static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
{
struct impl *backend = rfcomm->backend;
@ -2389,6 +2434,11 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
}
if (SPA_LIKELY (parsed)) {
struct updated_call *updated_call;
updated_call = calloc(1, sizeof(struct updated_call));
updated_call->id = idx;
spa_list_append(&rfcomm->updated_call_list, &updated_call->link);
spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) {
if (call->id == idx) {
bool changed = false;
@ -2430,17 +2480,6 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
rfcomm->hfp_hf_in_progress = false;
} else if (spa_strstartswith(token, "OK") || spa_strstartswith(token, "ERROR") ||
spa_strstartswith(token, "+CME ERROR:")) {
rfcomm->hfp_hf_cmd_in_progress = false;
if (!spa_list_is_empty(&rfcomm->hfp_hf_commands)) {
struct rfcomm_cmd *cmd;
cmd = spa_list_first(&rfcomm->hfp_hf_commands, struct rfcomm_cmd, link);
spa_list_remove(&cmd->link);
spa_log_debug(backend->log, "Sending postponed command: %s", cmd->cmd);
rfcomm_send_cmd(rfcomm, "%s", cmd->cmd);
free(cmd->cmd);
free(cmd);
}
if (spa_strstartswith(token, "OK")) {
switch(rfcomm->hf_state) {
case hfp_hf_brsf:
@ -2539,17 +2578,35 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
/* Report volume on SLC establishment */
SPA_FALLTHROUGH;
case hfp_hf_clcc:
if (rfcomm->hf_state == hfp_hf_clcc) {
hfp_hf_remove_disconnected_calls(rfcomm);
}
rfcomm_send_volume_cmd(rfcomm, SPA_BT_VOLUME_ID_RX);
rfcomm->hf_state = hfp_hf_vgs;
break;
case hfp_hf_vgs:
rfcomm_send_volume_cmd(rfcomm, SPA_BT_VOLUME_ID_TX);
rfcomm->hf_state = hfp_hf_vgm;
rfcomm->hf_state = hfp_hf_done;
break;
case hfp_hf_clcc_update:
hfp_hf_remove_disconnected_calls(rfcomm);
rfcomm->hf_state = hfp_hf_done;
break;
default:
break;
}
}
rfcomm->hfp_hf_cmd_in_progress = false;
if (!spa_list_is_empty(&rfcomm->hfp_hf_commands)) {
struct rfcomm_cmd *cmd;
cmd = spa_list_first(&rfcomm->hfp_hf_commands, struct rfcomm_cmd, link);
spa_list_remove(&cmd->link);
spa_log_debug(backend->log, "Sending postponed command: %s", cmd->cmd);
rfcomm_send_cmd(rfcomm, "%s", cmd->cmd);
free(cmd->cmd);
free(cmd);
}
}
return true;
@ -3492,6 +3549,7 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
rfcomm->source.mask = SPA_IO_IN;
rfcomm->source.rmask = 0;
spa_list_init(&rfcomm->hfp_hf_commands);
spa_list_init(&rfcomm->updated_call_list);
/* By default all indicators are enabled */
rfcomm->cind_enabled_indicators = 0xFFFFFFFF;
memset(rfcomm->hf_indicators, 0, sizeof rfcomm->hf_indicators);