mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-03-11 05:33:58 -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 extended_error_reporting:1;
|
||||||
unsigned int clip_notify:1;
|
unsigned int clip_notify:1;
|
||||||
unsigned int hfp_hf_3way:1;
|
unsigned int hfp_hf_3way:1;
|
||||||
|
unsigned int hfp_hf_clcc:1;
|
||||||
unsigned int chld_supported:1;
|
unsigned int chld_supported:1;
|
||||||
enum hfp_hf_state hf_state;
|
enum hfp_hf_state hf_state;
|
||||||
enum hsp_hs_state hs_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->msbc_supported_by_hfp || rfcomm->lc3_supported_by_hfp))
|
||||||
rfcomm->codec_negotiation_supported = true;
|
rfcomm->codec_negotiation_supported = true;
|
||||||
rfcomm->hfp_hf_3way = (features & SPA_BT_HFP_AG_FEATURE_3WAY) != 0;
|
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) {
|
} 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 &&
|
if (selected_codec != HFP_AUDIO_CODEC_CVSD && selected_codec != HFP_AUDIO_CODEC_MSBC &&
|
||||||
selected_codec != HFP_AUDIO_CODEC_LC3_SWB) {
|
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")) {
|
} else if (spa_streq(rfcomm->hf_indicators[indicator], "call")) {
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
struct spa_bt_telephony_call *call, *tcall;
|
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")) {
|
} else if (spa_streq(rfcomm->hf_indicators[indicator], "callheld")) {
|
||||||
if (value == 0) { /* Reject waiting call or no held calls */
|
if (value == 0) { /* Reject waiting call or no held calls */
|
||||||
struct spa_bt_telephony_call *call, *tcall;
|
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);
|
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) {
|
} 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);
|
call = hfp_hf_add_call(rfcomm, rfcomm->telephony_ag, CALL_STATE_WAITING, number);
|
||||||
if (call == NULL)
|
if (call == NULL)
|
||||||
spa_log_warn(backend->log, "failed to create waiting call");
|
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")) {
|
} else if (spa_strstartswith(token, "OK")) {
|
||||||
switch(rfcomm->hf_state) {
|
switch(rfcomm->hf_state) {
|
||||||
case hfp_hf_brsf:
|
case hfp_hf_brsf:
|
||||||
|
|
@ -3036,7 +3107,8 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
|
||||||
rfcomm->transport->path, handler);
|
rfcomm->transport->path, handler);
|
||||||
} else if (profile == SPA_BT_PROFILE_HFP_AG) {
|
} else if (profile == SPA_BT_PROFILE_HFP_AG) {
|
||||||
/* Start SLC connection */
|
/* 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_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);
|
bool has_lc3 = device_supports_codec(backend, rfcomm->device, HFP_AUDIO_CODEC_LC3_SWB);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,6 @@ struct impl {
|
||||||
struct agimpl {
|
struct agimpl {
|
||||||
struct spa_bt_telephony_ag this;
|
struct spa_bt_telephony_ag this;
|
||||||
struct spa_list link;
|
struct spa_list link;
|
||||||
int id;
|
|
||||||
char *path;
|
char *path;
|
||||||
struct spa_hook_list listener_list;
|
struct spa_hook_list listener_list;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
|
|
@ -196,7 +195,6 @@ struct agimpl {
|
||||||
|
|
||||||
struct callimpl {
|
struct callimpl {
|
||||||
struct spa_bt_telephony_call this;
|
struct spa_bt_telephony_call this;
|
||||||
int id;
|
|
||||||
char *path;
|
char *path;
|
||||||
struct spa_hook_list listener_list;
|
struct spa_hook_list listener_list;
|
||||||
void *user_data;
|
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) \
|
#define find_free_object_id(list, obj_type, link) \
|
||||||
({ \
|
({ \
|
||||||
int id = 0; \
|
int id = 1; \
|
||||||
obj_type *object; \
|
obj_type *object; \
|
||||||
spa_list_for_each(object, list, link) { \
|
spa_list_for_each(object, list, link) { \
|
||||||
if (object->id <= id) \
|
if (object->this.id <= id) \
|
||||||
id = object->id + 1; \
|
id = object->this.id + 1; \
|
||||||
} \
|
} \
|
||||||
id; \
|
id; \
|
||||||
})
|
})
|
||||||
|
|
@ -759,7 +757,7 @@ telephony_ag_new(struct spa_bt_telephony *telephony, size_t user_data_size)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
agimpl->this.telephony = telephony;
|
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_list_init(&agimpl->this.call_list);
|
||||||
spa_hook_list_init(&agimpl->listener_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,
|
.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 */
|
/* register object */
|
||||||
if (!dbus_connection_register_object_path(impl->conn, path, &vtable, agimpl)) {
|
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;
|
return NULL;
|
||||||
|
|
||||||
callimpl->this.ag = ag;
|
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_hook_list_init(&callimpl->listener_list);
|
||||||
|
|
||||||
spa_list_append(&ag->call_list, &callimpl->this.link);
|
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,
|
.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 */
|
/* register object */
|
||||||
if (!dbus_connection_register_object_path(impl->conn, path, &vtable, callimpl)) {
|
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_ag {
|
||||||
struct spa_bt_telephony *telephony;
|
struct spa_bt_telephony *telephony;
|
||||||
struct spa_list call_list;
|
struct spa_list call_list;
|
||||||
|
|
||||||
|
int id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct spa_bt_telephony_call {
|
struct spa_bt_telephony_call {
|
||||||
struct spa_bt_telephony_ag *ag;
|
struct spa_bt_telephony_ag *ag;
|
||||||
struct spa_list link; /* link in ag->call_list */
|
struct spa_list link; /* link in ag->call_list */
|
||||||
|
|
||||||
|
int id;
|
||||||
|
|
||||||
/* D-Bus properties */
|
/* D-Bus properties */
|
||||||
char *line_identification;
|
char *line_identification;
|
||||||
char *incoming_line;
|
char *incoming_line;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue