summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2008-09-08 18:20:29 -0300
committerLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2008-09-08 18:20:29 -0300
commit957d01bac7a4c448bbe0a15de613af7927d1c7d0 (patch)
tree4c279a27c3284d9434a08cc5802b97bf846c6479 /audio
parent75b61c0a4f415fdb6518b9cf99f9b5d4b8072c5f (diff)
Fix a2dp and avrcp drivers to not rely on BDADDR_ANY.
Diffstat (limited to 'audio')
-rw-r--r--audio/a2dp.c118
-rw-r--r--audio/a2dp.h4
-rw-r--r--audio/avdtp.c133
-rw-r--r--audio/avdtp.h7
-rw-r--r--audio/control.c87
-rw-r--r--audio/control.h4
-rw-r--r--audio/manager.c34
7 files changed, 270 insertions, 117 deletions
diff --git a/audio/a2dp.c b/audio/a2dp.c
index 5e8cfd85..de15a42a 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -92,12 +92,15 @@ struct a2dp_setup {
static DBusConnection *connection = NULL;
-static GSList *sinks = NULL;
-static GSList *sources = NULL;
-
-static uint32_t source_record_id = 0;
-static uint32_t sink_record_id = 0;
+struct a2dp_server {
+ bdaddr_t src;
+ GSList *sinks;
+ GSList *sources;
+ uint32_t source_record_id;
+ uint32_t sink_record_id;
+};
+static GSList *servers = NULL;
static GSList *setups = NULL;
static unsigned int cb_id = 0;
@@ -981,7 +984,7 @@ static sdp_record_t *a2dp_sink_record()
return NULL;
}
-static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type,
+static struct a2dp_sep *a2dp_add_sep(struct a2dp_server *server, uint8_t type,
uint8_t codec)
{
struct a2dp_sep *sep;
@@ -994,8 +997,9 @@ static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type,
sep = g_new0(struct a2dp_sep, 1);
ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind;
- sep->sep = avdtp_register_sep(type, AVDTP_MEDIA_TYPE_AUDIO, codec,
- ind, &cfm, sep);
+ sep->sep = avdtp_register_sep(&server->src, type,
+ AVDTP_MEDIA_TYPE_AUDIO, codec, ind,
+ &cfm, sep);
if (sep->sep == NULL) {
g_free(sep);
return NULL;
@@ -1005,13 +1009,13 @@ static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type,
sep->type = type;
if (type == AVDTP_SEP_TYPE_SOURCE) {
- l = &sources;
+ l = &server->sources;
create_record = a2dp_source_record;
- record_id = &source_record_id;
+ record_id = &server->source_record_id;
} else {
- l = &sinks;
+ l = &server->sinks;
create_record = a2dp_sink_record;
- record_id = &sink_record_id;
+ record_id = &server->sink_record_id;
}
if (*record_id != 0)
@@ -1025,7 +1029,7 @@ static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type,
return NULL;
}
- if (add_record_to_server(BDADDR_ANY, record) < 0) {
+ if (add_record_to_server(&server->src, record) < 0) {
error("Unable to register A2DP service record");\
sdp_record_free(record);
avdtp_unregister_sep(sep->sep);
@@ -1040,7 +1044,21 @@ add:
return sep;
}
-int a2dp_init(DBusConnection *conn, GKeyFile *config)
+static struct a2dp_server *find_server(GSList *list, const bdaddr_t *src)
+{
+ GSList *l;
+
+ for (l = list; l; l = l->next) {
+ struct a2dp_server *server = l->data;
+
+ if (bacmp(&server->src, src) == 0)
+ return server;
+ }
+
+ return NULL;
+}
+
+int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)
{
int sbc_srcs = 1, sbc_sinks = 0;
int mpeg12_srcs = 0, mpeg12_sinks = 0;
@@ -1048,6 +1066,7 @@ int a2dp_init(DBusConnection *conn, GKeyFile *config)
char *str;
GError *err = NULL;
int i;
+ struct a2dp_server *server;
if (!config)
goto proceed;
@@ -1107,27 +1126,36 @@ int a2dp_init(DBusConnection *conn, GKeyFile *config)
}
proceed:
- connection = dbus_connection_ref(conn);
-
- avdtp_init(config);
+ if (!connection)
+ connection = dbus_connection_ref(conn);
+
+ server = find_server(servers, src);
+ if (!server) {
+ server = g_new0(struct a2dp_server, 1);
+ if (!server)
+ return -ENOMEM;
+ avdtp_init(src, config);
+ bacpy(&server->src, src);
+ servers = g_slist_append(servers, server);
+ }
if (source) {
for (i = 0; i < sbc_srcs; i++)
- a2dp_add_sep(conn, AVDTP_SEP_TYPE_SOURCE,
+ a2dp_add_sep(server, AVDTP_SEP_TYPE_SOURCE,
A2DP_CODEC_SBC);
for (i = 0; i < mpeg12_srcs; i++)
- a2dp_add_sep(conn, AVDTP_SEP_TYPE_SOURCE,
+ a2dp_add_sep(server, AVDTP_SEP_TYPE_SOURCE,
A2DP_CODEC_MPEG12);
}
if (sink) {
for (i = 0; i < sbc_sinks; i++)
- a2dp_add_sep(conn, AVDTP_SEP_TYPE_SINK,
+ a2dp_add_sep(server, AVDTP_SEP_TYPE_SINK,
A2DP_CODEC_SBC);
for (i = 0; i < mpeg12_sinks; i++)
- a2dp_add_sep(conn, AVDTP_SEP_TYPE_SINK,
+ a2dp_add_sep(server, AVDTP_SEP_TYPE_SINK,
A2DP_CODEC_MPEG12);
}
@@ -1140,27 +1168,34 @@ static void a2dp_unregister_sep(struct a2dp_sep *sep)
g_free(sep);
}
-void a2dp_exit()
+void a2dp_unregister(const bdaddr_t *src)
{
- g_slist_foreach(sinks, (GFunc) a2dp_unregister_sep, NULL);
- g_slist_free(sinks);
- sinks = NULL;
+ struct a2dp_server *server;
- g_slist_foreach(sources, (GFunc) a2dp_unregister_sep, NULL);
- g_slist_free(sources);
- sources = NULL;
+ server = find_server(servers, src);
+ if (!server)
+ return;
- if (source_record_id) {
- remove_record_from_server(source_record_id);
- source_record_id = 0;
- }
+ g_slist_foreach(server->sinks, (GFunc) a2dp_unregister_sep, NULL);
+ g_slist_free(server->sinks);
- if (sink_record_id) {
- remove_record_from_server(sink_record_id);
- sink_record_id = 0;
- }
+ g_slist_foreach(server->sources, (GFunc) a2dp_unregister_sep, NULL);
+ g_slist_free(server->sources);
+
+ if (server->source_record_id)
+ remove_record_from_server(server->source_record_id);
+
+ if (server->sink_record_id)
+ remove_record_from_server(server->sink_record_id);
+
+ servers = g_slist_remove(servers, server);
+ g_free(server);
+
+ if (servers)
+ return;
dbus_connection_unref(connection);
+ connection = NULL;
}
gboolean a2dp_source_cancel(struct audio_device *dev, unsigned int id)
@@ -1201,6 +1236,7 @@ unsigned int a2dp_source_config(struct avdtp *session, a2dp_config_cb_t cb,
{
struct a2dp_setup_cb *cb_data;
GSList *l;
+ struct a2dp_server *server;
struct a2dp_setup *setup;
struct a2dp_sep *sep = NULL, *tmp;
struct avdtp_local_sep *lsep;
@@ -1208,6 +1244,12 @@ unsigned int a2dp_source_config(struct avdtp *session, a2dp_config_cb_t cb,
struct avdtp_service_capability *cap;
struct avdtp_media_codec_capability *codec_cap = NULL;
int posix_err;
+ bdaddr_t src;
+
+ avdtp_get_peers(session, &src, NULL);
+ server = find_server(servers, &src);
+ if (!server)
+ return 0;
for (l = caps; l != NULL; l = l->next) {
cap = l->data;
@@ -1222,7 +1264,7 @@ unsigned int a2dp_source_config(struct avdtp *session, a2dp_config_cb_t cb,
if (!codec_cap)
return 0;
- for (l = sources; l != NULL; l = l->next) {
+ for (l = server->sources; l != NULL; l = l->next) {
tmp = l->data;
if (tmp->locked)
@@ -1264,7 +1306,7 @@ unsigned int a2dp_source_config(struct avdtp *session, a2dp_config_cb_t cb,
switch (avdtp_sep_get_state(sep->sep)) {
case AVDTP_STATE_IDLE:
- for (l = sources; l != NULL; l = l->next) {
+ for (l = server->sources; l != NULL; l = l->next) {
tmp = l->data;
if (avdtp_has_stream(session, tmp->stream))
diff --git a/audio/a2dp.h b/audio/a2dp.h
index 6ec3ebc8..daa8f344 100644
--- a/audio/a2dp.h
+++ b/audio/a2dp.h
@@ -129,8 +129,8 @@ typedef void (*a2dp_stream_cb_t) (struct avdtp *session,
struct avdtp_error *err,
void *user_data);
-int a2dp_init(DBusConnection *conn, GKeyFile *config);
-void a2dp_exit(void);
+int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config);
+void a2dp_unregister(const bdaddr_t *src);
unsigned int a2dp_source_config(struct avdtp *session, a2dp_config_cb_t cb,
GSList *caps, void *user_data);
diff --git a/audio/avdtp.c b/audio/avdtp.c
index c3286bfc..b052b927 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -291,6 +291,12 @@ struct avdtp_remote_sep {
struct avdtp_stream *stream;
};
+struct avdtp_server {
+ bdaddr_t src;
+ GIOChannel *io;
+ GSList *seps;
+};
+
struct avdtp_local_sep {
avdtp_state_t state;
struct avdtp_stream *stream;
@@ -300,6 +306,7 @@ struct avdtp_local_sep {
struct avdtp_sep_ind *ind;
struct avdtp_sep_cfm *cfm;
void *user_data;
+ struct avdtp_server *server;
};
struct stream_callback {
@@ -327,11 +334,12 @@ struct avdtp_stream {
};
/* Structure describing an AVDTP connection between two devices */
+
struct avdtp {
int ref;
int free_lock;
- bdaddr_t src;
+ struct avdtp_server *server;
bdaddr_t dst;
avdtp_session_state_t last_state;
@@ -362,11 +370,7 @@ struct avdtp {
DBusPendingCall *pending_auth;
};
-static uint8_t free_seid = 1;
-static GSList *local_seps = NULL;
-
-static GIOChannel *avdtp_server = NULL;
-
+static GSList *servers = NULL;
static GSList *sessions = NULL;
static int send_request(struct avdtp *session, gboolean priority,
@@ -383,6 +387,20 @@ static void avdtp_sep_set_state(struct avdtp *session,
struct avdtp_local_sep *sep,
avdtp_state_t state);
+static struct avdtp_server *find_server(GSList *list, const bdaddr_t *src)
+{
+ GSList *l;
+
+ for (l = list; l; l = l->next) {
+ struct avdtp_server *server = l->data;
+
+ if (bacmp(&server->src, src) == 0)
+ return server;
+ }
+
+ return NULL;
+}
+
static const char *avdtp_statestr(avdtp_state_t state)
{
switch (state) {
@@ -834,11 +852,12 @@ struct avdtp *avdtp_ref(struct avdtp *session)
return session;
}
-static struct avdtp_local_sep *find_local_sep_by_seid(uint8_t seid)
+static struct avdtp_local_sep *find_local_sep_by_seid(struct avdtp_server *server,
+ uint8_t seid)
{
GSList *l;
- for (l = local_seps; l != NULL; l = g_slist_next(l)) {
+ for (l = server->seps; l != NULL; l = g_slist_next(l)) {
struct avdtp_local_sep *sep = l->data;
if (sep->info.seid == seid)
@@ -848,12 +867,14 @@ static struct avdtp_local_sep *find_local_sep_by_seid(uint8_t seid)
return NULL;
}
-static struct avdtp_local_sep *find_local_sep(uint8_t type, uint8_t media_type,
+static struct avdtp_local_sep *find_local_sep(struct avdtp_server *server,
+ uint8_t type,
+ uint8_t media_type,
uint8_t codec)
{
GSList *l;
- for (l = local_seps; l != NULL; l = g_slist_next(l)) {
+ for (l = server->seps; l != NULL; l = g_slist_next(l)) {
struct avdtp_local_sep *sep = l->data;
if (sep->info.inuse)
@@ -941,7 +962,7 @@ static gboolean avdtp_discover_cmd(struct avdtp *session,
rsp_size = sizeof(struct discover_resp);
info = rsp->seps;
- for (l = local_seps; l != NULL; l = l->next) {
+ for (l = session->server->seps; l != NULL; l = l->next) {
struct avdtp_local_sep *sep = l->data;
if (rsp_size + sizeof(struct seid_info) > session->mtu)
@@ -971,7 +992,7 @@ static gboolean avdtp_getcap_cmd(struct avdtp *session,
return FALSE;
}
- sep = find_local_sep_by_seid(req->acp_seid);
+ sep = find_local_sep_by_seid(session->server, req->acp_seid);
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1022,7 +1043,7 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session,
return FALSE;
}
- sep = find_local_sep_by_seid(req->acp_seid);
+ sep = find_local_sep_by_seid(session->server, req->acp_seid);
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1099,7 +1120,7 @@ static gboolean avdtp_open_cmd(struct avdtp *session, struct seid_req *req,
return FALSE;
}
- sep = find_local_sep_by_seid(req->acp_seid);
+ sep = find_local_sep_by_seid(session->server, req->acp_seid);
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1160,7 +1181,8 @@ static gboolean avdtp_start_cmd(struct avdtp *session, struct start_req *req,
for (i = 0; i < seid_count; i++, seid++) {
failed_seid = seid->seid;
- sep = find_local_sep_by_seid(req->first_seid.seid);
+ sep = find_local_sep_by_seid(session->server,
+ req->first_seid.seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1208,7 +1230,7 @@ static gboolean avdtp_close_cmd(struct avdtp *session, struct seid_req *req,
return FALSE;
}
- sep = find_local_sep_by_seid(req->acp_seid);
+ sep = find_local_sep_by_seid(session->server, req->acp_seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1269,7 +1291,8 @@ static gboolean avdtp_suspend_cmd(struct avdtp *session,
for (i = 0; i < seid_count; i++, seid++) {
failed_seid = seid->seid;
- sep = find_local_sep_by_seid(req->first_seid.seid);
+ sep = find_local_sep_by_seid(session->server,
+ req->first_seid.seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1317,7 +1340,7 @@ static gboolean avdtp_abort_cmd(struct avdtp *session, struct seid_req *req,
return FALSE;
}
- sep = find_local_sep_by_seid(req->acp_seid);
+ sep = find_local_sep_by_seid(session->server, req->acp_seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
@@ -1584,8 +1607,8 @@ static int l2cap_connect(struct avdtp *session)
{
int err;
- err = bt_l2cap_connect(&session->src, &session->dst, AVDTP_PSM, 0,
- l2cap_connect_cb, session);
+ err = bt_l2cap_connect(&session->server->src, &session->dst, AVDTP_PSM,
+ 0, l2cap_connect_cb, session);
if (err < 0) {
error("Connect failed. %s(%d)", strerror(-err), -err);
return err;
@@ -2130,7 +2153,7 @@ static struct avdtp *find_session(const bdaddr_t *src, const bdaddr_t *dst)
for (l = sessions; l != NULL; l = g_slist_next(l)) {
struct avdtp *s = l->data;
- if (bacmp(src, &s->src) || bacmp(dst, &s->dst))
+ if (bacmp(src, &s->server->src) || bacmp(dst, &s->dst))
continue;
return s;
@@ -2157,7 +2180,7 @@ static struct avdtp *avdtp_get_internal(const bdaddr_t *src, const bdaddr_t *dst
session = g_new0(struct avdtp, 1);
session->sock = -1;
- bacpy(&session->src, src);
+ session->server = find_server(servers, src);
bacpy(&session->dst, dst);
session->ref = 1;
session->state = AVDTP_SESSION_STATE_DISCONNECTED;
@@ -2330,7 +2353,7 @@ int avdtp_get_seps(struct avdtp *session, uint8_t acp_type, uint8_t media_type,
int_type = acp_type == AVDTP_SEP_TYPE_SINK ?
AVDTP_SEP_TYPE_SOURCE : AVDTP_SEP_TYPE_SINK;
- *lsep = find_local_sep(int_type, media_type, codec);
+ *lsep = find_local_sep(session->server, int_type, media_type, codec);
if (!*lsep)
return -EINVAL;
@@ -2630,44 +2653,54 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream)
return 0;
}
-struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
+struct avdtp_local_sep *avdtp_register_sep(const bdaddr_t *src, uint8_t type,
+ uint8_t media_type,
uint8_t codec_type,
struct avdtp_sep_ind *ind,
struct avdtp_sep_cfm *cfm,
void *user_data)
{
+ struct avdtp_server *server;
struct avdtp_local_sep *sep;
- if (free_seid > MAX_SEID)
+ server = find_server(servers, src);
+ if (!server)
+ return NULL;
+
+ if (g_slist_length(server->seps) > MAX_SEID)
return NULL;
sep = g_new0(struct avdtp_local_sep, 1);
sep->state = AVDTP_STATE_IDLE;
- sep->info.seid = free_seid++;
+ sep->info.seid = g_slist_length(server->seps) + 1;
sep->info.type = type;
sep->info.media_type = media_type;
sep->codec = codec_type;
sep->ind = ind;
sep->cfm = cfm;
sep->user_data = user_data;
+ sep->server = server;
debug("SEP %p registered: type:%d codec:%d seid:%d", sep,
sep->info.type, sep->codec, sep->info.seid);
- local_seps = g_slist_append(local_seps, sep);
+ server->seps = g_slist_append(server->seps, sep);
return sep;
}
int avdtp_unregister_sep(struct avdtp_local_sep *sep)
{
+ struct avdtp_server *server;
+
if (!sep)
return -EINVAL;
if (sep->info.inuse)
return -EBUSY;
- local_seps = g_slist_remove(local_seps, sep);
+ server = sep->server;
+ server->seps = g_slist_remove(server->seps, sep);
g_free(sep);
@@ -2684,7 +2717,8 @@ static void auth_cb(DBusError *derr, void *user_data)
error("Access denied: %s", derr->message);
if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY)) {
debug("Canceling authorization request");
- btd_cancel_authorization(&session->src, &session->dst);
+ btd_cancel_authorization(&session->server->src,
+ &session->dst);
}
connection_lost(session, -EACCES);
@@ -2771,14 +2805,14 @@ drop:
g_io_channel_unref(chan);
}
-static GIOChannel *avdtp_server_socket(gboolean master)
+static GIOChannel *avdtp_server_socket(const bdaddr_t *src, gboolean master)
{
int lm = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT;
if (master)
lm |= L2CAP_LM_MASTER;
- return bt_l2cap_listen(BDADDR_ANY, AVDTP_PSM, 0, lm, avdtp_server_cb,
+ return bt_l2cap_listen(src, AVDTP_PSM, 0, lm, avdtp_server_cb,
NULL);
}
@@ -2835,18 +2869,16 @@ avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep)
void avdtp_get_peers(struct avdtp *session, bdaddr_t *src, bdaddr_t *dst)
{
if (src)
- bacpy(src, &session->src);
+ bacpy(src, &session->server->src);
if (dst)
bacpy(dst, &session->dst);
}
-int avdtp_init(GKeyFile *config)
+int avdtp_init(const bdaddr_t *src, GKeyFile *config)
{
GError *err = NULL;
gboolean tmp, master = TRUE;
-
- if (avdtp_server)
- return 0;
+ struct avdtp_server *server;
if (config) {
tmp = g_key_file_get_boolean(config, "General",
@@ -2858,21 +2890,36 @@ int avdtp_init(GKeyFile *config)
master = tmp;
}
- avdtp_server = avdtp_server_socket(master);
- if (!avdtp_server)
+ server = g_new0(struct avdtp_server, 1);
+ if (!server)
+ return -ENOMEM;
+
+ server->io = avdtp_server_socket(src, master);
+ if (!server->io) {
+ g_free(server);
return -1;
+ }
+
+ bacpy(&server->src, src);
+
+ servers = g_slist_append(servers, server);
return 0;
}
-void avdtp_exit(void)
+void avdtp_exit(const bdaddr_t *src)
{
- if (!avdtp_server)
+ struct avdtp_server *server;
+
+ server = find_server(servers, src);
+ if (!server)
return;
- g_io_channel_close(avdtp_server);
- g_io_channel_unref(avdtp_server);
- avdtp_server = NULL;
+ servers = g_slist_remove(servers, server);
+
+ g_io_channel_close(server->io);
+ g_io_channel_unref(server->io);
+ g_free(server);
}
gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream)
diff --git a/audio/avdtp.h b/audio/avdtp.h
index de7e6e3d..0b06bd00 100644
--- a/audio/avdtp.h
+++ b/audio/avdtp.h
@@ -241,7 +241,8 @@ int avdtp_suspend(struct avdtp *session, struct avdtp_stream *stream);
int avdtp_close(struct avdtp *session, struct avdtp_stream *stream);
int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream);
-struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
+struct avdtp_local_sep *avdtp_register_sep(const bdaddr_t *src, uint8_t type,
+ uint8_t media_type,
uint8_t codec_type,
struct avdtp_sep_ind *ind,
struct avdtp_sep_cfm *cfm,
@@ -264,5 +265,5 @@ int avdtp_error_posix_errno(struct avdtp_error *err);
void avdtp_get_peers(struct avdtp *session, bdaddr_t *src, bdaddr_t *dst);
-int avdtp_init(GKeyFile *config);
-void avdtp_exit(void);
+int avdtp_init(const bdaddr_t *src, GKeyFile *config);
+void avdtp_exit(const bdaddr_t *src);
diff --git a/audio/control.c b/audio/control.c
index a1014d48..15e38c99 100644
--- a/audio/control.c
+++ b/audio/control.c
@@ -97,11 +97,7 @@
static DBusConnection *connection = NULL;
-static uint32_t tg_record_id = 0;
-static uint32_t ct_record_id = 0;
-
-static GIOChannel *avctp_server = NULL;
-
+static GSList *servers = NULL;
static GSList *sessions = NULL;
typedef enum {
@@ -150,6 +146,13 @@ struct avrcp_header {
#error "Unknown byte order"
#endif
+struct avctp_server {
+ bdaddr_t src;
+ GIOChannel *io;
+ uint32_t tg_record_id;
+ uint32_t ct_record_id;
+};
+
struct avctp {
struct audio_device *dev;
@@ -703,7 +706,7 @@ drop:
close(session->sock);
}
-static GIOChannel *avctp_server_socket(gboolean master)
+static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master)
{
GIOChannel *io;
int lm = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT;
@@ -711,7 +714,7 @@ static GIOChannel *avctp_server_socket(gboolean master)
if (master)
lm |= L2CAP_LM_MASTER;
- io = bt_l2cap_listen(BDADDR_ANY, AVCTP_PSM, 0, lm, avctp_server_cb,
+ io = bt_l2cap_listen(src, AVCTP_PSM, 0, lm, avctp_server_cb,
NULL);
if (!io) {
error("Unable to allocate new io channel");
@@ -810,14 +813,12 @@ void avrcp_disconnect(struct audio_device *dev)
control->session = NULL;
}
-int avrcp_init(DBusConnection *conn, GKeyFile *config)
+int avrcp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)
{
sdp_record_t *record;
gboolean tmp, master = TRUE;
GError *err = NULL;
-
- if (avctp_server)
- return 0;
+ struct avctp_server *server;
if (config) {
tmp = g_key_file_get_boolean(config, "General",
@@ -829,7 +830,12 @@ int avrcp_init(DBusConnection *conn, GKeyFile *config)
master = tmp;
}
- connection = dbus_connection_ref(conn);
+ server = g_new0(struct avctp_server, 1);
+ if (!server)
+ return -ENOMEM;
+
+ if (!connection)
+ connection = dbus_connection_ref(conn);
record = avrcp_tg_record();
if (!record) {
@@ -837,12 +843,12 @@ int avrcp_init(DBusConnection *conn, GKeyFile *config)
return -1;
}
- if (add_record_to_server(BDADDR_ANY, record) < 0) {
+ if (add_record_to_server(src, record) < 0) {
error("Unable to register AVRCP target service record");
sdp_record_free(record);
return -1;
}
- tg_record_id = record->handle;
+ server->tg_record_id = record->handle;
record = avrcp_ct_record();
if (!record) {
@@ -850,34 +856,61 @@ int avrcp_init(DBusConnection *conn, GKeyFile *config)
return -1;
}
- if (add_record_to_server(BDADDR_ANY, record) < 0) {
+ if (add_record_to_server(src, record) < 0) {
error("Unable to register AVRCP controller service record");
sdp_record_free(record);
return -1;
}
- ct_record_id = record->handle;
+ server->ct_record_id = record->handle;
- avctp_server = avctp_server_socket(master);
- if (!avctp_server)
+ server->io = avctp_server_socket(src, master);
+ if (!server->io) {
+ remove_record_from_server(server->ct_record_id);
+ remove_record_from_server(server->tg_record_id);
+ g_free(server);
return -1;
+ }
+
+ bacpy(&server->src, src);
+
+ servers = g_slist_append(servers, server);
return 0;
}
-void avrcp_exit(void)
+static struct avctp_server *find_server(GSList *list, const bdaddr_t *src)
{
- if (!avctp_server)
+ GSList *l;
+
+ for (l = list; l; l = l->next) {
+ struct avctp_server *server = l->data;
+
+ if (bacmp(&server->src, src) == 0)
+ return server;
+ }
+
+ return NULL;
+}
+
+void avrcp_unregister(const bdaddr_t *src)
+{
+ struct avctp_server *server;
+
+ server = find_server(servers, src);
+ if (!server)
return;
- g_io_channel_close(avctp_server);
- g_io_channel_unref(avctp_server);
- avctp_server = NULL;
+ servers = g_slist_remove(servers, server);
- remove_record_from_server(ct_record_id);
- ct_record_id = 0;
+ remove_record_from_server(server->ct_record_id);
+ remove_record_from_server(server->tg_record_id);
- remove_record_from_server(tg_record_id);
- tg_record_id = 0;
+ g_io_channel_close(server->io);
+ g_io_channel_unref(server->io);
+ g_free(server);
+
+ if (servers)
+ return;
dbus_connection_unref(connection);
connection = NULL;
diff --git a/audio/control.h b/audio/control.h
index 6475df51..163caa56 100644
--- a/audio/control.h
+++ b/audio/control.h
@@ -24,8 +24,8 @@
#define AUDIO_CONTROL_INTERFACE "org.bluez.Control"
-int avrcp_init(DBusConnection *conn, GKeyFile *config);
-void avrcp_exit(void);
+int avrcp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config);
+void avrcp_unregister(const bdaddr_t *src);
gboolean avrcp_connect(struct audio_device *dev);
void avrcp_disconnect(struct audio_device *dev);
diff --git a/audio/manager.c b/audio/manager.c
index 3aa1a5dd..deeb375c 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -831,7 +831,21 @@ static int a2dp_server_probe(struct btd_adapter *adapter)
if (!adp)
return -EINVAL;
- return a2dp_init(connection, config);
+ return a2dp_register(connection, &adp->src, config);
+}
+
+static void a2dp_server_remove(struct btd_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;
+
+ return a2dp_unregister(&adp->src);
}
static int avrcp_server_probe(struct btd_adapter *adapter)
@@ -845,7 +859,21 @@ static int avrcp_server_probe(struct btd_adapter *adapter)
if (!adp)
return -EINVAL;
- return avrcp_init(connection, config);
+ return avrcp_register(connection, &adp->src, config);
+}
+
+static void avrcp_server_remove(struct btd_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;
+
+ return avrcp_unregister(&adp->src);
}
static struct btd_device_driver audio_driver = {
@@ -872,11 +900,13 @@ static struct btd_adapter_driver gateway_server_driver = {
static struct btd_adapter_driver a2dp_server_driver = {
.name = "audio-a2dp",
.probe = a2dp_server_probe,
+ .remove = a2dp_server_remove,
};
static struct btd_adapter_driver avrcp_server_driver = {
.name = "audio-control",
.probe = avrcp_server_probe,
+ .remove = avrcp_server_remove,
};
int audio_manager_init(DBusConnection *conn, GKeyFile *conf)