mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2025-01-27 14:54:10 +08:00
Fix a2dp and avrcp drivers to not rely on BDADDR_ANY.
This commit is contained in:
parent
75b61c0a4f
commit
957d01bac7
116
audio/a2dp.c
116
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);
|
||||
if (!connection)
|
||||
connection = dbus_connection_ref(conn);
|
||||
|
||||
avdtp_init(config);
|
||||
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))
|
||||
|
@ -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);
|
||||
|
133
audio/avdtp.c
133
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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -166,7 +166,7 @@ void sdp_svcdb_set_collectable(sdp_record_t *record, int sock)
|
||||
/*
|
||||
* Add a service record to the repository
|
||||
*/
|
||||
void sdp_record_add(bdaddr_t *device, sdp_record_t *rec)
|
||||
void sdp_record_add(const bdaddr_t *device, sdp_record_t *rec)
|
||||
{
|
||||
sdp_access_t *dev;
|
||||
|
||||
|
@ -377,7 +377,7 @@ void register_device_id(const uint16_t vendor, const uint16_t product,
|
||||
update_svclass_list();
|
||||
}
|
||||
|
||||
int add_record_to_server(bdaddr_t *src, sdp_record_t *rec)
|
||||
int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)
|
||||
{
|
||||
sdp_data_t *data;
|
||||
|
||||
|
@ -68,7 +68,7 @@ void sdp_svcdb_collect_all(int sock);
|
||||
void sdp_svcdb_set_collectable(sdp_record_t *rec, int sock);
|
||||
void sdp_svcdb_collect(sdp_record_t *rec);
|
||||
sdp_record_t *sdp_record_find(uint32_t handle);
|
||||
void sdp_record_add(bdaddr_t *device, sdp_record_t *rec);
|
||||
void sdp_record_add(const bdaddr_t *device, sdp_record_t *rec);
|
||||
int sdp_record_remove(uint32_t handle);
|
||||
sdp_list_t *sdp_get_record_list(void);
|
||||
sdp_list_t *sdp_get_access_list(void);
|
||||
@ -83,7 +83,7 @@ uint32_t sdp_get_time();
|
||||
int start_sdp_server(uint16_t mtu, const char *did, uint32_t flags);
|
||||
void stop_sdp_server(void);
|
||||
|
||||
int add_record_to_server(bdaddr_t *src, sdp_record_t *rec);
|
||||
int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec);
|
||||
int remove_record_from_server(uint32_t handle);
|
||||
|
||||
typedef void (*service_classes_callback_t) (const bdaddr_t *bdaddr, uint8_t value);
|
||||
|
Loading…
Reference in New Issue
Block a user