summaryrefslogtreecommitdiffstats
path: root/audio/manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/manager.c')
-rw-r--r--audio/manager.c377
1 files changed, 266 insertions, 111 deletions
diff --git a/audio/manager.c b/audio/manager.c
index 695c6ba0..8278ee25 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -85,33 +85,22 @@ typedef enum {
GET_RECORDS
} audio_sdp_state_t;
-struct audio_sdp_data {
- struct audio_device *device;
-
- DBusMessage *msg; /* Method call or NULL */
-
- GSList *records; /* sdp_record_t * */
-
- audio_sdp_state_t state;
-
- create_dev_cb_t cb;
- void *cb_data;
+struct audio_adapter {
+ bdaddr_t src;
+ char *path;
+ uint32_t hsp_ag_record_id;
+ uint32_t hfp_ag_record_id;
+ uint32_t hsp_hs_record_id;
+ GIOChannel *hsp_ag_server;
+ GIOChannel *hfp_ag_server;
+ GIOChannel *hsp_hs_server;
};
static DBusConnection *connection = NULL;
-
+static GKeyFile *config = NULL;
+static GSList *adapters = NULL;
static GSList *devices = NULL;
-static uint32_t hsp_ag_record_id = 0;
-static uint32_t hfp_ag_record_id = 0;
-
-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,
.gateway = FALSE,
@@ -120,6 +109,35 @@ static struct enabled_interfaces enabled = {
.control = TRUE,
};
+static struct audio_adapter *find_adapter(GSList *list, const char *path)
+{
+ GSList *l;
+
+ for (l = list; l; l = l->next) {
+ struct audio_adapter *adapter = l->data;
+
+ if (g_str_equal(adapter->path, path))
+ return adapter;
+ }
+
+ return NULL;
+}
+
+static struct audio_adapter *find_adapter_by_address(GSList *list,
+ const bdaddr_t *src)
+{
+ GSList *l;
+
+ for (l = list; l; l = l->next) {
+ struct audio_adapter *adapter = l->data;
+
+ if (bacmp(&adapter->src, src) == 0)
+ return adapter;
+ }
+
+ return NULL;
+}
+
static uint16_t get_service_uuid(const sdp_record_t *record)
{
sdp_list_t *classes;
@@ -154,19 +172,24 @@ done:
return uuid16;
}
-gboolean server_is_enabled(uint16_t svc)
+gboolean server_is_enabled(bdaddr_t *src, uint16_t svc)
{
+ struct audio_adapter *adp;
gboolean ret;
+ adp = find_adapter_by_address(adapters, src);
+ if (!adp)
+ return FALSE;
+
switch (svc) {
case HEADSET_SVCLASS_ID:
- ret = (hsp_ag_server != NULL);
+ ret = (adp->hsp_ag_server != NULL);
break;
case HEADSET_AGW_SVCLASS_ID:
- ret = (hsp_hs_server != NULL);
+ ret = (adp->hsp_hs_server != NULL);
break;
case HANDSFREE_SVCLASS_ID:
- ret = (hfp_ag_server != NULL);
+ ret = (adp->hfp_ag_server != NULL);
break;
case HANDSFREE_AGW_SVCLASS_ID:
ret = FALSE;
@@ -190,7 +213,7 @@ static void handle_record(sdp_record_t *record, struct audio_device *device)
uuid16 = get_service_uuid(record);
- if (!server_is_enabled(uuid16))
+ if (!server_is_enabled(&device->src, uuid16))
return;
switch (uuid16) {
@@ -455,6 +478,7 @@ static void auth_cb(DBusError *derr, void *user_data)
static void ag_io_cb(GIOChannel *chan, int err, const bdaddr_t *src,
const bdaddr_t *dst, gpointer data)
{
+ struct audio_adapter *adapter = data;
const char *uuid;
struct audio_device *device;
gboolean hfp_active;
@@ -464,7 +488,7 @@ static void ag_io_cb(GIOChannel *chan, int err, const bdaddr_t *src,
return;
}
- if (chan == hsp_ag_server) {
+ if (chan == adapter->hsp_ag_server) {
hfp_active = FALSE;
uuid = HSP_AG_UUID;
} else {
@@ -513,7 +537,7 @@ static void hs_io_cb(GIOChannel *chan, int err, const bdaddr_t *src,
return;
}
-static int headset_server_init(DBusConnection *conn, GKeyFile *config)
+static int headset_server_init(struct audio_adapter *adapter)
{
uint8_t chan = DEFAULT_HS_AG_CHANNEL;
sdp_record_t *record;
@@ -521,9 +545,6 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)
GError *err = NULL;
uint32_t features, flags;
- if (!enabled.headset)
- return 0;
-
if (config) {
gboolean tmp;
@@ -551,9 +572,9 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)
if (master)
flags |= RFCOMM_LM_MASTER;
- hsp_ag_server = bt_rfcomm_listen(BDADDR_ANY, chan, flags, ag_io_cb,
- NULL);
- if (!hsp_ag_server)
+ adapter->hsp_ag_server = bt_rfcomm_listen(&adapter->src, chan, flags,
+ ag_io_cb,adapter);
+ if (!adapter->hsp_ag_server)
return -1;
record = hsp_ag_record(chan);
@@ -562,14 +583,14 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)
return -1;
}
- if (add_record_to_server(BDADDR_ANY, record) < 0) {
+ if (add_record_to_server(&adapter->src, record) < 0) {
error("Unable to register HS AG service record");
sdp_record_free(record);
- g_io_channel_unref(hsp_ag_server);
- hsp_ag_server = NULL;
+ g_io_channel_unref(adapter->hsp_ag_server);
+ adapter->hsp_ag_server = NULL;
return -1;
}
- hsp_ag_record_id = record->handle;
+ adapter->hsp_ag_record_id = record->handle;
features = headset_config_init(config);
@@ -578,9 +599,9 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)
chan = DEFAULT_HF_AG_CHANNEL;
- hfp_ag_server = bt_rfcomm_listen(BDADDR_ANY, chan, flags, ag_io_cb,
- NULL);
- if (!hfp_ag_server)
+ adapter->hfp_ag_server = bt_rfcomm_listen(&adapter->src, chan, flags,
+ ag_io_cb, adapter);
+ if (!adapter->hfp_ag_server)
return -1;
record = hfp_ag_record(chan, features);
@@ -589,19 +610,19 @@ static int headset_server_init(DBusConnection *conn, GKeyFile *config)
return -1;
}
- if (add_record_to_server(BDADDR_ANY, record) < 0) {
+ if (add_record_to_server(&adapter->src, record) < 0) {
error("Unable to register HF AG service record");
sdp_record_free(record);
- g_io_channel_unref(hfp_ag_server);
- hfp_ag_server = NULL;
+ g_io_channel_unref(adapter->hfp_ag_server);
+ adapter->hfp_ag_server = NULL;
return -1;
}
- hfp_ag_record_id = record->handle;
+ adapter->hfp_ag_record_id = record->handle;
return 0;
}
-static int gateway_server_init(DBusConnection *conn, GKeyFile *config)
+static int gateway_server_init(struct audio_adapter *adapter)
{
uint8_t chan = DEFAULT_HSP_HS_CHANNEL;
sdp_record_t *record;
@@ -609,9 +630,6 @@ static int gateway_server_init(DBusConnection *conn, GKeyFile *config)
GError *err = NULL;
uint32_t flags;
- if (!enabled.gateway)
- return 0;
-
if (config) {
gboolean tmp;
@@ -630,9 +648,9 @@ static int gateway_server_init(DBusConnection *conn, GKeyFile *config)
if (master)
flags |= RFCOMM_LM_MASTER;
- hsp_hs_server = bt_rfcomm_listen(BDADDR_ANY, chan, flags, hs_io_cb,
- NULL);
- if (!hsp_hs_server)
+ adapter->hsp_hs_server = bt_rfcomm_listen(&adapter->src, chan, flags,
+ hs_io_cb, adapter);
+ if (!adapter->hsp_hs_server)
return -1;
record = hsp_hs_record(chan);
@@ -641,52 +659,19 @@ static int gateway_server_init(DBusConnection *conn, GKeyFile *config)
return -1;
}
- if (add_record_to_server(BDADDR_ANY, record) < 0) {
+ if (add_record_to_server(&adapter->src, 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;
+ g_io_channel_unref(adapter->hsp_hs_server);
+ adapter->hsp_hs_server = NULL;
return -1;
}
- hsp_hs_record_id = record->handle;
+ adapter->hsp_hs_record_id = record->handle;
return 0;
}
-static void server_exit(void)
-{
- if (hsp_ag_record_id) {
- remove_record_from_server(hsp_ag_record_id);
- hsp_ag_record_id = 0;
- }
-
- if (hsp_ag_server) {
- g_io_channel_unref(hsp_ag_server);
- hsp_ag_server = NULL;
- }
-
- if (hsp_hs_record_id) {
- remove_record_from_server(hsp_hs_record_id);
- hsp_hs_record_id = 0;
- }
-
- 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;
- }
-}
-
static int audio_probe(struct btd_device_driver *driver,
struct btd_device *device, GSList *records)
{
@@ -733,6 +718,148 @@ static void audio_remove(struct btd_device_driver *driver,
device_unregister(dev);
}
+static struct audio_adapter *create_audio_adapter(const char *path, bdaddr_t *src)
+{
+ struct audio_adapter *adp;
+
+ adp = g_new0(struct audio_adapter, 1);
+ adp->path = g_strdup(path);
+ bacpy(&adp->src, src);
+
+ return adp;
+}
+
+static struct audio_adapter *get_audio_adapter(struct adapter *adapter)
+{
+ struct audio_adapter *adp;
+ const gchar *path = adapter_get_path(adapter);
+ const char *source;
+ bdaddr_t src;
+
+ source = adapter_get_address(adapter);
+ str2ba(source, &src);
+
+ adp = find_adapter(adapters, path);
+ if (!adp) {
+ adp = create_audio_adapter(path, &src);
+ if (!adp)
+ return NULL;
+ adapters = g_slist_append(adapters, adp);
+ }
+
+ return adp;
+}
+
+static int headset_server_probe(struct adapter *adapter)
+{
+ struct audio_adapter *adp;
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ adp = get_audio_adapter(adapter);
+ if (!adp)
+ return -EINVAL;
+
+ return headset_server_init(adp);
+}
+
+static void headset_server_remove(struct adapter *adapter)
+{
+ struct audio_adapter *adp;
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ adp = find_adapter(adapters, path);
+ if (!adp)
+ return;
+
+ if (adp->hsp_ag_record_id) {
+ remove_record_from_server(adp->hsp_ag_record_id);
+ adp->hsp_ag_record_id = 0;
+ }
+
+ if (adp->hsp_ag_server) {
+ g_io_channel_unref(adp->hsp_ag_server);
+ adp->hsp_ag_server = NULL;
+ }
+
+ if (adp->hfp_ag_record_id) {
+ remove_record_from_server(adp->hfp_ag_record_id);
+ adp->hfp_ag_record_id = 0;
+ }
+
+ if (adp->hfp_ag_server) {
+ g_io_channel_unref(adp->hfp_ag_server);
+ adp->hfp_ag_server = NULL;
+ }
+}
+
+static int gateway_server_probe(struct adapter *adapter)
+{
+ struct audio_adapter *adp;
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ adp = get_audio_adapter(adapter);
+ if (!adp)
+ return -EINVAL;
+
+ return gateway_server_init(adp);
+}
+
+static void gateway_server_remove(struct adapter *adapter)
+{
+ struct audio_adapter *adp;
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ adp = find_adapter(adapters, path);
+ if (!adp)
+ return;
+
+ if (adp->hsp_hs_record_id) {
+ remove_record_from_server(adp->hsp_hs_record_id);
+ adp->hsp_hs_record_id = 0;
+ }
+
+ if (adp->hsp_hs_server) {
+ g_io_channel_unref(adp->hsp_hs_server);
+ adp->hsp_hs_server = NULL;
+ }
+}
+
+static int a2dp_server_probe(struct adapter *adapter)
+{
+ struct audio_adapter *adp;
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ adp = get_audio_adapter(adapter);
+ if (!adp)
+ return -EINVAL;
+
+ return a2dp_init(connection, config);
+}
+
+static int avrcp_server_probe(struct adapter *adapter)
+{
+ struct audio_adapter *adp;
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ adp = get_audio_adapter(adapter);
+ if (!adp)
+ return -EINVAL;
+
+ return avrcp_init(connection, config);
+}
+
static struct btd_device_driver audio_driver = {
.name = "audio",
.uuids = BTD_UUIDS(HSP_HS_UUID, HFP_HS_UUID, HSP_AG_UUID, HFP_AG_UUID,
@@ -742,16 +869,40 @@ static struct btd_device_driver audio_driver = {
.remove = audio_remove,
};
-int audio_manager_init(DBusConnection *conn, GKeyFile *config)
+static struct btd_adapter_driver headset_server_driver = {
+ .name = "audio-headset",
+ .probe = headset_server_probe,
+ .remove = headset_server_remove,
+};
+
+static struct btd_adapter_driver gateway_server_driver = {
+ .name = "audio-gateway",
+ .probe = gateway_server_probe,
+ .remove = gateway_server_remove,
+};
+
+static struct btd_adapter_driver a2dp_server_driver = {
+ .name = "audio-a2dp",
+ .probe = a2dp_server_probe,
+};
+
+static struct btd_adapter_driver avrcp_server_driver = {
+ .name = "audio-control",
+ .probe = avrcp_server_probe,
+};
+
+int audio_manager_init(DBusConnection *conn, GKeyFile *conf)
{
char **list;
int i;
connection = dbus_connection_ref(conn);
- if (!config)
+ if (!conf)
goto proceed;
+ config = conf;
+
list = g_key_file_get_string_list(config, "General", "Enable",
NULL, NULL);
for (i = 0; list && list[i] != NULL; i++) {
@@ -785,38 +936,42 @@ int audio_manager_init(DBusConnection *conn, GKeyFile *config)
g_strfreev(list);
proceed:
- if (enabled.headset) {
- if (headset_server_init(conn, config) < 0)
- goto failed;
- }
+ if (enabled.headset)
+ btd_register_adapter_driver(&headset_server_driver);
- if (enabled.gateway) {
- if (gateway_server_init(conn, config) < 0)
- goto failed;
- }
+ if (enabled.gateway)
+ btd_register_adapter_driver(&gateway_server_driver);
- if (enabled.source || enabled.sink) {
- if (a2dp_init(conn, config) < 0)
- goto failed;
- }
+ if (enabled.source || enabled.sink)
+ btd_register_adapter_driver(&a2dp_server_driver);
- if (enabled.control && avrcp_init(conn, config) < 0)
- goto failed;
+ if (enabled.control)
+ btd_register_adapter_driver(&avrcp_server_driver);
btd_register_device_driver(&audio_driver);
return 0;
-failed:
- audio_manager_exit();
- return -1;
}
void audio_manager_exit(void)
{
- server_exit();
-
dbus_connection_unref(connection);
+ if (config)
+ g_key_file_free(config);
+
+ if (enabled.headset)
+ btd_unregister_adapter_driver(&headset_server_driver);
+
+ if (enabled.gateway)
+ btd_unregister_adapter_driver(&gateway_server_driver);
+
+ if (enabled.source || enabled.sink)
+ btd_unregister_adapter_driver(&a2dp_server_driver);
+
+ if (enabled.control)
+ btd_unregister_adapter_driver(&avrcp_server_driver);
+
btd_unregister_device_driver(&audio_driver);
connection = NULL;