summaryrefslogtreecommitdiffstats
path: root/audio/manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/manager.c')
-rw-r--r--audio/manager.c203
1 files changed, 170 insertions, 33 deletions
diff --git a/audio/manager.c b/audio/manager.c
index 869557ca..6154e766 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -103,11 +103,15 @@ static struct device *default_dev = NULL;
static GSList *devices = NULL;
-static uint32_t hs_record_id = 0;
-static uint32_t hf_record_id = 0;
+static uint32_t hsp_ag_record_id = 0;
+static uint32_t hfp_ag_record_id = 0;
-static GIOChannel *hs_server = NULL;
-static GIOChannel *hf_server = NULL;
+static uint32_t hsp_hs_record_id = 0;
+
+static GIOChannel *hsp_ag_server = NULL;
+static GIOChannel *hfp_ag_server = NULL;
+
+static GIOChannel *hsp_hs_server = NULL;
static struct enabled_interfaces enabled = {
.headset = TRUE,
@@ -227,10 +231,16 @@ gboolean server_is_enabled(uint16_t svc)
switch (svc) {
case HEADSET_SVCLASS_ID:
- ret = (hs_server != NULL);
+ ret = (hsp_ag_server != NULL);
+ break;
+ case HEADSET_AGW_SVCLASS_ID:
+ ret = (hsp_hs_server != NULL);
break;
case HANDSFREE_SVCLASS_ID:
- ret = (hf_server != NULL);
+ ret = (hfp_ag_server != NULL);
+ break;
+ case HANDSFREE_AGW_SVCLASS_ID:
+ ret = FALSE;
break;
case AUDIO_SINK_SVCLASS_ID:
return enabled.sink;
@@ -1222,6 +1232,62 @@ static sdp_record_t *hsp_ag_record(uint8_t ch)
return record;
}
+static sdp_record_t *hsp_hs_record(uint8_t ch)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+ uuid_t l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_record_t *record;
+ sdp_list_t *aproto, *proto[2];
+ sdp_data_t *channel;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HEADSET_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
+ profile.version = 0x0100;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &ch);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ sdp_set_info_attr(record, "Headset", 0, 0);
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+
+ return record;
+}
+
static sdp_record_t *hfp_ag_record(uint8_t ch, uint32_t feat)
{
sdp_list_t *svclass_id, *pfseq, *apseq, *root;
@@ -1360,7 +1426,7 @@ static gboolean ag_io_cb(GIOChannel *chan, GIOCondition cond, void *data)
return TRUE;
}
- if (chan == hs_server) {
+ if (chan == hsp_ag_server) {
hfp_active = FALSE;
uuid = HSP_AG_UUID;
} else {
@@ -1406,6 +1472,12 @@ failed:
return TRUE;
}
+static gboolean hs_io_cb(GIOChannel *chan, GIOCondition cond, void *data)
+{
+ /*Stub*/
+ return TRUE;
+}
+
static GIOChannel *server_socket(uint8_t *channel, gboolean master)
{
int sock, lm;
@@ -1469,7 +1541,7 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)
GError *err = NULL;
uint32_t features;
- if (!(enabled.headset || enabled.gateway))
+ if (!enabled.headset)
return 0;
if (config) {
@@ -1494,8 +1566,8 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)
hfp = tmp;
}
- hs_server = server_socket(&chan, master);
- if (!hs_server)
+ hsp_ag_server = server_socket(&chan, master);
+ if (!hsp_ag_server)
return -1;
record = hsp_ag_record(chan);
@@ -1507,14 +1579,15 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)
if (add_record_to_server(BDADDR_ANY, record) < 0) {
error("Unable to register HS AG service record");
sdp_record_free(record);
- g_io_channel_unref(hs_server);
- hs_server = NULL;
+ g_io_channel_unref(hsp_ag_server);
+ hsp_ag_server = NULL;
return -1;
}
- hs_record_id = record->handle;
+ hsp_ag_record_id = record->handle;
- g_io_add_watch(hs_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- (GIOFunc) ag_io_cb, NULL);
+ g_io_add_watch(hsp_ag_server,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ (GIOFunc) ag_io_cb, NULL);
features = headset_config_init(config);
@@ -1523,8 +1596,8 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)
chan = DEFAULT_HF_AG_CHANNEL;
- hf_server = server_socket(&chan, master);
- if (!hf_server)
+ hfp_ag_server = server_socket(&chan, master);
+ if (!hfp_ag_server)
return -1;
record = hfp_ag_record(chan, features);
@@ -1536,38 +1609,97 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)
if (add_record_to_server(BDADDR_ANY, record) < 0) {
error("Unable to register HF AG service record");
sdp_record_free(record);
- g_io_channel_unref(hf_server);
- hf_server = NULL;
+ g_io_channel_unref(hfp_ag_server);
+ hfp_ag_server = NULL;
return -1;
}
- hf_record_id = record->handle;
+ hfp_ag_record_id = record->handle;
- g_io_add_watch(hf_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ g_io_add_watch(hfp_ag_server,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
(GIOFunc) ag_io_cb, NULL);
return 0;
}
+static int gateway_server_init(DBusConnection *conn, GKeyFile *config)
+{
+ uint8_t chan = DEFAULT_HSP_HS_CHANNEL;
+ sdp_record_t *record;
+ gboolean master = TRUE;
+ GError *err = NULL;
+
+ if (!enabled.gateway)
+ return 0;
+
+ if (config) {
+ gboolean tmp;
+
+ tmp = g_key_file_get_boolean(config, "General", "Master",
+ &err);
+ if (err) {
+ debug("audio.conf: %s", err->message);
+ g_error_free(err);
+ err = NULL;
+ } else
+ master = tmp;
+ }
+
+ hsp_hs_server = server_socket(&chan, master);
+ if (!hsp_hs_server)
+ return -1;
+
+ record = hsp_hs_record(chan);
+ if (!record) {
+ error("Unable to allocate new service record");
+ return -1;
+ }
+
+ if (add_record_to_server(BDADDR_ANY, record) < 0) {
+ error("Unable to register HSP HS service record");
+ sdp_record_free(record);
+ g_io_channel_unref(hsp_hs_server);
+ hsp_hs_server = NULL;
+ return -1;
+ }
+ hsp_hs_record_id = record->handle;
+
+ g_io_add_watch(hsp_hs_server,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ (GIOFunc) hs_io_cb, NULL);
+ return 0;
+}
+
static void server_exit(void)
{
- if (hs_record_id) {
- remove_record_from_server(hs_record_id);
- hs_record_id = 0;
+ if (hsp_ag_record_id) {
+ remove_record_from_server(hsp_ag_record_id);
+ hsp_ag_record_id = 0;
}
- if (hs_server) {
- g_io_channel_unref(hs_server);
- hs_server = NULL;
+ if (hsp_ag_server) {
+ g_io_channel_unref(hsp_ag_server);
+ hsp_ag_server = NULL;
}
- if (hf_record_id) {
- remove_record_from_server(hf_record_id);
- hf_record_id = 0;
+ if (hsp_hs_record_id) {
+ remove_record_from_server(hsp_hs_record_id);
+ hsp_hs_record_id = 0;
}
- if (hf_server) {
- g_io_channel_unref(hf_server);
- hf_server = NULL;
+ if (hsp_hs_server) {
+ g_io_channel_unref(hsp_hs_server);
+ hsp_hs_server = NULL;
+ }
+
+ if (hfp_ag_record_id) {
+ remove_record_from_server(hfp_ag_record_id);
+ hfp_ag_record_id = 0;
+ }
+
+ if (hfp_ag_server) {
+ g_io_channel_unref(hfp_ag_server);
+ hfp_ag_server = NULL;
}
}
@@ -1631,6 +1763,11 @@ int audio_manager_init(DBusConnection *conn, GKeyFile *config)
goto failed;
}
+ if (enabled.gateway) {
+ if (gateway_server_init(conn, config) < 0)
+ goto failed;
+ }
+
if (enabled.source || enabled.sink) {
if (a2dp_init(conn, config) < 0)
goto failed;