mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
bluez5: telephony: report transport codec & state on D-Bus
This is useful for implementations that do hardware offloading of the SCO audio channel and need to communicate state information to the hardware (at least).
This commit is contained in:
parent
dc5b85fe57
commit
63e1c48c8b
3 changed files with 252 additions and 34 deletions
|
|
@ -212,14 +212,25 @@ static void transport_destroy(void *data)
|
|||
rfcomm->transport = NULL;
|
||||
}
|
||||
|
||||
static void transport_state_changed (void *data, enum spa_bt_transport_state old,
|
||||
enum spa_bt_transport_state state)
|
||||
{
|
||||
struct rfcomm *rfcomm = data;
|
||||
if (rfcomm->telephony_ag) {
|
||||
rfcomm->telephony_ag->transport.state = state;
|
||||
telephony_ag_transport_notify_updated_props(rfcomm->telephony_ag);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct spa_bt_transport_events transport_events = {
|
||||
SPA_VERSION_BT_TRANSPORT_EVENTS,
|
||||
.destroy = transport_destroy,
|
||||
.state_changed = transport_state_changed,
|
||||
};
|
||||
|
||||
static const struct spa_bt_transport_implementation sco_transport_impl;
|
||||
|
||||
static int rfcomm_new_transport(struct rfcomm *rfcomm)
|
||||
static int rfcomm_new_transport(struct rfcomm *rfcomm, int codec)
|
||||
{
|
||||
struct impl *backend = rfcomm->backend;
|
||||
struct spa_bt_transport *t = NULL;
|
||||
|
|
@ -248,7 +259,7 @@ static int rfcomm_new_transport(struct rfcomm *rfcomm)
|
|||
t->backend = &backend->this;
|
||||
t->n_channels = 1;
|
||||
t->channels[0] = SPA_AUDIO_CHANNEL_MONO;
|
||||
t->codec = HFP_AUDIO_CODEC_CVSD;
|
||||
t->codec = codec;
|
||||
|
||||
td = t->user_data;
|
||||
td->rfcomm = rfcomm;
|
||||
|
|
@ -271,6 +282,12 @@ static int rfcomm_new_transport(struct rfcomm *rfcomm)
|
|||
|
||||
spa_bt_transport_add_listener(t, &rfcomm->transport_listener, &transport_events, rfcomm);
|
||||
|
||||
if (rfcomm->telephony_ag) {
|
||||
rfcomm->telephony_ag->transport.codec = codec;
|
||||
rfcomm->telephony_ag->transport.state = SPA_BT_TRANSPORT_STATE_IDLE;
|
||||
telephony_ag_transport_notify_updated_props(rfcomm->telephony_ag);
|
||||
}
|
||||
|
||||
rfcomm->transport = t;
|
||||
return 0;
|
||||
|
||||
|
|
@ -939,10 +956,9 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
|
|||
rfcomm_send_reply(rfcomm, "+BCS: 2");
|
||||
codec_switch_start_timer(rfcomm, HFP_CODEC_SWITCH_INITIAL_TIMEOUT_MSEC);
|
||||
} else {
|
||||
if (rfcomm_new_transport(rfcomm) < 0) {
|
||||
if (rfcomm_new_transport(rfcomm, HFP_AUDIO_CODEC_CVSD) < 0) {
|
||||
// TODO: We should manage the missing transport
|
||||
} else {
|
||||
rfcomm->transport->codec = HFP_AUDIO_CODEC_CVSD;
|
||||
spa_bt_device_connect_profile(rfcomm->device, rfcomm->profile);
|
||||
rfcomm_emit_volume_changed(rfcomm, -1, SPA_BT_VOLUME_INVALID);
|
||||
}
|
||||
|
|
@ -981,14 +997,13 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf)
|
|||
spa_log_debug(backend->log, "RFCOMM selected_codec = %i", selected_codec);
|
||||
|
||||
/* Recreate transport, since previous connection may now be invalid */
|
||||
if (rfcomm_new_transport(rfcomm) < 0) {
|
||||
if (rfcomm_new_transport(rfcomm, selected_codec) < 0) {
|
||||
// TODO: We should manage the missing transport
|
||||
rfcomm_send_error(rfcomm, CMEE_AG_FAILURE);
|
||||
if (was_switching_codec)
|
||||
spa_bt_device_emit_codec_switched(rfcomm->device, -ENOMEM);
|
||||
return true;
|
||||
}
|
||||
rfcomm->transport->codec = selected_codec;
|
||||
spa_bt_device_connect_profile(rfcomm->device, rfcomm->profile);
|
||||
rfcomm_emit_volume_changed(rfcomm, -1, SPA_BT_VOLUME_INVALID);
|
||||
|
||||
|
|
@ -1745,10 +1760,9 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
|
|||
rfcomm->hf_state = hfp_hf_bcs;
|
||||
|
||||
if (!rfcomm->transport || (rfcomm->transport->codec != selected_codec) ) {
|
||||
if (rfcomm_new_transport(rfcomm) < 0) {
|
||||
if (rfcomm_new_transport(rfcomm, selected_codec) < 0) {
|
||||
// TODO: We should manage the missing transport
|
||||
} else {
|
||||
rfcomm->transport->codec = selected_codec;
|
||||
spa_bt_device_connect_profile(rfcomm->device, rfcomm->profile);
|
||||
}
|
||||
}
|
||||
|
|
@ -2116,10 +2130,9 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
|
|||
rfcomm->slc_configured = true;
|
||||
|
||||
if (!rfcomm->codec_negotiation_supported) {
|
||||
if (rfcomm_new_transport(rfcomm) < 0) {
|
||||
if (rfcomm_new_transport(rfcomm, HFP_AUDIO_CODEC_CVSD) < 0) {
|
||||
// TODO: We should manage the missing transport
|
||||
} else {
|
||||
rfcomm->transport->codec = HFP_AUDIO_CODEC_CVSD;
|
||||
spa_bt_device_connect_profile(rfcomm->device, rfcomm->profile);
|
||||
}
|
||||
}
|
||||
|
|
@ -2127,6 +2140,10 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
|
|||
rfcomm->telephony_ag = telephony_ag_new(backend->telephony, sizeof(struct spa_hook));
|
||||
telephony_ag_add_listener(rfcomm->telephony_ag, telephony_ag_get_user_data(rfcomm->telephony_ag),
|
||||
&telephony_ag_events, rfcomm);
|
||||
if (rfcomm->transport) {
|
||||
rfcomm->telephony_ag->transport.codec = rfcomm->transport->codec;
|
||||
rfcomm->telephony_ag->transport.state = rfcomm->transport->state;
|
||||
}
|
||||
telephony_ag_register(rfcomm->telephony_ag);
|
||||
|
||||
/* Report volume on SLC establishment */
|
||||
|
|
@ -2909,8 +2926,7 @@ static void codec_switch_timer_event(struct spa_source *source)
|
|||
/* Failure, try falling back to CVSD. */
|
||||
rfcomm->hfp_ag_initial_codec_setup = HFP_AG_INITIAL_CODEC_SETUP_NONE;
|
||||
if (rfcomm->transport == NULL) {
|
||||
if (rfcomm_new_transport(rfcomm) == 0) {
|
||||
rfcomm->transport->codec = HFP_AUDIO_CODEC_CVSD;
|
||||
if (rfcomm_new_transport(rfcomm, HFP_AUDIO_CODEC_CVSD) == 0) {
|
||||
spa_bt_device_connect_profile(rfcomm->device, rfcomm->profile);
|
||||
}
|
||||
}
|
||||
|
|
@ -3085,10 +3101,9 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
|
|||
spa_list_append(&backend->rfcomm_list, &rfcomm->link);
|
||||
|
||||
if (profile == SPA_BT_PROFILE_HSP_HS || profile == SPA_BT_PROFILE_HSP_AG) {
|
||||
if (rfcomm_new_transport(rfcomm) < 0)
|
||||
if (rfcomm_new_transport(rfcomm, HFP_AUDIO_CODEC_CVSD) < 0)
|
||||
goto fail_need_memory;
|
||||
|
||||
rfcomm->transport->codec = HFP_AUDIO_CODEC_CVSD;
|
||||
rfcomm->has_volume = rfcomm_volume_enabled(rfcomm);
|
||||
|
||||
if (profile == SPA_BT_PROFILE_HSP_AG) {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#define PW_TELEPHONY_OBJECT_PATH "/org/freedesktop/PipeWire/Telephony"
|
||||
|
||||
#define PW_TELEPHONY_AG_IFACE "org.freedesktop.PipeWire.Telephony.AudioGateway1"
|
||||
#define PW_TELEPHONY_AG_TRANSPORT_IFACE "org.freedesktop.PipeWire.Telephony.AudioGatewayTransport1"
|
||||
#define PW_TELEPHONY_CALL_IFACE "org.freedesktop.PipeWire.Telephony.Call1"
|
||||
|
||||
#define OFONO_MANAGER_IFACE "org.ofono.Manager"
|
||||
|
|
@ -114,6 +115,10 @@
|
|||
" <interface name='" PW_TELEPHONY_AG_IFACE "'>" \
|
||||
PW_TELEPHONY_AG_COMMON_INTROSPECT_XML \
|
||||
" </interface>" \
|
||||
" <interface name='" PW_TELEPHONY_AG_TRANSPORT_IFACE "'>" \
|
||||
" <property name='State' type='s' access='read'/>" \
|
||||
" <property name='Codec' type='y' access='read'/>" \
|
||||
" </interface>" \
|
||||
" <interface name='" OFONO_VOICE_CALL_MANAGER_IFACE "'>" \
|
||||
PW_TELEPHONY_AG_COMMON_INTROSPECT_XML \
|
||||
" <method name='GetCalls'>" \
|
||||
|
|
@ -128,6 +133,7 @@
|
|||
" </signal>" \
|
||||
" </interface>" \
|
||||
DBUS_OBJECT_MANAGER_IFACE_INTROSPECT_XML \
|
||||
DBUS_PROPERTIES_IFACE_INTROSPECT_XML \
|
||||
DBUS_INTROSPECTABLE_IFACE_INTROSPECT_XML \
|
||||
"</node>"
|
||||
|
||||
|
|
@ -190,6 +196,10 @@ struct agimpl {
|
|||
|
||||
bool dial_in_progress;
|
||||
struct callimpl *dial_return;
|
||||
|
||||
struct {
|
||||
struct spa_bt_telephony_ag_transport transport;
|
||||
} prev;
|
||||
};
|
||||
|
||||
struct callimpl {
|
||||
|
|
@ -222,6 +232,7 @@ struct callimpl {
|
|||
#define call_emit_answer(s,e) call_emit(s,answer,0,e)
|
||||
#define call_emit_hangup(s,e) call_emit(s,hangup,0,e)
|
||||
|
||||
static void dbus_iter_append_ag_interfaces(DBusMessageIter *i, struct spa_bt_telephony_ag *ag);
|
||||
static void dbus_iter_append_call_properties(DBusMessageIter *i, struct spa_bt_telephony_call *call, bool all);
|
||||
|
||||
#define PW_TELEPHONY_ERROR_FAILED "org.freedesktop.PipeWire.Telephony.Error.Failed"
|
||||
|
|
@ -292,8 +303,7 @@ static DBusMessage *manager_get_managed_objects(struct impl *impl, DBusMessage *
|
|||
{
|
||||
struct agimpl *agimpl;
|
||||
spa_autoptr(DBusMessage) r = NULL;
|
||||
DBusMessageIter iter, array1, entry1, array2, entry2, props_dict;
|
||||
const char *interface = PW_TELEPHONY_AG_IFACE;
|
||||
DBusMessageIter iter, array1, entry1, props_dict;
|
||||
|
||||
if ((r = dbus_message_new_method_return(m)) == NULL)
|
||||
return NULL;
|
||||
|
|
@ -305,18 +315,12 @@ static DBusMessage *manager_get_managed_objects(struct impl *impl, DBusMessage *
|
|||
spa_list_for_each (agimpl, &impl->ag_list, link) {
|
||||
if (agimpl->path) {
|
||||
dbus_message_iter_open_container(&array1, DBUS_TYPE_DICT_ENTRY, NULL, &entry1);
|
||||
dbus_message_iter_append_basic(&entry1, DBUS_TYPE_OBJECT_PATH, &agimpl->path);
|
||||
if (ofono_compat) {
|
||||
dbus_message_iter_append_basic(&entry1, DBUS_TYPE_OBJECT_PATH, &agimpl->path);
|
||||
dbus_message_iter_open_container(&entry1, DBUS_TYPE_ARRAY, "{sv}", &props_dict);
|
||||
dbus_message_iter_close_container(&entry1, &props_dict);
|
||||
} else {
|
||||
dbus_message_iter_open_container(&entry1, DBUS_TYPE_ARRAY, "{sa{sv}}", &array2);
|
||||
dbus_message_iter_open_container(&array2, DBUS_TYPE_DICT_ENTRY, NULL, &entry2);
|
||||
dbus_message_iter_append_basic(&entry2, DBUS_TYPE_STRING, &interface);
|
||||
dbus_message_iter_open_container(&entry2, DBUS_TYPE_ARRAY, "{sv}", &props_dict);
|
||||
dbus_message_iter_close_container(&entry2, &props_dict);
|
||||
dbus_message_iter_close_container(&array2, &entry2);
|
||||
dbus_message_iter_close_container(&entry1, &array2);
|
||||
dbus_iter_append_ag_interfaces(&entry1, &agimpl->this);
|
||||
}
|
||||
dbus_message_iter_close_container(&array1, &entry1);
|
||||
}
|
||||
|
|
@ -466,6 +470,90 @@ void telephony_free(struct spa_bt_telephony *telephony)
|
|||
free(impl);
|
||||
}
|
||||
|
||||
static void telephony_ag_transport_commit_properties(struct spa_bt_telephony_ag *ag)
|
||||
{
|
||||
struct agimpl *agimpl = SPA_CONTAINER_OF(ag, struct agimpl, this);
|
||||
agimpl->prev.transport = ag->transport;
|
||||
}
|
||||
|
||||
static const char * const * transport_state_to_string(int state)
|
||||
{
|
||||
static const char * const state_str[] = {
|
||||
"error",
|
||||
"idle",
|
||||
"pending",
|
||||
"active",
|
||||
};
|
||||
if (state < -1 || state > 2)
|
||||
state = -1;
|
||||
return &state_str[state + 1];
|
||||
}
|
||||
|
||||
static bool
|
||||
dbus_iter_append_ag_transport_properties(DBusMessageIter *i, struct spa_bt_telephony_ag *ag, bool all)
|
||||
{
|
||||
struct agimpl *agimpl = SPA_CONTAINER_OF(ag, struct agimpl, this);
|
||||
DBusMessageIter dict, entry, variant;
|
||||
bool changed = false;
|
||||
|
||||
dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "{sv}", &dict);
|
||||
|
||||
if (all || ag->transport.codec != agimpl->prev.transport.codec) {
|
||||
dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
|
||||
const char *name = "Codec";
|
||||
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name);
|
||||
dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
|
||||
DBUS_TYPE_BYTE_AS_STRING,
|
||||
&variant);
|
||||
dbus_message_iter_append_basic(&variant, DBUS_TYPE_BYTE, &ag->transport.codec);
|
||||
dbus_message_iter_close_container(&entry, &variant);
|
||||
dbus_message_iter_close_container(&dict, &entry);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (all || ag->transport.state != agimpl->prev.transport.state) {
|
||||
dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
|
||||
const char *name = "State";
|
||||
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name);
|
||||
dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
|
||||
DBUS_TYPE_STRING_AS_STRING,
|
||||
&variant);
|
||||
dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING,
|
||||
transport_state_to_string(ag->transport.state));
|
||||
dbus_message_iter_close_container(&entry, &variant);
|
||||
dbus_message_iter_close_container(&dict, &entry);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(i, &dict);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_iter_append_ag_interfaces(DBusMessageIter *i, struct spa_bt_telephony_ag *ag)
|
||||
{
|
||||
struct agimpl *agimpl = SPA_CONTAINER_OF(ag, struct agimpl, this);
|
||||
DBusMessageIter entry, dict, props_dict;
|
||||
|
||||
dbus_message_iter_append_basic(i, DBUS_TYPE_OBJECT_PATH, &agimpl->path);
|
||||
dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "{sa{sv}}", &dict);
|
||||
|
||||
const char *interface = PW_TELEPHONY_AG_IFACE;
|
||||
dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
|
||||
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &interface);
|
||||
dbus_message_iter_open_container(&entry, DBUS_TYPE_ARRAY, "{sv}", &props_dict);
|
||||
dbus_message_iter_close_container(&entry, &props_dict);
|
||||
dbus_message_iter_close_container(&dict, &entry);
|
||||
|
||||
const char *interface2 = PW_TELEPHONY_AG_TRANSPORT_IFACE;
|
||||
dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
|
||||
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &interface2);
|
||||
dbus_iter_append_ag_transport_properties(&entry, ag, true);
|
||||
dbus_message_iter_close_container(&dict, &entry);
|
||||
|
||||
dbus_message_iter_close_container(i, &dict);
|
||||
}
|
||||
|
||||
static DBusMessage *ag_introspect(struct agimpl *agimpl, DBusMessage *m)
|
||||
{
|
||||
const char *xml = PW_TELEPHONY_AG_INTROSPECT_XML;
|
||||
|
|
@ -511,6 +599,80 @@ static DBusMessage *ag_get_managed_objects(struct agimpl *agimpl, DBusMessage *m
|
|||
return spa_steal_ptr(r);
|
||||
}
|
||||
|
||||
static DBusMessage *ag_properties_get(struct agimpl *agimpl, DBusMessage *m)
|
||||
{
|
||||
const char *iface, *name;
|
||||
DBusMessage *r;
|
||||
DBusMessageIter i, v;
|
||||
|
||||
if (!dbus_message_get_args(m, NULL,
|
||||
DBUS_TYPE_STRING, &iface,
|
||||
DBUS_TYPE_STRING, &name,
|
||||
DBUS_TYPE_INVALID))
|
||||
return NULL;
|
||||
|
||||
if (spa_streq(iface, PW_TELEPHONY_AG_TRANSPORT_IFACE))
|
||||
return dbus_message_new_error(m, DBUS_ERROR_UNKNOWN_INTERFACE,
|
||||
"No such interface");
|
||||
|
||||
if (spa_streq(name, "Codec")) {
|
||||
r = dbus_message_new_method_return(m);
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
dbus_message_iter_init_append(r, &i);
|
||||
dbus_message_iter_open_container(&i, DBUS_TYPE_VARIANT,
|
||||
DBUS_TYPE_BYTE_AS_STRING, &v);
|
||||
dbus_message_iter_append_basic(&v, DBUS_TYPE_BYTE,
|
||||
&agimpl->this.transport.codec);
|
||||
dbus_message_iter_close_container(&i, &v);
|
||||
return r;
|
||||
} else if (spa_streq(name, "State")) {
|
||||
r = dbus_message_new_method_return(m);
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
dbus_message_iter_init_append(r, &i);
|
||||
dbus_message_iter_open_container(&i, DBUS_TYPE_VARIANT,
|
||||
DBUS_TYPE_STRING_AS_STRING, &v);
|
||||
dbus_message_iter_append_basic(&v, DBUS_TYPE_STRING,
|
||||
transport_state_to_string(agimpl->this.transport.state));
|
||||
dbus_message_iter_close_container(&i, &v);
|
||||
return r;
|
||||
}
|
||||
|
||||
return dbus_message_new_error(m, DBUS_ERROR_UNKNOWN_PROPERTY,
|
||||
"No such property");
|
||||
}
|
||||
|
||||
static DBusMessage *ag_properties_get_all(struct agimpl *agimpl, DBusMessage *m)
|
||||
{
|
||||
DBusMessage *r;
|
||||
DBusMessageIter i;
|
||||
const char *iface;
|
||||
|
||||
if (!dbus_message_get_args(m, NULL,
|
||||
DBUS_TYPE_STRING, &iface,
|
||||
DBUS_TYPE_INVALID))
|
||||
return NULL;
|
||||
|
||||
if (!spa_streq(iface, PW_TELEPHONY_AG_TRANSPORT_IFACE))
|
||||
return dbus_message_new_error(m, DBUS_ERROR_UNKNOWN_INTERFACE,
|
||||
"No such interface");
|
||||
|
||||
r = dbus_message_new_method_return(m);
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
|
||||
dbus_message_iter_init_append(r, &i);
|
||||
dbus_iter_append_ag_transport_properties(&i, &agimpl->this, true);
|
||||
return r;
|
||||
}
|
||||
|
||||
static DBusMessage *ag_properties_set(struct agimpl *agimpl, DBusMessage *m)
|
||||
{
|
||||
return dbus_message_new_error(m, DBUS_ERROR_PROPERTY_READ_ONLY,
|
||||
"Property not writable");
|
||||
}
|
||||
|
||||
static bool validate_phone_number(const char *number)
|
||||
{
|
||||
const char *c;
|
||||
|
|
@ -693,6 +855,12 @@ static DBusHandlerResult ag_handler(DBusConnection *c, DBusMessage *m, void *use
|
|||
r = ag_introspect(agimpl, m);
|
||||
} else if (dbus_message_is_method_call(m, DBUS_INTERFACE_OBJECT_MANAGER, "GetManagedObjects")) {
|
||||
r = ag_get_managed_objects(agimpl, m, false);
|
||||
} else if (dbus_message_is_method_call(m, DBUS_INTERFACE_PROPERTIES, "Get")) {
|
||||
r = ag_properties_get(agimpl, m);
|
||||
} else if (dbus_message_is_method_call(m, DBUS_INTERFACE_PROPERTIES, "GetAll")) {
|
||||
r = ag_properties_get_all(agimpl, m);
|
||||
} else if (dbus_message_is_method_call(m, DBUS_INTERFACE_PROPERTIES, "Set")) {
|
||||
r = ag_properties_set(agimpl, m);
|
||||
} else if (dbus_message_is_method_call(m, PW_TELEPHONY_AG_IFACE, "Dial") ||
|
||||
dbus_message_is_method_call(m, OFONO_VOICE_CALL_MANAGER_IFACE, "Dial")) {
|
||||
r = ag_dial(agimpl, m);
|
||||
|
|
@ -799,20 +967,12 @@ int telephony_ag_register(struct spa_bt_telephony_ag *ag)
|
|||
/* notify on ObjectManager of the Manager object */
|
||||
{
|
||||
spa_autoptr(DBusMessage) msg = NULL;
|
||||
DBusMessageIter iter, entry, dict, props_dict;
|
||||
const char *interface = PW_TELEPHONY_AG_IFACE;
|
||||
DBusMessageIter iter;
|
||||
|
||||
msg = dbus_message_new_signal(impl->path, DBUS_INTERFACE_OBJECT_MANAGER,
|
||||
"InterfacesAdded");
|
||||
dbus_message_iter_init_append(msg, &iter);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
|
||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sa{sv}}", &dict);
|
||||
dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
|
||||
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &interface);
|
||||
dbus_message_iter_open_container(&entry, DBUS_TYPE_ARRAY, "{sv}", &props_dict);
|
||||
dbus_message_iter_close_container(&entry, &props_dict);
|
||||
dbus_message_iter_close_container(&dict, &entry);
|
||||
dbus_message_iter_close_container(&iter, &dict);
|
||||
dbus_iter_append_ag_interfaces(&iter, ag);
|
||||
|
||||
if (!dbus_connection_send(impl->conn, msg, NULL)) {
|
||||
spa_log_error(impl->log, "failed to send InterfacesAdded for %s", path);
|
||||
|
|
@ -859,6 +1019,7 @@ void telephony_ag_unregister(struct spa_bt_telephony_ag *ag)
|
|||
spa_autoptr(DBusMessage) msg = NULL;
|
||||
DBusMessageIter iter, entry;
|
||||
const char *interface = PW_TELEPHONY_AG_IFACE;
|
||||
const char *interface2 = PW_TELEPHONY_AG_TRANSPORT_IFACE;
|
||||
|
||||
msg = dbus_message_new_signal(impl->path, DBUS_INTERFACE_OBJECT_MANAGER,
|
||||
"InterfacesRemoved");
|
||||
|
|
@ -867,6 +1028,7 @@ void telephony_ag_unregister(struct spa_bt_telephony_ag *ag)
|
|||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_STRING_AS_STRING, &entry);
|
||||
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &interface);
|
||||
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &interface2);
|
||||
dbus_message_iter_close_container(&iter, &entry);
|
||||
|
||||
if (!dbus_connection_send(impl->conn, msg, NULL)) {
|
||||
|
|
@ -895,6 +1057,37 @@ void telephony_ag_unregister(struct spa_bt_telephony_ag *ag)
|
|||
agimpl->path = NULL;
|
||||
}
|
||||
|
||||
/* send message to notify about property changes */
|
||||
void telephony_ag_transport_notify_updated_props(struct spa_bt_telephony_ag *ag)
|
||||
{
|
||||
struct agimpl *agimpl = SPA_CONTAINER_OF(ag, struct agimpl, this);
|
||||
struct impl *impl = SPA_CONTAINER_OF(agimpl->this.telephony, struct impl, this);
|
||||
|
||||
spa_autoptr(DBusMessage) msg = NULL;
|
||||
const char *interface = PW_TELEPHONY_AG_TRANSPORT_IFACE;
|
||||
DBusMessageIter i, a;
|
||||
|
||||
msg = dbus_message_new_signal(agimpl->path,
|
||||
DBUS_INTERFACE_PROPERTIES,
|
||||
"PropertiesChanged");
|
||||
|
||||
dbus_message_iter_init_append(msg, &i);
|
||||
dbus_message_iter_append_basic(&i, DBUS_TYPE_STRING, &interface);
|
||||
|
||||
if (!dbus_iter_append_ag_transport_properties(&i, ag, false))
|
||||
return;
|
||||
|
||||
dbus_message_iter_open_container(&i, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_STRING_AS_STRING, &a);
|
||||
dbus_message_iter_close_container(&i, &a);
|
||||
|
||||
if (!dbus_connection_send(impl->conn, msg, NULL)){
|
||||
spa_log_warn(impl->log, "sending PropertiesChanged failed");
|
||||
}
|
||||
|
||||
telephony_ag_transport_commit_properties(ag);
|
||||
}
|
||||
|
||||
void telephony_ag_add_listener(struct spa_bt_telephony_ag *ag,
|
||||
struct spa_hook *listener,
|
||||
const struct spa_bt_telephony_ag_events *events,
|
||||
|
|
|
|||
|
|
@ -30,11 +30,19 @@ struct spa_bt_telephony {
|
|||
|
||||
};
|
||||
|
||||
struct spa_bt_telephony_ag_transport {
|
||||
int8_t codec;
|
||||
enum spa_bt_transport_state state;
|
||||
};
|
||||
|
||||
struct spa_bt_telephony_ag {
|
||||
struct spa_bt_telephony *telephony;
|
||||
struct spa_list call_list;
|
||||
|
||||
int id;
|
||||
|
||||
/* D-Bus properties */
|
||||
struct spa_bt_telephony_ag_transport transport;
|
||||
};
|
||||
|
||||
struct spa_bt_telephony_call {
|
||||
|
|
@ -91,6 +99,8 @@ void telephony_ag_add_listener(struct spa_bt_telephony_ag *ag,
|
|||
const struct spa_bt_telephony_ag_events *events,
|
||||
void *data);
|
||||
|
||||
void telephony_ag_transport_notify_updated_props(struct spa_bt_telephony_ag *ag);
|
||||
|
||||
/* register/unregister AudioGateway object on the bus */
|
||||
int telephony_ag_register(struct spa_bt_telephony_ag *ag);
|
||||
void telephony_ag_unregister(struct spa_bt_telephony_ag *ag);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue