bluetooth: Support port availability flag

Use the port availability flag to expose whether a certain profile is
connected and whether it's doing actual audio streaming.

The proposed mapping is the following:
- Profile disconnected: port is unavailable
- Profile is connected (but not streaming/playing): availability unknown
- Profile is streaming/playing: port is available

The availability-unknown is specially interesting: it involves that if
the sink/source exists (corresponding card profile set), it is currently
in suspended state.

For example, for SCO cases (HFGW or HSP), this means the SCO is down. A
policy module would typically not change this, unless someone is really
trying to use the sink/source. This situation would be nicely handled by
module-suspend-on-idle, which would automatically connect SCO.

On the other hand, if the user wants to control the status of the SCO,
it will still be possible by resuming the sink or source (suspend=0).
This works out-of-the-box since most UIs would show to the user ports
whose availability is unknown.
This commit is contained in:
Mikel Astiz 2012-08-31 12:51:02 +02:00 committed by Arun Raghavan
parent 4cc4c30187
commit dcc11dcbe9

View file

@ -1230,6 +1230,15 @@ static pa_bt_audio_state_t parse_state_property_change(DBusMessage *m) {
return state; return state;
} }
static pa_port_available_t audio_state_to_availability(pa_bt_audio_state_t state) {
if (state < PA_BT_AUDIO_STATE_CONNECTED)
return PA_PORT_AVAILABLE_NO;
else if (state >= PA_BT_AUDIO_STATE_PLAYING)
return PA_PORT_AVAILABLE_YES;
else
return PA_PORT_AVAILABLE_UNKNOWN;
}
/* Run from main thread */ /* Run from main thread */
static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *userdata) { static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *userdata) {
DBusError err; DBusError err;
@ -1300,6 +1309,50 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us
} }
break; break;
} }
if (state != PA_BT_AUDIO_STATE_INVALID) {
pa_device_port *port;
pa_port_available_t available = audio_state_to_availability(state);
pa_assert_se(port = pa_hashmap_get(u->card->ports, "hfgw-output"));
pa_device_port_set_available(port, available);
pa_assert_se(port = pa_hashmap_get(u->card->ports, "hfgw-input"));
pa_device_port_set_available(port, available);
}
} else if (dbus_message_is_signal(m, "org.bluez.Headset", "PropertyChanged")) {
pa_bt_audio_state_t state = parse_state_property_change(m);
if (state != PA_BT_AUDIO_STATE_INVALID) {
pa_device_port *port;
pa_port_available_t available = audio_state_to_availability(state);
pa_assert_se(port = pa_hashmap_get(u->card->ports, "hsp-output"));
pa_device_port_set_available(port, available);
pa_assert_se(port = pa_hashmap_get(u->card->ports, "hsp-input"));
pa_device_port_set_available(port, available);
}
} else if (dbus_message_is_signal(m, "org.bluez.AudioSource", "PropertyChanged")) {
pa_bt_audio_state_t state = parse_state_property_change(m);
if (state != PA_BT_AUDIO_STATE_INVALID) {
pa_device_port *port;
pa_port_available_t available = audio_state_to_availability(state);
pa_assert_se(port = pa_hashmap_get(u->card->ports, "a2dp-input"));
pa_device_port_set_available(port, available);
}
} else if (dbus_message_is_signal(m, "org.bluez.AudioSink", "PropertyChanged")) {
pa_bt_audio_state_t state = parse_state_property_change(m);
if (state != PA_BT_AUDIO_STATE_INVALID) {
pa_device_port *port;
pa_port_available_t available = audio_state_to_availability(state);
pa_assert_se(port = pa_hashmap_get(u->card->ports, "a2dp-output"));
pa_device_port_set_available(port, available);
}
} }
fail: fail:
@ -2107,7 +2160,7 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
return 0; return 0;
} }
static void create_ports_for_profile(struct userdata *u, pa_card_new_data *card_new_data, pa_card_profile *profile) { static void create_ports_for_profile(struct userdata *u, const pa_bluetooth_device *device, pa_card_new_data *card_new_data, pa_card_profile *profile) {
pa_device_port *port; pa_device_port *port;
enum profile *d; enum profile *d;
@ -2120,6 +2173,7 @@ static void create_ports_for_profile(struct userdata *u, pa_card_new_data *card_
port->is_output = 1; port->is_output = 1;
port->is_input = 0; port->is_input = 0;
port->priority = profile->priority * 100; port->priority = profile->priority * 100;
port->available = audio_state_to_availability(device->audio_sink_state);
pa_hashmap_put(port->profiles, profile->name, profile); pa_hashmap_put(port->profiles, profile->name, profile);
break; break;
@ -2129,6 +2183,7 @@ static void create_ports_for_profile(struct userdata *u, pa_card_new_data *card_
port->is_output = 0; port->is_output = 0;
port->is_input = 1; port->is_input = 1;
port->priority = profile->priority * 100; port->priority = profile->priority * 100;
port->available = audio_state_to_availability(device->audio_source_state);
pa_hashmap_put(port->profiles, profile->name, profile); pa_hashmap_put(port->profiles, profile->name, profile);
break; break;
@ -2138,6 +2193,7 @@ static void create_ports_for_profile(struct userdata *u, pa_card_new_data *card_
port->is_output = 1; port->is_output = 1;
port->is_input = 0; port->is_input = 0;
port->priority = profile->priority * 100; port->priority = profile->priority * 100;
port->available = audio_state_to_availability(device->headset_state);
pa_hashmap_put(port->profiles, profile->name, profile); pa_hashmap_put(port->profiles, profile->name, profile);
pa_assert_se(port = pa_device_port_new(u->core, "hsp-input", _("Bluetooth Telephony (HSP/HFP)"), 0)); pa_assert_se(port = pa_device_port_new(u->core, "hsp-input", _("Bluetooth Telephony (HSP/HFP)"), 0));
@ -2145,6 +2201,7 @@ static void create_ports_for_profile(struct userdata *u, pa_card_new_data *card_
port->is_output = 0; port->is_output = 0;
port->is_input = 1; port->is_input = 1;
port->priority = profile->priority * 100; port->priority = profile->priority * 100;
port->available = audio_state_to_availability(device->headset_state);
pa_hashmap_put(port->profiles, profile->name, profile); pa_hashmap_put(port->profiles, profile->name, profile);
break; break;
@ -2154,6 +2211,7 @@ static void create_ports_for_profile(struct userdata *u, pa_card_new_data *card_
port->is_output = 1; port->is_output = 1;
port->is_input = 0; port->is_input = 0;
port->priority = profile->priority * 100; port->priority = profile->priority * 100;
port->available = audio_state_to_availability(device->hfgw_state);
pa_hashmap_put(port->profiles, profile->name, profile); pa_hashmap_put(port->profiles, profile->name, profile);
pa_assert_se(port = pa_device_port_new(u->core, "hfgw-input", _("Bluetooth Handsfree Gateway"), 0)); pa_assert_se(port = pa_device_port_new(u->core, "hfgw-input", _("Bluetooth Handsfree Gateway"), 0));
@ -2161,6 +2219,7 @@ static void create_ports_for_profile(struct userdata *u, pa_card_new_data *card_
port->is_output = 0; port->is_output = 0;
port->is_input = 1; port->is_input = 1;
port->priority = profile->priority * 100; port->priority = profile->priority * 100;
port->available = audio_state_to_availability(device->hfgw_state);
pa_hashmap_put(port->profiles, profile->name, profile); pa_hashmap_put(port->profiles, profile->name, profile);
break; break;
@ -2222,7 +2281,7 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) {
d = PA_CARD_PROFILE_DATA(p); d = PA_CARD_PROFILE_DATA(p);
*d = PROFILE_A2DP; *d = PROFILE_A2DP;
create_ports_for_profile(u, &data, p); create_ports_for_profile(u, device, &data, p);
pa_hashmap_put(data.profiles, p->name, p); pa_hashmap_put(data.profiles, p->name, p);
} }
@ -2237,7 +2296,7 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) {
d = PA_CARD_PROFILE_DATA(p); d = PA_CARD_PROFILE_DATA(p);
*d = PROFILE_A2DP_SOURCE; *d = PROFILE_A2DP_SOURCE;
create_ports_for_profile(u, &data, p); create_ports_for_profile(u, device, &data, p);
pa_hashmap_put(data.profiles, p->name, p); pa_hashmap_put(data.profiles, p->name, p);
} }
@ -2253,7 +2312,7 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) {
d = PA_CARD_PROFILE_DATA(p); d = PA_CARD_PROFILE_DATA(p);
*d = PROFILE_HSP; *d = PROFILE_HSP;
create_ports_for_profile(u, &data, p); create_ports_for_profile(u, device, &data, p);
pa_hashmap_put(data.profiles, p->name, p); pa_hashmap_put(data.profiles, p->name, p);
} }
@ -2268,7 +2327,7 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) {
d = PA_CARD_PROFILE_DATA(p); d = PA_CARD_PROFILE_DATA(p);
*d = PROFILE_HFGW; *d = PROFILE_HFGW;
create_ports_for_profile(u, &data, p); create_ports_for_profile(u, device, &data, p);
pa_hashmap_put(data.profiles, p->name, p); pa_hashmap_put(data.profiles, p->name, p);
} }
@ -2467,6 +2526,9 @@ int pa__init(pa_module* m) {
mike, mike,
"type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'", "type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'",
"type='signal',sender='org.bluez',interface='org.bluez.HandsfreeGateway',member='PropertyChanged'", "type='signal',sender='org.bluez',interface='org.bluez.HandsfreeGateway',member='PropertyChanged'",
"type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'",
"type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'",
"type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
NULL) < 0) { NULL) < 0) {
pa_xfree(speaker); pa_xfree(speaker);