mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
bluez5: backend-native: add CLCC support
Start call id at 1 as for the index calls in HFP, and move this id to spa_bt_telephony_[ag|call] so they can be used by CLCC to retrieve the related call. if enhanced call status is supported, send AT+CLCC on +CIEV events to get the calls information.
This commit is contained in:
parent
a8363ff92b
commit
f5e08677a2
3 changed files with 84 additions and 10 deletions
|
|
@ -183,6 +183,7 @@ struct rfcomm {
|
|||
unsigned int extended_error_reporting:1;
|
||||
unsigned int clip_notify:1;
|
||||
unsigned int hfp_hf_3way:1;
|
||||
unsigned int hfp_hf_clcc:1;
|
||||
unsigned int chld_supported:1;
|
||||
enum hfp_hf_state hf_state;
|
||||
enum hsp_hs_state hs_state;
|
||||
|
|
@ -1774,6 +1775,7 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
|
|||
(rfcomm->msbc_supported_by_hfp || rfcomm->lc3_supported_by_hfp))
|
||||
rfcomm->codec_negotiation_supported = true;
|
||||
rfcomm->hfp_hf_3way = (features & SPA_BT_HFP_AG_FEATURE_3WAY) != 0;
|
||||
rfcomm->hfp_hf_clcc = (features & SPA_BT_HFP_AG_FEATURE_ENHANCED_CALL_STATUS) != 0;
|
||||
} else if (sscanf(token, "+BCS:%u", &selected_codec) == 1 && rfcomm->codec_negotiation_supported) {
|
||||
if (selected_codec != HFP_AUDIO_CODEC_CVSD && selected_codec != HFP_AUDIO_CODEC_MSBC &&
|
||||
selected_codec != HFP_AUDIO_CODEC_LC3_SWB) {
|
||||
|
|
@ -1920,6 +1922,9 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rfcomm->hfp_hf_clcc)
|
||||
rfcomm_send_cmd(rfcomm, "AT+CLCC");
|
||||
} else if (spa_streq(rfcomm->hf_indicators[indicator], "call")) {
|
||||
if (value == 0) {
|
||||
struct spa_bt_telephony_call *call, *tcall;
|
||||
|
|
@ -1941,6 +1946,9 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rfcomm->hfp_hf_clcc)
|
||||
rfcomm_send_cmd(rfcomm, "AT+CLCC");
|
||||
} 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;
|
||||
|
|
@ -1976,6 +1984,9 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
|
|||
telephony_call_notify_updated_props(call);
|
||||
}
|
||||
}
|
||||
|
||||
if (rfcomm->hfp_hf_clcc)
|
||||
rfcomm_send_cmd(rfcomm, "AT+CLCC");
|
||||
}
|
||||
}
|
||||
} else if (sscanf(token, "+CLIP: \"%16[^\"]\",%u", number, &type) == 2) {
|
||||
|
|
@ -1995,6 +2006,66 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
|
|||
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;
|
||||
unsigned int status, mpty;
|
||||
bool found = false;
|
||||
|
||||
token[strcspn(token, "\r")] = 0;
|
||||
token[strcspn(token, "\n")] = 0;
|
||||
token += strlen("+CLCC: ");
|
||||
token[strcspn(token, ",")] = 0;
|
||||
idx = atoi(token);
|
||||
token += strcspn(token, "\0") + 1;
|
||||
// Skip direction
|
||||
token[strcspn(token, ",")] = 0;
|
||||
token += strcspn(token, "\0") + 1;
|
||||
token[strcspn(token, ",")] = 0;
|
||||
status = atoi(token);
|
||||
token += strcspn(token, "\0") + 1;
|
||||
// Skip mode
|
||||
token[strcspn(token, ",")] = 0;
|
||||
token += strcspn(token, "\0") + 1;
|
||||
token[strcspn(token, ",")] = 0;
|
||||
mpty = atoi(token);
|
||||
token += strcspn(token, "\0") + 1;
|
||||
if (strlen(token) > 0) {
|
||||
if (sscanf(token, "\"%16[^\"]\",%u", number, &type) != 2) {
|
||||
spa_log_warn(backend->log, "Failed to parse number: %s", token);
|
||||
number[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) {
|
||||
if (call->id == idx) {
|
||||
bool changed = false;
|
||||
|
||||
found = true;
|
||||
|
||||
if (call->state != status) {
|
||||
call->state =status;
|
||||
changed = true;
|
||||
}
|
||||
if (call->multiparty != mpty) {
|
||||
call->multiparty = mpty;
|
||||
changed = true;
|
||||
}
|
||||
if (strlen(number) && !spa_streq(number, call->line_identification)) {
|
||||
if (call->line_identification)
|
||||
free(call->line_identification);
|
||||
call->line_identification = strdup(number);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
telephony_call_notify_updated_props(call);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
spa_log_warn(backend->log, "unknown call index: %u", idx);
|
||||
}
|
||||
} else if (spa_strstartswith(token, "OK")) {
|
||||
switch(rfcomm->hf_state) {
|
||||
case hfp_hf_brsf:
|
||||
|
|
@ -3036,7 +3107,8 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
|
|||
rfcomm->transport->path, handler);
|
||||
} else if (profile == SPA_BT_PROFILE_HFP_AG) {
|
||||
/* Start SLC connection */
|
||||
unsigned int hf_features = SPA_BT_HFP_HF_FEATURE_CLIP | SPA_BT_HFP_HF_FEATURE_3WAY;
|
||||
unsigned int hf_features = SPA_BT_HFP_HF_FEATURE_CLIP | SPA_BT_HFP_HF_FEATURE_3WAY |
|
||||
SPA_BT_HFP_HF_FEATURE_ENHANCED_CALL_STATUS;
|
||||
bool has_msbc = device_supports_codec(backend, rfcomm->device, HFP_AUDIO_CODEC_MSBC);
|
||||
bool has_lc3 = device_supports_codec(backend, rfcomm->device, HFP_AUDIO_CODEC_LC3_SWB);
|
||||
|
||||
|
|
|
|||
|
|
@ -185,7 +185,6 @@ struct impl {
|
|||
struct agimpl {
|
||||
struct spa_bt_telephony_ag this;
|
||||
struct spa_list link;
|
||||
int id;
|
||||
char *path;
|
||||
struct spa_hook_list listener_list;
|
||||
void *user_data;
|
||||
|
|
@ -196,7 +195,6 @@ struct agimpl {
|
|||
|
||||
struct callimpl {
|
||||
struct spa_bt_telephony_call this;
|
||||
int id;
|
||||
char *path;
|
||||
struct spa_hook_list listener_list;
|
||||
void *user_data;
|
||||
|
|
@ -266,11 +264,11 @@ static const char *telephony_error_to_description (enum spa_bt_telephony_error e
|
|||
|
||||
#define find_free_object_id(list, obj_type, link) \
|
||||
({ \
|
||||
int id = 0; \
|
||||
int id = 1; \
|
||||
obj_type *object; \
|
||||
spa_list_for_each(object, list, link) { \
|
||||
if (object->id <= id) \
|
||||
id = object->id + 1; \
|
||||
if (object->this.id <= id) \
|
||||
id = object->this.id + 1; \
|
||||
} \
|
||||
id; \
|
||||
})
|
||||
|
|
@ -759,7 +757,7 @@ telephony_ag_new(struct spa_bt_telephony *telephony, size_t user_data_size)
|
|||
return NULL;
|
||||
|
||||
agimpl->this.telephony = telephony;
|
||||
agimpl->id = find_free_object_id(&impl->ag_list, struct agimpl, link);
|
||||
agimpl->this.id = find_free_object_id(&impl->ag_list, struct agimpl, link);
|
||||
spa_list_init(&agimpl->this.call_list);
|
||||
spa_hook_list_init(&agimpl->listener_list);
|
||||
|
||||
|
|
@ -803,7 +801,7 @@ int telephony_ag_register(struct spa_bt_telephony_ag *ag)
|
|||
.message_function = ag_handler,
|
||||
};
|
||||
|
||||
path = spa_aprintf (PW_TELEPHONY_OBJECT_PATH "/ag%d", agimpl->id);
|
||||
path = spa_aprintf (PW_TELEPHONY_OBJECT_PATH "/ag%d", agimpl->this.id);
|
||||
|
||||
/* register object */
|
||||
if (!dbus_connection_register_object_path(impl->conn, path, &vtable, agimpl)) {
|
||||
|
|
@ -933,7 +931,7 @@ telephony_call_new(struct spa_bt_telephony_ag *ag, size_t user_data_size)
|
|||
return NULL;
|
||||
|
||||
callimpl->this.ag = ag;
|
||||
callimpl->id = find_free_object_id(&ag->call_list, struct callimpl, this.link);
|
||||
callimpl->this.id = find_free_object_id(&ag->call_list, struct callimpl, this.link);
|
||||
spa_hook_list_init(&callimpl->listener_list);
|
||||
|
||||
spa_list_append(&ag->call_list, &callimpl->this.link);
|
||||
|
|
@ -1262,7 +1260,7 @@ int telephony_call_register(struct spa_bt_telephony_call *call)
|
|||
.message_function = call_handler,
|
||||
};
|
||||
|
||||
path = spa_aprintf ("%s/call%d", agimpl->path, callimpl->id);
|
||||
path = spa_aprintf ("%s/call%d", agimpl->path, callimpl->this.id);
|
||||
|
||||
/* register object */
|
||||
if (!dbus_connection_register_object_path(impl->conn, path, &vtable, callimpl)) {
|
||||
|
|
|
|||
|
|
@ -32,12 +32,16 @@ struct spa_bt_telephony {
|
|||
struct spa_bt_telephony_ag {
|
||||
struct spa_bt_telephony *telephony;
|
||||
struct spa_list call_list;
|
||||
|
||||
int id;
|
||||
};
|
||||
|
||||
struct spa_bt_telephony_call {
|
||||
struct spa_bt_telephony_ag *ag;
|
||||
struct spa_list link; /* link in ag->call_list */
|
||||
|
||||
int id;
|
||||
|
||||
/* D-Bus properties */
|
||||
char *line_identification;
|
||||
char *incoming_line;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue