mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
bluez: implement profile on device
Enumerate the available profiles on the device. Make params visible. Implement set_profile, only expose the nodes that belong to the profile.
This commit is contained in:
parent
5f70a2713e
commit
9db240e786
3 changed files with 90 additions and 35 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue