diff --git a/android/Android.mk b/android/Android.mk
index c23dca6..4184d80 100644
--- a/android/Android.mk
+++ b/android/Android.mk
bluez/lib/bluetooth.c \
bluez/lib/hci.c \
bluez/src/shared/util.c \
+ bluez/src/shared/queue.c \
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/bluez \
diff --git a/android/Makefile.am b/android/Makefile.am
index bb8ea9e..3ea32e9 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
src/log.h src/log.c \
btio/btio.h btio/btio.c \
src/shared/util.h src/shared/util.c \
+ src/shared/queue.h src/shared/queue.c \
android/avdtp.h android/avdtp.c
android_avdtptest_CFLAGS = $(AM_CFLAGS)
android_avdtptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
diff --git a/android/a2dp.c b/android/a2dp.c
index 10f5523..f219042 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
#include "lib/sdp.h"
#include "lib/sdp_lib.h"
#include "profiles/audio/a2dp-codecs.h"
+#include "src/shared/queue.h"
#include "src/log.h"
#include "hal-msg.h"
#include "ipc-common.h"
static struct ipc *hal_ipc = NULL;
static struct ipc *audio_ipc = NULL;
+static struct queue *lseps = NULL;
+
struct a2dp_preset {
void *data;
int8_t len;
struct a2dp_endpoint *endpoint = data;
if (endpoint->sep)
- avdtp_unregister_sep(endpoint->sep);
+ avdtp_unregister_sep(lseps, endpoint->sep);
if (endpoint->caps)
preset_free(endpoint->caps);
gpointer user_data)
{
struct a2dp_device *dev = user_data;
+ struct avdtp *session;
uint16_t imtu, omtu;
GError *gerr = NULL;
int fd;
fd = g_io_channel_unix_get_fd(chan);
/* FIXME: Add proper version */
- dev->session = avdtp_new(fd, imtu, omtu, 0x0100);
- if (!dev->session)
+ session = avdtp_new(fd, imtu, omtu, 0x0100, lseps);
+ if (!session)
goto failed;
+ dev->session = session;
+
avdtp_add_disconnect_cb(dev->session, disconnect_cb, dev);
/* Proceed to stream setup if initiator */
endpoint = g_new0(struct a2dp_endpoint, 1);
endpoint->id = g_slist_length(endpoints) + 1;
endpoint->codec = codec;
- endpoint->sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE,
+ endpoint->sep = avdtp_register_sep(lseps, AVDTP_SEP_TYPE_SOURCE,
AVDTP_MEDIA_TYPE_AUDIO,
codec, FALSE, &sep_ind,
&sep_cfm, endpoint);
ipc_cleanup(audio_ipc);
audio_ipc = NULL;
+
+ queue_destroy(lseps, NULL);
}
static bool bt_audio_register(ipc_disconnect_cb disconnect)
bacpy(&adapter_addr, addr);
+ lseps = queue_new();
+
server = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
BT_IO_OPT_PSM, AVDTP_PSM,
diff --git a/android/avdtp.c b/android/avdtp.c
index b290feb..35bc548 100644
--- a/android/avdtp.c
+++ b/android/avdtp.c
#include "lib/bluetooth.h"
#include "src/log.h"
#include "src/shared/util.h"
+#include "src/shared/queue.h"
#include "avdtp.h"
#include "../profiles/audio/a2dp-codecs.h"
guint io_id;
GSList *seps; /* Elements of type struct avdtp_remote_sep * */
+ struct queue *lseps; /* Elements of type struct avdtp_local_sep * */
GSList *streams; /* Elements of type struct avdtp_stream * */
bool shutdown;
};
-static GSList *lseps = NULL;
-
static int send_request(struct avdtp *session, gboolean priority,
struct avdtp_stream *stream, uint8_t signal_id,
void *buffer, size_t size);
g_slist_free_full(session->seps, sep_free);
g_slist_free_full(session->disconnect, g_free);
+ /* Free copy of the SEP list */
+ session->lseps = NULL;
+
g_free(session->buf);
g_free(session);
return session;
}
-static struct avdtp_local_sep *find_local_sep_by_seid(uint8_t seid)
+static bool match_by_seid(const void *data, const void *user_data)
{
- GSList *l;
+ const struct avdtp_local_sep *sep = data;
+ uint8_t seid = PTR_TO_UINT(user_data);
- for (l = lseps; l != NULL; l = g_slist_next(l)) {
- struct avdtp_local_sep *sep = l->data;
-
- if (sep->info.seid == seid)
- return sep;
- }
+ return sep->info.seid == seid;
+}
- return NULL;
+static struct avdtp_local_sep *find_local_sep_by_seid(struct avdtp *session,
+ uint8_t seid)
+{
+ return queue_find(session->lseps, match_by_seid, INT_TO_PTR(seid));
}
struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
signal_id, NULL, 0);
}
+static void copy_seps(void *data, void *user_data)
+{
+ struct avdtp_local_sep *sep = data;
+ struct seid_info **p = user_data;
+
+ memcpy(*p, &sep->info, sizeof(struct seid_info));
+ *p = *p + 1;
+}
+
static gboolean avdtp_discover_cmd(struct avdtp *session, uint8_t transaction,
void *buf, int size)
{
- GSList *l;
- unsigned int rsp_size, sep_count, i;
- struct seid_info *seps;
+ unsigned int rsp_size, sep_count;
+ struct seid_info *seps, *p;
gboolean ret;
- sep_count = g_slist_length(lseps);
+ sep_count = queue_length(session->lseps);
if (sep_count == 0) {
uint8_t err = AVDTP_NOT_SUPPORTED_COMMAND;
rsp_size = sep_count * sizeof(struct seid_info);
seps = g_new0(struct seid_info, sep_count);
+ p = seps;
- for (l = lseps, i = 0; l != NULL; l = l->next, i++) {
- struct avdtp_local_sep *sep = l->data;
-
- memcpy(&seps[i], &sep->info, sizeof(struct seid_info));
- }
+ queue_foreach(session->lseps, copy_seps, &p);
ret = avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
AVDTP_DISCOVER, seps, rsp_size);
goto failed;
}
- sep = find_local_sep_by_seid(req->acp_seid);
+ sep = find_local_sep_by_seid(session, req->acp_seid);
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
return FALSE;
}
- sep = find_local_sep_by_seid(req->acp_seid);
+ sep = find_local_sep_by_seid(session, req->acp_seid);
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
memset(buf, 0, sizeof(buf));
- sep = find_local_sep_by_seid(req->acp_seid);
+ sep = find_local_sep_by_seid(session, req->acp_seid);
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
return FALSE;
}
- sep = find_local_sep_by_seid(req->acp_seid);
+ sep = find_local_sep_by_seid(session, req->acp_seid);
if (!sep) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
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, req->first_seid.seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
return FALSE;
}
- sep = find_local_sep_by_seid(req->acp_seid);
+ sep = find_local_sep_by_seid(session, req->acp_seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
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, req->first_seid.seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
return FALSE;
}
- sep = find_local_sep_by_seid(req->acp_seid);
+ sep = find_local_sep_by_seid(session, req->acp_seid);
if (!sep || !sep->stream)
return TRUE;
return FALSE;
}
- sep = find_local_sep_by_seid(req->acp_seid);
+ sep = find_local_sep_by_seid(session, req->acp_seid);
if (!sep || !sep->stream) {
err = AVDTP_BAD_ACP_SEID;
goto failed;
return err;
}
-struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version)
+struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version,
+ struct queue *lseps)
{
struct avdtp *session;
GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
int new_fd;
+ if (!lseps)
+ return NULL;
+
new_fd = dup(fd);
if (new_fd < 0) {
error("dup(): %s (%d)", strerror(errno), errno);
(GIOFunc) session_cb, session,
NULL);
+ session->lseps = lseps;
+
return avdtp_ref(session);
}
&req, sizeof(req));
}
-struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
+struct avdtp_local_sep *avdtp_register_sep(struct queue *lseps, uint8_t type,
+ uint8_t media_type,
uint8_t codec_type,
gboolean delay_reporting,
struct avdtp_sep_ind *ind,
if (!seid)
return NULL;
- if (g_slist_length(lseps) > MAX_SEID)
+ if (queue_length(lseps) > MAX_SEID)
return NULL;
sep = g_new0(struct avdtp_local_sep, 1);
DBG("SEP %p registered: type:%d codec:%d seid:%d", sep,
sep->info.type, sep->codec, sep->info.seid);
- lseps = g_slist_append(lseps, sep);
+
+ if (!queue_push_tail(lseps, sep)) {
+ g_free(sep);
+ return NULL;
+ }
return sep;
}
sep->vndcodec_codec = codec_id;
}
-int avdtp_unregister_sep(struct avdtp_local_sep *sep)
+int avdtp_unregister_sep(struct queue *lseps, struct avdtp_local_sep *sep)
{
if (!sep)
return -EINVAL;
- lseps = g_slist_remove(lseps, sep);
-
if (sep->stream)
release_stream(sep->stream, sep->stream->session);
sep->info.type, sep->codec, sep->info.seid);
util_clear_uid(&seids, sep->info.seid);
+ queue_remove(lseps, sep);
g_free(sep);
return 0;
diff --git a/android/avdtp.h b/android/avdtp.h
index d5335e4..07516a8 100644
--- a/android/avdtp.h
+++ b/android/avdtp.h
struct avdtp_error *err, void *user_data);
typedef void (*avdtp_disconnect_cb_t) (void *user_data);
-struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version);
+struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version,
+ struct queue *lseps);
unsigned int avdtp_add_disconnect_cb(struct avdtp *session,
avdtp_disconnect_cb_t cb,
int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
uint16_t delay);
-struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
+struct avdtp_local_sep *avdtp_register_sep(struct queue *lseps, uint8_t type,
+ uint8_t media_type,
uint8_t codec_type,
gboolean delay_reporting,
struct avdtp_sep_ind *ind,
struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
struct avdtp_local_sep *lsep);
-int avdtp_unregister_sep(struct avdtp_local_sep *sep);
+int avdtp_unregister_sep(struct queue *lseps, struct avdtp_local_sep *sep);
avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep);
diff --git a/android/avdtptest.c b/android/avdtptest.c
index ce39519..6529423 100644
--- a/android/avdtptest.c
+++ b/android/avdtptest.c
#include "src/shared/util.h"
#include "btio/btio.h"
+#include "src/shared/queue.h"
#include "avdtp.h"
static GMainLoop *mainloop = NULL;
static guint media_player = 0;
static guint media_recorder = 0;
static guint idle_id = 0;
+static struct queue *lseps = NULL;
static bool fragment = false;
return;
}
- avdtp = avdtp_new(fd, imtu, omtu, version);
+ avdtp = avdtp_new(fd, imtu, omtu, version, lseps);
if (!avdtp) {
printf("Failed to create avdtp instance\n");
g_main_loop_quit(mainloop);
}
}
- local_sep = avdtp_register_sep(dev_role, AVDTP_MEDIA_TYPE_AUDIO,
+ local_sep = avdtp_register_sep(lseps, dev_role, AVDTP_MEDIA_TYPE_AUDIO,
0x00, TRUE, &sep_ind, &sep_cfm, NULL);
if (!local_sep) {
printf("Failed to register sep\n");
exit(0);
}
+ queue_push_tail(lseps, local_sep);
+
if (!bacmp(&dst, BDADDR_ANY)) {
printf("Listening...\n");
io = do_listen(&err);
printf("Done\n");
+ queue_destroy(lseps, NULL);
+
avdtp_unref(avdtp);
avdtp = NULL;
diff --git a/unit/test-avdtp.c b/unit/test-avdtp.c
index 34820d1..a293a1d 100644
--- a/unit/test-avdtp.c
+++ b/unit/test-avdtp.c
#include <glib.h>
#include "src/shared/util.h"
+#include "src/shared/queue.h"
#include "src/log.h"
#include "android/avdtp.h"
#define MAX_SEID 0x3E
-GSList *lseps = NULL;
-
struct test_pdu {
bool valid;
bool fragmented;
struct avdtp *session;
struct avdtp_local_sep *sep;
struct avdtp_stream *stream;
+ struct queue *lseps;
guint source;
guint process;
int fd;
err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
g_assert(err == 0);
- context->session = avdtp_new(sv[0], imtu, omtu, version);
+ context->lseps = queue_new();
+ g_assert(context->lseps);
+
+ context->session = avdtp_new(sv[0], imtu, omtu, version,
+ context->lseps);
g_assert(context->session != NULL);
channel = g_io_channel_unix_new(sv[1]);
struct context *context = create_context(0x0100, data);
struct avdtp_local_sep *sep;
- sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE, AVDTP_MEDIA_TYPE_AUDIO,
+ sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SOURCE,
+ AVDTP_MEDIA_TYPE_AUDIO,
0x00, FALSE, &sep_ind, &sep_cfm,
context);
execute_context(context);
- avdtp_unregister_sep(sep);
+ avdtp_unregister_sep(context->lseps, sep);
+ queue_destroy(context->lseps, NULL);
}
static void test_server_1_3(gconstpointer data)
struct context *context = create_context(0x0103, data);
struct avdtp_local_sep *sep;
- sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE, AVDTP_MEDIA_TYPE_AUDIO,
+ sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SOURCE,
+ AVDTP_MEDIA_TYPE_AUDIO,
0x00, TRUE, &sep_ind, NULL, context);
g_idle_add(send_pdu, context);
execute_context(context);
- avdtp_unregister_sep(sep);
+ avdtp_unregister_sep(context->lseps, sep);
+ queue_destroy(context->lseps, NULL);
}
static void test_server_1_3_sink(gconstpointer data)
struct context *context = create_context(0x0103, data);
struct avdtp_local_sep *sep;
- sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
+ sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
+ AVDTP_MEDIA_TYPE_AUDIO,
0x00, TRUE, &sep_ind, NULL, context);
g_idle_add(send_pdu, context);
execute_context(context);
- avdtp_unregister_sep(sep);
+ avdtp_unregister_sep(context->lseps, sep);
+ queue_destroy(context->lseps, NULL);
}
static void test_server_0_sep(gconstpointer data)
{
struct avdtp_local_sep *sep = data;
- avdtp_unregister_sep(sep);
+ /* Removed from the queue by caller */
+ avdtp_unregister_sep(NULL, sep);
}
static void test_server_seid(gconstpointer data)
unsigned int i;
for (i = 0; i < sizeof(int) * 8; i++) {
- sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK,
+ sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
AVDTP_MEDIA_TYPE_AUDIO,
0x00, TRUE, &sep_ind, NULL,
context);
g_assert(sep);
-
- lseps = g_slist_append(lseps, sep);
}
/* Now add (MAX_SEID + 1) SEP -> it shall fail */
- sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK,
+ sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
AVDTP_MEDIA_TYPE_AUDIO,
0x00, TRUE, &sep_ind, NULL,
context);
g_assert(!sep);
/* Remove all SEPs */
- g_slist_free_full(lseps, unregister_sep);
- lseps = NULL;
+ queue_destroy(context->lseps, unregister_sep);
}
static void test_server_seid_duplicate(gconstpointer data)
int i;
for (i = 0; i < 2; i++) {
- sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK,
+ sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
AVDTP_MEDIA_TYPE_AUDIO,
0x00, TRUE, &sep_ind, NULL,
context);
g_assert(sep);
-
- lseps = g_slist_append(lseps, sep);
}
/* Remove 1st element */
- sep = g_slist_nth_data(lseps, 0);
- lseps = g_slist_remove(lseps, sep);
- avdtp_unregister_sep(sep);
+ sep = queue_peek_head(context->lseps);
+ g_assert(sep);
+
+ avdtp_unregister_sep(context->lseps, sep);
/* Now register new element */
- sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK,
+ sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
AVDTP_MEDIA_TYPE_AUDIO,
0x00, TRUE, &sep_ind, NULL,
context);
g_assert(sep);
- lseps = g_slist_append(lseps, sep);
- /* Check SEID ids */
+ /* Check SEID ids with DISCOVER */
g_idle_add(send_pdu, context);
execute_context(context);
/* Remove all SEPs */
- g_slist_free_full(lseps, unregister_sep);
- lseps = NULL;
+ queue_destroy(context->lseps, unregister_sep);
}
static gboolean sep_getcap_ind_frg(struct avdtp *session,
struct context *context = context_new(0x0100, 48, 48, data);
struct avdtp_local_sep *sep;
- sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE, AVDTP_MEDIA_TYPE_AUDIO,
+ sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SOURCE,
+ AVDTP_MEDIA_TYPE_AUDIO,
0x00, TRUE, &sep_ind_frg,
NULL, context);
execute_context(context);
- avdtp_unregister_sep(sep);
+ avdtp_unregister_sep(context->lseps, sep);
+ queue_destroy(context->lseps, NULL);
}
static void discover_cb(struct avdtp *session, GSList *seps,
struct context *context = create_context(0x0100, data);
struct avdtp_local_sep *sep;
- sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
- 0x00, FALSE, NULL, &sep_cfm,
- context);
+ sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
+ AVDTP_MEDIA_TYPE_AUDIO,
+ 0x00, FALSE, NULL, &sep_cfm, context);
+
context->sep = sep;
avdtp_discover(context->session, discover_cb, context);
execute_context(context);
- avdtp_unregister_sep(sep);
+ avdtp_unregister_sep(context->lseps, sep);
+ queue_destroy(context->lseps, NULL);
}
static void test_client_1_3(gconstpointer data)
struct context *context = create_context(0x0103, data);
struct avdtp_local_sep *sep;
- sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
- 0x00, TRUE, NULL, &sep_cfm,
- context);
+ sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
+ AVDTP_MEDIA_TYPE_AUDIO,
+ 0x00, TRUE, NULL, &sep_cfm, context);
+
context->sep = sep;
avdtp_discover(context->session, discover_cb, context);
execute_context(context);
- avdtp_unregister_sep(sep);
+ avdtp_unregister_sep(context->lseps, sep);
+ queue_destroy(context->lseps, NULL);
}
static void test_client_frg(gconstpointer data)
struct context *context = context_new(0x0100, 48, 48, data);
struct avdtp_local_sep *sep;
- sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
- 0x00, TRUE, NULL, &sep_cfm,
- context);
+ sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
+ AVDTP_MEDIA_TYPE_AUDIO,
+ 0x00, TRUE, NULL, &sep_cfm, context);
+
context->sep = sep;
avdtp_discover(context->session, discover_cb, context);
execute_context(context);
- avdtp_unregister_sep(sep);
+ avdtp_unregister_sep(context->lseps, sep);
+ queue_destroy(context->lseps, NULL);
}
int main(int argc, char *argv[])