diff --git a/spa/plugins/bluez5/backend-native.c b/spa/plugins/bluez5/backend-native.c index ccbcb2544..920dd3cf2 100644 --- a/spa/plugins/bluez5/backend-native.c +++ b/spa/plugins/bluez5/backend-native.c @@ -184,6 +184,7 @@ struct rfcomm { unsigned int clip_notify:1; unsigned int hfp_hf_3way:1; unsigned int hfp_hf_clcc:1; + unsigned int hfp_hf_in_progress:1; unsigned int chld_supported:1; enum hfp_hf_state hf_state; enum hsp_hs_state hs_state; @@ -1424,6 +1425,9 @@ static void hfp_hf_swap_calls(void *data, enum spa_bt_telephony_error *err) if (!rfcomm->chld_supported) { *err = BT_TELEPHONY_ERROR_NOT_SUPPORTED; return; + } else if (rfcomm->hfp_hf_in_progress) { + *err = BT_TELEPHONY_ERROR_IN_PROGRESS; + return; } spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { @@ -1450,20 +1454,7 @@ static void hfp_hf_swap_calls(void *data, enum spa_bt_telephony_error *err) return; } - spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { - bool changed = false; - if (call->state == CALL_STATE_ACTIVE) { - call->state = CALL_STATE_HELD; - changed = true; - } else if (call->state == CALL_STATE_HELD) { - call->state = CALL_STATE_ACTIVE; - changed = true; - } - - if (changed) - telephony_call_notify_updated_props(call); - } - + rfcomm->hfp_hf_in_progress = true; *err = BT_TELEPHONY_ERROR_NONE; } @@ -1471,7 +1462,7 @@ static void hfp_hf_release_and_answer(void *data, enum spa_bt_telephony_error *e { struct rfcomm *rfcomm = data; struct impl *backend = rfcomm->backend; - struct spa_bt_telephony_call *call, *tcall; + struct spa_bt_telephony_call *call; bool found_active = false; bool found_waiting = false; char reply[20]; @@ -1479,6 +1470,9 @@ static void hfp_hf_release_and_answer(void *data, enum spa_bt_telephony_error *e if (!rfcomm->chld_supported) { *err = BT_TELEPHONY_ERROR_NOT_SUPPORTED; return; + } else if (rfcomm->hfp_hf_in_progress) { + *err = BT_TELEPHONY_ERROR_IN_PROGRESS; + return; } spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { @@ -1501,17 +1495,7 @@ static void hfp_hf_release_and_answer(void *data, enum spa_bt_telephony_error *e return; } - spa_list_for_each_safe(call, tcall, &rfcomm->telephony_ag->call_list, link) { - if (call->state == CALL_STATE_ACTIVE) { - call->state = CALL_STATE_DISCONNECTED; - telephony_call_notify_updated_props(call); - telephony_call_destroy(call); - } else if (call->state == CALL_STATE_WAITING) { - call->state = CALL_STATE_ACTIVE; - telephony_call_notify_updated_props(call); - } - } - + rfcomm->hfp_hf_in_progress = true; *err = BT_TELEPHONY_ERROR_NONE; } @@ -1519,7 +1503,7 @@ static void hfp_hf_release_and_swap(void *data, enum spa_bt_telephony_error *err { struct rfcomm *rfcomm = data; struct impl *backend = rfcomm->backend; - struct spa_bt_telephony_call *call, *tcall; + struct spa_bt_telephony_call *call; bool found_active = false; bool found_held = false; char reply[20]; @@ -1527,6 +1511,9 @@ static void hfp_hf_release_and_swap(void *data, enum spa_bt_telephony_error *err if (!rfcomm->chld_supported) { *err = BT_TELEPHONY_ERROR_NOT_SUPPORTED; return; + } else if (rfcomm->hfp_hf_in_progress) { + *err = BT_TELEPHONY_ERROR_IN_PROGRESS; + return; } spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { @@ -1553,17 +1540,7 @@ static void hfp_hf_release_and_swap(void *data, enum spa_bt_telephony_error *err return; } - spa_list_for_each_safe(call, tcall, &rfcomm->telephony_ag->call_list, link) { - if (call->state == CALL_STATE_ACTIVE) { - call->state = CALL_STATE_DISCONNECTED; - telephony_call_notify_updated_props(call); - telephony_call_destroy(call); - } else if (call->state == CALL_STATE_HELD) { - call->state = CALL_STATE_ACTIVE; - telephony_call_notify_updated_props(call); - } - } - + rfcomm->hfp_hf_in_progress = true; *err = BT_TELEPHONY_ERROR_NONE; } @@ -1579,6 +1556,9 @@ static void hfp_hf_hold_and_answer(void *data, enum spa_bt_telephony_error *err) if (!rfcomm->chld_supported) { *err = BT_TELEPHONY_ERROR_NOT_SUPPORTED; return; + } else if (rfcomm->hfp_hf_in_progress) { + *err = BT_TELEPHONY_ERROR_IN_PROGRESS; + return; } spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { @@ -1601,20 +1581,7 @@ static void hfp_hf_hold_and_answer(void *data, enum spa_bt_telephony_error *err) return; } - spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { - bool changed = false; - if (call->state == CALL_STATE_ACTIVE) { - call->state = CALL_STATE_HELD; - changed = true; - } else if (call->state == CALL_STATE_WAITING) { - call->state = CALL_STATE_ACTIVE; - changed = true; - } - - if (changed) - telephony_call_notify_updated_props(call); - } - + rfcomm->hfp_hf_in_progress = true; *err = BT_TELEPHONY_ERROR_NONE; } @@ -1677,6 +1644,9 @@ static void hfp_hf_create_multiparty(void *data, enum spa_bt_telephony_error *er if (!rfcomm->chld_supported) { *err = BT_TELEPHONY_ERROR_NOT_SUPPORTED; return; + } else if (rfcomm->hfp_hf_in_progress) { + *err = BT_TELEPHONY_ERROR_IN_PROGRESS; + return; } spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { @@ -1703,21 +1673,7 @@ static void hfp_hf_create_multiparty(void *data, enum spa_bt_telephony_error *er return; } - spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { - bool changed = false; - if (call->state == CALL_STATE_ACTIVE) { - call->multiparty = true; - changed = true; - } else if (call->state == CALL_STATE_HELD) { - call->state = CALL_STATE_ACTIVE; - call->multiparty = true; - changed = true; - } - - if (changed) - telephony_call_notify_updated_props(call); - } - + rfcomm->hfp_hf_in_progress = true; *err = BT_TELEPHONY_ERROR_NONE; } @@ -1925,6 +1881,8 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token) if (rfcomm->hfp_hf_clcc) rfcomm_send_cmd(rfcomm, "AT+CLCC"); + else + rfcomm->hfp_hf_in_progress = false; } else if (spa_streq(rfcomm->hf_indicators[indicator], "call")) { if (value == 0) { struct spa_bt_telephony_call *call, *tcall; @@ -1948,6 +1906,8 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token) if (rfcomm->hfp_hf_clcc) rfcomm_send_cmd(rfcomm, "AT+CLCC"); + else + rfcomm->hfp_hf_in_progress = false; } else if (spa_streq(rfcomm->hf_indicators[indicator], "callheld")) { if (value == 0) { /* Reject waiting call or no held calls */ struct spa_bt_telephony_call *call, *tcall; @@ -1970,6 +1930,21 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token) } } } + } else if (value == 1) { /* Swap calls */ + struct spa_bt_telephony_call *call; + spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { + bool changed = false; + if (call->state == CALL_STATE_ACTIVE) { + call->state = CALL_STATE_HELD; + changed = true; + } else if (call->state == CALL_STATE_HELD) { + call->state = CALL_STATE_ACTIVE; + changed = true; + } + + if (changed) + telephony_call_notify_updated_props(call); + } } else if (value == 2) { /* No active calls, place waiting on hold */ struct spa_bt_telephony_call *call; spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { @@ -1986,6 +1961,8 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token) if (rfcomm->hfp_hf_clcc) rfcomm_send_cmd(rfcomm, "AT+CLCC"); + else + rfcomm->hfp_hf_in_progress = false; } } } else if (sscanf(token, "+CLIP: \"%16[^\"]\",%u", number, &type) == 2) { @@ -2001,10 +1978,21 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token) } } else if (sscanf(token, "+CCWA: \"%16[^\"]\",%u", number, &type) == 2) { struct spa_bt_telephony_call *call; + bool found = false; + spa_log_info(backend->log, "Waiting call"); - call = hfp_hf_add_call(rfcomm, rfcomm->telephony_ag, CALL_STATE_WAITING, number); - if (call == NULL) - spa_log_warn(backend->log, "failed to create waiting call"); + spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { + if (call->state == CALL_STATE_WAITING) { + spa_log_info(backend->log, "waiting call already in progress (id: %d)", call->id); + found = true; + break; + } + } + if (!found) { + call = hfp_hf_add_call(rfcomm, rfcomm->telephony_ag, CALL_STATE_WAITING, number); + if (call == NULL) + spa_log_warn(backend->log, "failed to create waiting call"); + } } else if (spa_strstartswith(token, "+CLCC: ")) { struct spa_bt_telephony_call *call; int idx; @@ -2070,6 +2058,8 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token) else if (call->id != idx) spa_log_warn(backend->log, "wrong call index: %d, expected: %d", call->id, idx); } + + rfcomm->hfp_hf_in_progress = false; } else if (spa_strstartswith(token, "OK")) { switch(rfcomm->hf_state) { case hfp_hf_brsf: diff --git a/spa/plugins/bluez5/telephony.c b/spa/plugins/bluez5/telephony.c index 4007c35ae..348a70c0a 100644 --- a/spa/plugins/bluez5/telephony.c +++ b/spa/plugins/bluez5/telephony.c @@ -228,6 +228,7 @@ static void dbus_iter_append_call_properties(DBusMessageIter *i, struct spa_bt_t #define PW_TELEPHONY_ERROR_NOT_SUPPORTED "org.freedesktop.PipeWire.Telephony.Error.NotSupported" #define PW_TELEPHONY_ERROR_INVALID_FORMAT "org.freedesktop.PipeWire.Telephony.Error.InvalidFormat" #define PW_TELEPHONY_ERROR_INVALID_STATE "org.freedesktop.PipeWire.Telephony.Error.InvalidState" +#define PW_TELEPHONY_ERROR_IN_PROGRESS "org.freedesktop.PipeWire.Telephony.Error.InProgress" static const char *telephony_error_to_dbus (enum spa_bt_telephony_error err) { @@ -240,6 +241,8 @@ static const char *telephony_error_to_dbus (enum spa_bt_telephony_error err) return PW_TELEPHONY_ERROR_INVALID_FORMAT; case BT_TELEPHONY_ERROR_INVALID_STATE: return PW_TELEPHONY_ERROR_INVALID_STATE; + case BT_TELEPHONY_ERROR_IN_PROGRESS: + return PW_TELEPHONY_ERROR_IN_PROGRESS; default: return ""; } @@ -256,6 +259,8 @@ static const char *telephony_error_to_description (enum spa_bt_telephony_error e return "Invalid phone number or tones"; case BT_TELEPHONY_ERROR_INVALID_STATE: return "The current state does not allow this method call"; + case BT_TELEPHONY_ERROR_IN_PROGRESS: + return "Command already in progress"; default: return ""; } diff --git a/spa/plugins/bluez5/telephony.h b/spa/plugins/bluez5/telephony.h index 38775976f..dfbdc73d4 100644 --- a/spa/plugins/bluez5/telephony.h +++ b/spa/plugins/bluez5/telephony.h @@ -13,6 +13,7 @@ enum spa_bt_telephony_error { BT_TELEPHONY_ERROR_NOT_SUPPORTED, BT_TELEPHONY_ERROR_INVALID_FORMAT, BT_TELEPHONY_ERROR_INVALID_STATE, + BT_TELEPHONY_ERROR_IN_PROGRESS, }; enum spa_bt_telephony_call_state {