diff --git a/spa/plugins/bluez5/a2dp-sink.c b/spa/plugins/bluez5/a2dp-sink.c index e40023618..3a414a9a1 100644 --- a/spa/plugins/bluez5/a2dp-sink.c +++ b/spa/plugins/bluez5/a2dp-sink.c @@ -911,6 +911,7 @@ static int impl_node_send_command(void *object, const struct spa_command *comman if ((res = do_start(this)) < 0) return res; break; + case SPA_NODE_COMMAND_Suspend: case SPA_NODE_COMMAND_Pause: if ((res = do_stop(this)) < 0) return res; diff --git a/spa/plugins/bluez5/bluez5-device.c b/spa/plugins/bluez5/bluez5-device.c index 4293a1836..ba28ecd64 100644 --- a/spa/plugins/bluez5/bluez5-device.c +++ b/spa/plugins/bluez5/bluez5-device.c @@ -73,11 +73,10 @@ struct impl { struct spa_bt_device *bt_dev; - uint32_t next_id; uint32_t profile; }; -static void emit_node (struct impl *this, struct spa_bt_transport *t, const char *factory_name) +static void emit_node (struct impl *this, struct spa_bt_transport *t, uint32_t id, const char *factory_name) { struct spa_device_object_info info; struct spa_dict_item items[2]; @@ -93,39 +92,74 @@ static void emit_node (struct impl *this, struct spa_bt_transport *t, const char info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS; info.props = &SPA_DICT_INIT_ARRAY(items); - spa_device_emit_object_info(&this->hooks, this->next_id++, &info); + spa_device_emit_object_info(&this->hooks, id, &info); } -static int emit_nodes(struct impl *this) +static struct spa_bt_transport *find_transport(struct impl *this, int profile) { struct spa_bt_device *device = this->bt_dev; struct spa_bt_transport *t; spa_list_for_each(t, &device->transport_list, device_link) { - if (t->profile & device->connected_profiles) { - switch (t->profile) { - case SPA_BT_PROFILE_A2DP_SOURCE: - emit_node (this, t, SPA_NAME_API_BLUEZ5_A2DP_SOURCE); - break; - case SPA_BT_PROFILE_A2DP_SINK: - emit_node (this, t, SPA_NAME_API_BLUEZ5_A2DP_SINK); - break; - case SPA_BT_PROFILE_HSP_HS: - case SPA_BT_PROFILE_HSP_AG: - case SPA_BT_PROFILE_HFP_HF: - case SPA_BT_PROFILE_HFP_AG: - emit_node (this, t, SPA_NAME_API_BLUEZ5_SCO_SOURCE); - emit_node (this, t, SPA_NAME_API_BLUEZ5_SCO_SINK); - break; - default: - return -EINVAL; - } - } + if (t->profile & device->connected_profiles && + (t->profile & profile) == t->profile) + return t; } + return NULL; +} +static int emit_nodes(struct impl *this) +{ + struct spa_bt_transport *t; + + t = find_transport(this, this->profile); + if (t == NULL) + return 0; + + switch (this->profile) { + case SPA_BT_PROFILE_A2DP_SOURCE: + emit_node(this, t, 0, SPA_NAME_API_BLUEZ5_A2DP_SOURCE); + break; + case SPA_BT_PROFILE_A2DP_SINK: + emit_node(this, t, 0, SPA_NAME_API_BLUEZ5_A2DP_SINK); + break; + case SPA_BT_PROFILE_HSP_HS: + case SPA_BT_PROFILE_HSP_AG: + case SPA_BT_PROFILE_HFP_HF: + case SPA_BT_PROFILE_HFP_AG: + emit_node(this, t, 0, SPA_NAME_API_BLUEZ5_SCO_SOURCE); + emit_node(this, t, 1, SPA_NAME_API_BLUEZ5_SCO_SINK); + break; + default: + return -EINVAL; + } return 0; } +static int set_profile(struct impl *this, uint32_t profile) +{ + if (this->profile == profile) + return 0; + + switch (this->profile) { + case SPA_BT_PROFILE_A2DP_SOURCE: + case SPA_BT_PROFILE_A2DP_SINK: + spa_device_emit_object_info(&this->hooks, 0, NULL); + break; + case SPA_BT_PROFILE_HSP_HS: + case SPA_BT_PROFILE_HSP_AG: + case SPA_BT_PROFILE_HFP_HF: + case SPA_BT_PROFILE_HFP_AG: + spa_device_emit_object_info(&this->hooks, 0, NULL); + spa_device_emit_object_info(&this->hooks, 1, NULL); + break; + default: + break; + } + this->profile = profile; + return emit_nodes(this); +} + static const struct spa_dict_item info_items[] = { { SPA_KEY_DEVICE_API, "bluez5" }, { SPA_KEY_MEDIA_CLASS, "Audio/Device" }, @@ -146,6 +180,7 @@ static int impl_add_listener(void *object, if (events->info) { struct spa_device_info info; + struct spa_param_info params[2]; info = SPA_DEVICE_INFO_INIT(); @@ -153,8 +188,10 @@ static int impl_add_listener(void *object, info.props = &SPA_DICT_INIT_ARRAY(info_items); info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS; - info.n_params = 0; - info.params = NULL; + params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumProfile, SPA_PARAM_INFO_READ); + params[1] = SPA_PARAM_INFO(SPA_PARAM_Profile, SPA_PARAM_INFO_READWRITE); + info.n_params = SPA_N_ELEMENTS(params); + info.params = params; spa_device_emit_info(&this->hooks, &info); } @@ -178,6 +215,18 @@ static int impl_sync(void *object, int seq) return 0; } +static inline int maskn(int v, int n) +{ + int pos = 0, cnt = 0; + while (v) { + if ((v & 1) == 1 && (++cnt == n)) + return 1 << pos; + v >>= 1; + pos++; + } + return 0; +} + static int impl_enum_params(void *object, int seq, uint32_t id, uint32_t start, uint32_t num, const struct spa_pod *filter) @@ -188,6 +237,7 @@ static int impl_enum_params(void *object, int seq, uint8_t buffer[1024]; struct spa_result_device_params result; uint32_t count = 0; + struct spa_bt_device *device = this->bt_dev; spa_return_val_if_fail(this != NULL, -EINVAL); spa_return_val_if_fail(num != 0, -EINVAL); @@ -202,6 +252,8 @@ static int impl_enum_params(void *object, int seq, switch (id) { case SPA_PARAM_EnumProfile: { + int profile; + switch (result.index) { case 0: param = spa_pod_builder_add_object(&b, @@ -209,14 +261,18 @@ static int impl_enum_params(void *object, int seq, SPA_PARAM_PROFILE_index, SPA_POD_Int(0), SPA_PARAM_PROFILE_name, SPA_POD_String("Off")); break; - case 1: + default: + { + profile = maskn(device->connected_profiles, result.index); + if (profile == 0) + return 0; + param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_ParamProfile, id, - SPA_PARAM_PROFILE_index, SPA_POD_Int(1), - SPA_PARAM_PROFILE_name, SPA_POD_String("On")); + SPA_PARAM_PROFILE_index, SPA_POD_Int(profile), + SPA_PARAM_PROFILE_name, SPA_POD_String(spa_bt_profile_name(profile))); break; - default: - return 0; + } } break; } @@ -270,7 +326,7 @@ static int impl_set_param(void *object, spa_debug_pod(0, NULL, param); return res; } - + set_profile(this, id); break; } default: @@ -352,8 +408,6 @@ impl_init(const struct spa_handle_factory *factory, reset_props(&this->props); - this->next_id = 0; - return 0; } diff --git a/spa/plugins/bluez5/defs.h b/spa/plugins/bluez5/defs.h index 75c6a8ae5..ee419d287 100644 --- a/spa/plugins/bluez5/defs.h +++ b/spa/plugins/bluez5/defs.h @@ -109,8 +109,8 @@ extern "C" { enum spa_bt_profile { SPA_BT_PROFILE_NULL = 0, - SPA_BT_PROFILE_A2DP_SOURCE = (1 << 0), - SPA_BT_PROFILE_A2DP_SINK = (1 << 1), + SPA_BT_PROFILE_A2DP_SINK = (1 << 0), + SPA_BT_PROFILE_A2DP_SOURCE = (1 << 1), SPA_BT_PROFILE_HSP_HS = (1 << 2), SPA_BT_PROFILE_HSP_AG = (1 << 3), SPA_BT_PROFILE_HFP_HF = (1 << 4),