All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ 1/6] Initial VDP implementation
@ 2011-08-16 13:43 Prasad Bhat
  2011-08-16 13:43 ` [PATCH BlueZ 2/6] Implementation of video-sink for VDP Prasad Bhat
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Prasad Bhat @ 2011-08-16 13:43 UTC (permalink / raw)
  To: linux-bluetooth

---
 Makefile.am |    1 +
 audio/vdp.c | 2026 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 audio/vdp.h |  112 ++++
 3 files changed, 2139 insertions(+), 0 deletions(-)
 create mode 100644 audio/vdp.c
 create mode 100644 audio/vdp.h

diff --git a/Makefile.am b/Makefile.am
index 3c8ab40..f1c9003 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -141,6 +141,7 @@ builtin_sources += audio/main.c \
 			audio/source.h audio/source.c \
 			audio/sink.h audio/sink.c \
 			audio/a2dp.h audio/a2dp.c \
+			audio/vdp.h audio/vdp.c \
 			audio/avdtp.h audio/avdtp.c \
 			audio/ipc.h audio/ipc.c \
 			audio/unix.h audio/unix.c \
diff --git a/audio/vdp.c b/audio/vdp.c
new file mode 100644
index 0000000..58db8ba
--- /dev/null
+++ b/audio/vdp.c
@@ -0,0 +1,2026 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011 Prasad Bhat <prasadbhat22@gmail.com>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include <dbus/dbus.h>
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "log.h"
+#include "device.h"
+#include "manager.h"
+#include "avdtp.h"
+#include "video-sink.h"
+#include "video-source.h"
+#include "unix.h"
+#include "media.h"
+#include "vdp.h"
+#include "sdpd.h"
+
+#define RECONFIGURE_TIMEOUT 500
+#define SUSPEND_TIMEOUT 5
+
+struct vdp_sep {
+	struct vdp_server *server;
+	struct vdp_endpoint *endpoint;
+	uint8_t type;
+	uint8_t codec;
+	struct avdtp_local_sep *lsep;
+	struct avdtp *session;
+	struct avdtp_stream *stream;
+	guint suspend_timer;
+	gboolean delay_reporting;
+	gboolean locked;
+	gboolean suspending;
+	gboolean starting;
+	void *user_data;
+	GDestroyNotify destroy;
+};
+
+struct vdp_setup_cb {
+	struct vdp_setup *setup;
+	vdp_select_cb_t select_cb;
+	vdp_config_cb_t config_cb;
+	vdp_stream_cb_t resume_cb;
+	vdp_stream_cb_t suspend_cb;
+	guint source_id;
+	void *user_data;
+	unsigned int id;
+};
+
+struct vdp_setup {
+	struct audio_device *dev;
+	struct avdtp *session;
+	struct vdp_sep *sep;
+	struct avdtp_remote_sep *rsep;
+	struct avdtp_stream *stream;
+	struct avdtp_error *err;
+	avdtp_set_configuration_cb setconf_cb;
+	GSList *caps;
+	gboolean reconfigure;
+	gboolean start;
+	GSList *cb;
+	int ref;
+};
+
+static DBusConnection *connection = NULL;
+
+struct vdp_server {
+	bdaddr_t src;
+	GSList *sinks;
+	GSList *sources;
+	uint32_t source_record_id;
+	uint32_t sink_record_id;
+	uint16_t version;
+	gboolean sink_enabled;
+	gboolean source_enabled;
+};
+
+static GSList *servers = NULL;
+static GSList *setups = NULL;
+static unsigned int cb_id = 0;
+
+static struct vdp_setup *setup_ref(struct vdp_setup *setup)
+{
+	setup->ref++;
+
+	DBG("%p: ref=%d", setup, setup->ref);
+
+	return setup;
+}
+
+static struct audio_device *vdp_get_dev(struct avdtp *session)
+{
+	bdaddr_t src, dst;
+
+	avdtp_get_peers(session, &src, &dst);
+
+	return manager_find_device(NULL, &src, &dst, NULL, FALSE);
+}
+
+static struct vdp_setup *setup_new(struct avdtp *session)
+{
+	struct audio_device *dev;
+	struct vdp_setup *setup;
+
+	dev = vdp_get_dev(session);
+	if (!dev) {
+		error("Unable to create setup");
+		return NULL;
+	}
+
+	setup = g_new0(struct vdp_setup, 1);
+	setup->session = avdtp_ref(session);
+	setup->dev = vdp_get_dev(session);
+	setups = g_slist_append(setups, setup);
+
+	return setup;
+}
+
+static void setup_free(struct vdp_setup *s)
+{
+	DBG("%p", s);
+
+	setups = g_slist_remove(setups, s);
+	if (s->session)
+		avdtp_unref(s->session);
+	g_slist_foreach(s->cb, (GFunc) g_free, NULL);
+	g_slist_free(s->cb);
+	g_slist_foreach(s->caps, (GFunc) g_free, NULL);
+	g_slist_free(s->caps);
+	g_free(s);
+}
+
+static void setup_unref(struct vdp_setup *setup)
+{
+	setup->ref--;
+
+	DBG("%p: ref=%d", setup, setup->ref);
+
+	if (setup->ref > 0)
+		return;
+
+	setup_free(setup);
+}
+
+static struct vdp_setup_cb *setup_cb_new(struct vdp_setup *setup)
+{
+	struct vdp_setup_cb *cb;
+
+	cb = g_new0(struct vdp_setup_cb, 1);
+	cb->setup = setup;
+	cb->id = ++cb_id;
+
+	setup->cb = g_slist_append(setup->cb, cb);
+	return cb;
+}
+
+static void setup_cb_free(struct vdp_setup_cb *cb)
+{
+	struct vdp_setup *setup = cb->setup;
+
+	DBG("");
+	
+	if (cb->source_id)
+		g_source_remove(cb->source_id);
+
+	setup->cb = g_slist_remove(setup->cb, cb);
+	setup_unref(cb->setup);
+	g_free(cb);
+}
+
+static void finalize_setup_errno(struct vdp_setup *s, int err,
+					GSourceFunc cb1, ...)
+{
+	GSourceFunc finalize;
+	va_list args;
+	struct avdtp_error avdtp_err;
+
+	DBG("");
+	
+	if (err < 0) {
+		avdtp_error_init(&avdtp_err, AVDTP_ERRNO, -err);
+		s->err = &avdtp_err;
+	}
+
+	va_start(args, cb1);
+	finalize = cb1;
+	setup_ref(s);
+	while (finalize != NULL) {
+		finalize(s);
+		finalize = va_arg(args, GSourceFunc);
+	}
+	setup_unref(s);
+	va_end(args);
+}
+
+static gboolean finalize_config(gpointer data)
+{
+	struct vdp_setup *s = data;
+	GSList *l;
+	struct avdtp_stream *stream = s->err ? NULL : s->stream;
+
+	DBG("");
+	
+	for (l = s->cb; l != NULL; ) {
+		struct vdp_setup_cb *cb = l->data;
+
+		l = l->next;
+
+		if (!cb->config_cb)
+			continue;
+
+		cb->config_cb(s->session, s->sep, stream, s->err,
+							cb->user_data);
+		setup_cb_free(cb);
+	}
+
+	return FALSE;
+}
+
+static gboolean finalize_resume(gpointer data)
+{
+	struct vdp_setup *s = data;
+	GSList *l;
+	
+	DBG("");
+
+	for (l = s->cb; l != NULL; ) {
+		struct vdp_setup_cb *cb = l->data;
+
+		l = l->next;
+
+		if (!cb->resume_cb)
+			continue;
+
+		cb->resume_cb(s->session, s->err, cb->user_data);
+		setup_cb_free(cb);
+	}
+
+	return FALSE;
+}
+
+static gboolean finalize_suspend(gpointer data)
+{
+	struct vdp_setup *s = data;
+	GSList *l;
+	
+	DBG("");
+
+	for (l = s->cb; l != NULL; ) {
+		struct vdp_setup_cb *cb = l->data;
+
+		l = l->next;
+
+		if (!cb->suspend_cb)
+			continue;
+
+		cb->suspend_cb(s->session, s->err, cb->user_data);
+		setup_cb_free(cb);
+	}
+
+	return FALSE;
+}
+
+static void finalize_select(struct vdp_setup *s)
+{
+	GSList *l;
+
+	DBG("");
+	
+	for (l = s->cb; l != NULL; ) {
+		struct vdp_setup_cb *cb = l->data;
+
+		l = l->next;
+
+		if (!cb->select_cb)
+			continue;
+
+		cb->select_cb(s->session, s->sep, s->caps, cb->user_data);
+		setup_cb_free(cb);
+	}
+}
+
+static struct vdp_setup *find_setup_by_session(struct avdtp *session)
+{
+	GSList *l;
+
+	for (l = setups; l != NULL; l = l->next) {
+		struct vdp_setup *setup = l->data;
+
+		if (setup->session == session)
+			return setup;
+	}
+
+	return NULL;
+}
+
+static struct vdp_setup *vdp_setup_get(struct avdtp *session)
+{
+	struct vdp_setup *setup;
+
+	setup = find_setup_by_session(session);
+	if (!setup) {
+		setup = setup_new(session);
+		if (!setup)
+			return NULL;
+	}
+
+	return setup_ref(setup);
+}
+
+static struct vdp_setup *find_setup_by_dev(struct audio_device *dev)
+{
+	GSList *l;
+
+	for (l = setups; l != NULL; l = l->next) {
+		struct vdp_setup *setup = l->data;
+
+		if (setup->dev == dev)
+			return setup;
+	}
+
+	return NULL;
+}
+
+static void stream_state_changed(struct avdtp_stream *stream,
+					avdtp_state_t old_state,
+					avdtp_state_t new_state,
+					struct avdtp_error *err,
+					void *user_data)
+{
+	struct vdp_sep *sep = user_data;
+
+	if (new_state != AVDTP_STATE_IDLE)
+		return;
+
+	if (sep->suspend_timer) {
+		g_source_remove(sep->suspend_timer);
+		sep->suspend_timer = 0;
+	}
+
+	if (sep->session) {
+		avdtp_unref(sep->session);
+		sep->session = NULL;
+	}
+
+	sep->stream = NULL;
+
+	if (sep->endpoint && sep->endpoint->clear_configuration)
+		sep->endpoint->clear_configuration(sep, sep->user_data);
+}
+
+static gboolean auto_config(gpointer data)
+{
+	struct vdp_setup *setup = data;
+	struct avdtp_error *err = NULL;
+	
+	DBG("");
+
+	/* Check if configuration was aborted */
+	if (setup->sep->stream == NULL)
+		return FALSE;
+
+	if (setup->err != NULL) {
+		err = setup->err;
+		goto done;
+	}
+
+	avdtp_stream_add_cb(setup->session, setup->stream,
+				stream_state_changed, setup->sep);
+
+done:
+	if (setup->setconf_cb)
+		setup->setconf_cb(setup->session, setup->stream, setup->err);
+
+	finalize_config(setup);
+
+	if (err)
+		g_free(err);
+
+	setup_unref(setup);
+
+	return FALSE;
+}
+
+static struct vdp_server *find_server(GSList *list, const bdaddr_t *src)
+{
+
+	for (; list; list = list->next) {
+		struct vdp_server *server = list->data;
+
+		if (bacmp(&server->src, src) == 0)
+			return server;
+	}
+	DBG("find server no server found");
+	return NULL;
+}
+
+gboolean vdp_sep_get_lock(struct vdp_sep *sep)
+{
+	return sep->locked;
+}
+
+static void endpoint_open_cb(struct vdp_sep *sep, guint setup_id,
+								gboolean ret)
+{
+	struct vdp_setup *setup = GUINT_TO_POINTER(setup_id);
+	int err;
+
+	if (ret == FALSE) {
+		setup->stream = NULL;
+		finalize_setup_errno(setup, -EPERM, finalize_config, NULL);
+		return;
+	}
+
+	err = avdtp_open(setup->session, setup->stream);
+	if (err == 0)
+		return;
+
+	error("Error on avdtp_open %s (%d)", strerror(-err), -err);
+	setup->stream = NULL;
+	finalize_setup_errno(setup, err, finalize_config, NULL);
+}
+
+unsigned int vdp_config(struct avdtp *session, struct vdp_sep *sep,
+				vdp_config_cb_t cb, GSList *caps,
+				void *user_data)
+{
+	struct vdp_setup_cb *cb_data;
+	GSList *l;
+	struct vdp_server *server;
+	struct vdp_setup *setup;
+	struct vdp_sep *tmp;
+	struct avdtp_service_capability *cap;
+	struct avdtp_media_codec_capability *codec_cap = NULL;
+	int posix_err;
+	bdaddr_t src;
+
+	DBG("");
+	
+	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;
+
+		if (cap->category != AVDTP_MEDIA_CODEC)
+			continue;
+
+		codec_cap = (void *) cap->data;
+		break;
+	}
+
+	if (!codec_cap)
+		return 0;
+
+	if (sep->codec != codec_cap->media_codec_type)
+		return 0;
+
+	DBG("vdp_config: selected SEP %p", sep->lsep);
+
+	setup = vdp_setup_get(session);
+	if (!setup)
+		return 0;
+
+	cb_data = setup_cb_new(setup);
+	cb_data->config_cb = cb;
+	cb_data->user_data = user_data;
+
+	setup->sep = sep;
+	setup->stream = sep->stream;
+
+	/* Copy given caps if they are different than current caps */
+	if (setup->caps != caps) {
+		g_slist_foreach(setup->caps, (GFunc) g_free, NULL);
+		g_slist_free(setup->caps);
+		setup->caps = g_slist_copy(caps);
+	}
+
+	switch (avdtp_sep_get_state(sep->lsep)) {
+	case AVDTP_STATE_IDLE:
+		if (sep->type == AVDTP_SEP_TYPE_SOURCE)
+			l = server->sources;
+		else
+			l = server->sinks;
+
+		for (; l != NULL; l = l->next) {
+			tmp = l->data;
+			if (avdtp_has_stream(session, tmp->stream))
+				break;
+		}
+
+		if (l != NULL) {
+			if (vdp_sep_get_lock(tmp))
+				goto failed;
+			setup->reconfigure = TRUE;
+			if (avdtp_close(session, tmp->stream, FALSE) < 0) {
+				error("avdtp_close failed");
+				goto failed;
+			}
+			break;
+		}
+
+		setup->rsep = avdtp_find_remote_sep(session, sep->lsep);
+		if (setup->rsep == NULL) {
+			error("No matching ACP and INT SEPs found");
+			goto failed;
+		}
+
+		posix_err = avdtp_set_configuration(session, setup->rsep,
+							sep->lsep, caps,
+							&setup->stream);
+		if (posix_err < 0) {
+			error("avdtp_set_configuration: %s",
+				strerror(-posix_err));
+			goto failed;
+		}
+		break;
+	case AVDTP_STATE_OPEN:
+	case AVDTP_STATE_STREAMING:
+		if (avdtp_stream_has_capabilities(setup->stream, caps)) {
+			DBG("Configuration match: resuming");
+			cb_data->source_id = g_idle_add(finalize_config,
+								setup);
+		} else if (!setup->reconfigure) {
+			setup->reconfigure = TRUE;
+			if (avdtp_close(session, sep->stream, FALSE) < 0) {
+				error("avdtp_close failed");
+				goto failed;
+			}
+		}
+		break;
+	default:
+		error("SEP in bad state for requesting a new stream");
+		goto failed;
+	}
+
+	return cb_data->id;
+
+failed:
+	setup_cb_free(cb_data);
+	return 0;
+}
+
+static struct vdp_sep *vdp_find_sep(struct avdtp *session, GSList *list,
+                                        const char *sender)
+{
+	for (; list; list = list->next) {
+		struct vdp_sep *sep = list->data;
+
+		/* Use sender's endpoint if available */
+		if (sender) {
+			const char *name;
+
+			if (sep->endpoint == NULL)
+				continue;
+
+			name = sep->endpoint->get_name(sep, sep->user_data);
+			if (g_strcmp0(sender, name) != 0)
+				continue;
+		}
+
+		if (avdtp_find_remote_sep(session, sep->lsep) == NULL)
+			continue;
+
+		return sep;
+	}
+
+	return NULL;
+}
+
+
+static struct vdp_sep *vdp_select_sep(struct avdtp *session, uint8_t type,
+					const char *sender)
+{
+	struct vdp_server *server;
+	struct vdp_sep *sep;
+	GSList *l;
+	bdaddr_t src;
+
+	avdtp_get_peers(session, &src, NULL);
+	server = find_server(servers, &src);
+	if (!server)
+		return NULL;
+
+	l = type == AVDTP_SEP_TYPE_SINK ? server->sources : server->sinks;
+
+	/* Check sender's seps first */
+	sep = vdp_find_sep(session, l, sender);
+	if (sep != NULL)
+		return sep;
+
+	return vdp_find_sep(session, l, NULL);
+}
+
+static gboolean select_h263_params(struct h263_baseline_codec_cap *cap,
+					struct h263_baseline_codec_cap *supported)
+{
+	memset(cap, 0, sizeof(struct h263_baseline_codec_cap));
+
+	cap->cap.media_type = AVDTP_MEDIA_TYPE_VIDEO;
+	cap->cap.media_codec_type = VDP_CODEC_H263_BASELINE;
+
+	if (supported->level & H263_LEVEL_10)
+		cap->level = H263_LEVEL_10;
+	else {
+		error("No supported level");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+static gboolean select_capabilities(struct avdtp *session,
+					struct avdtp_remote_sep *rsep,
+					GSList **caps)
+{
+	struct avdtp_service_capability *media_transport, *media_codec;
+	struct h263_baseline_codec_cap h263_cap;
+
+	media_codec = avdtp_get_codec(rsep);
+	if (!media_codec)
+		return FALSE;
+
+	select_h263_params(&h263_cap, (struct h263_baseline_codec_cap *) media_codec->data);
+
+	media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+						NULL, 0);
+
+	*caps = g_slist_append(*caps, media_transport);
+
+	media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &h263_cap,
+						sizeof(h263_cap));
+
+	*caps = g_slist_append(*caps, media_codec);
+
+	if (avdtp_get_delay_reporting(rsep)) {
+		struct avdtp_service_capability *delay_reporting;
+		delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
+								NULL, 0);
+		*caps = g_slist_append(*caps, delay_reporting);
+	}
+
+	return TRUE;
+}
+
+static void select_cb(struct vdp_sep *sep, guint setup_id, void *ret,
+								int size)
+{
+	struct vdp_setup *setup = GUINT_TO_POINTER(setup_id);
+	struct avdtp_service_capability *media_transport, *media_codec;
+	struct avdtp_media_codec_capability *cap;
+
+	if (size < 0) {
+		DBG("Endpoint replied an invalid configuration");
+		goto done;
+	}
+
+	media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+						NULL, 0);
+
+	setup->caps = g_slist_append(setup->caps, media_transport);
+
+	cap = g_malloc0(sizeof(*cap) + size);
+	cap->media_type = AVDTP_MEDIA_TYPE_VIDEO;
+	cap->media_codec_type = setup->sep->codec;
+	memcpy(cap->data, ret, size);
+
+	media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, cap,
+						sizeof(*cap) + size);
+
+	setup->caps = g_slist_append(setup->caps, media_codec);
+	g_free(cap);
+
+done:
+	finalize_select(setup);
+}
+
+static gboolean auto_select(gpointer data)
+{
+	struct vdp_setup *setup = data;
+
+	finalize_select(setup);
+
+	return FALSE;
+}
+
+unsigned int vdp_select_capabilities(struct avdtp *session,
+					uint8_t type, const char *sender,
+					vdp_select_cb_t cb,
+					void *user_data)
+{
+	struct vdp_setup *setup;
+	struct vdp_setup_cb *cb_data;
+	struct vdp_sep *sep;
+	struct avdtp_service_capability *service;
+	struct avdtp_media_codec_capability *codec;
+	int err;
+
+	DBG("");
+	
+	sep = vdp_select_sep(session, type, sender);
+	if (!sep) {
+		error("Unable to select SEP");
+		return 0;
+	}
+
+	setup = vdp_setup_get(session);
+	if (!setup)
+		return 0;
+
+	cb_data = setup_cb_new(setup);
+	cb_data->select_cb = cb;
+	cb_data->user_data = user_data;
+
+	setup->sep = sep;
+	setup->rsep = avdtp_find_remote_sep(session, sep->lsep);
+
+	if (setup->rsep == NULL) {
+		error("Could not find remote sep");
+		goto fail;
+	}
+
+	/* FIXME: Remove auto select when it is not longer possible to register
+	endpoint in the configuration file */
+	if (sep->endpoint == NULL) {
+		if (!select_capabilities(session, setup->rsep,
+					&setup->caps)) {
+			error("Unable to auto select remote SEP capabilities");
+			goto fail;
+		}
+
+		g_idle_add(auto_select, setup);
+
+		return cb_data->id;
+	}
+
+	service = avdtp_get_codec(setup->rsep);
+	codec = (struct avdtp_media_codec_capability *) service->data;
+
+	err = sep->endpoint->select_configuration(sep, codec->data,
+					service->length - sizeof(*codec),
+					GPOINTER_TO_UINT(setup),
+					select_cb, sep->user_data);
+	if (err == 0)
+		return cb_data->id;
+
+fail:
+	setup_cb_free(cb_data);
+	return 0;
+
+}
+
+static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream,
+				struct avdtp_error *err, void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct vdp_setup *setup;
+	struct audio_device *dev;
+	int ret;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Set_Configuration_Cfm", sep);
+	else
+		DBG("Source %p: Set_Configuration_Cfm", sep);
+
+	setup = find_setup_by_session(session);
+
+	if (err) {
+		if (setup) {
+			setup->err = err;
+			finalize_config(setup);
+		}
+		return;
+	}
+
+	avdtp_stream_add_cb(session, stream, stream_state_changed, vdp_sep);
+	vdp_sep->stream = stream;
+
+	if (!setup)
+		return;
+
+	dev = vdp_get_dev(session);
+	
+	/* Notify D-Bus interface of the new stream */
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SOURCE)
+		video_sink_new_stream(dev, session, setup->stream);
+	else
+		video_source_new_stream(dev, session, setup->stream);
+
+	/* Notify Endpoint */
+	if (vdp_sep->endpoint) {
+		struct avdtp_service_capability *service;
+		struct avdtp_media_codec_capability *codec;
+		int err;
+
+		service = avdtp_stream_get_codec(stream);
+		codec = (struct avdtp_media_codec_capability *) service->data;
+
+		err = vdp_sep->endpoint->set_configuration(vdp_sep, dev,
+						codec->data, service->length -
+						sizeof(*codec),
+						GPOINTER_TO_UINT(setup),
+						endpoint_open_cb,
+						vdp_sep->user_data);
+		if (err == 0)
+			return;
+
+		setup->stream = NULL;
+		finalize_setup_errno(setup, -EPERM, finalize_config, NULL);
+		return;
+	}
+
+	ret = avdtp_open(session, stream);
+	if (ret < 0) {
+		error("Error on avdtp_open %s (%d)", strerror(-ret), -ret);
+		setup->stream = NULL;
+		finalize_setup_errno(setup, ret, finalize_config, NULL);
+	}
+}
+
+static void getconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Set_Configuration_Cfm", sep);
+	else
+		DBG("Source %p: Set_Configuration_Cfm", sep);
+}
+
+static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct vdp_setup *setup;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Open_Cfm", sep);
+	else
+		DBG("Source %p: Open_Cfm", sep);
+
+	setup = find_setup_by_session(session);
+	if (!setup)
+		return;
+
+	if (setup->reconfigure)
+		setup->reconfigure = FALSE;
+
+	if (err) {
+		setup->stream = NULL;
+		setup->err = err;
+	}
+
+	finalize_config(setup);
+}
+
+static void start_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct vdp_setup *setup;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Start_Cfm", sep);
+	else
+		DBG("Source %p: Start_Cfm", sep);
+
+	setup = find_setup_by_session(session);
+	if (!setup)
+		return;
+
+	if (err) {
+		setup->stream = NULL;
+		setup->err = err;
+	}
+
+	finalize_resume(setup);
+}
+
+static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct vdp_setup *setup;
+	gboolean start;
+	int perr;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Suspend_Cfm", sep);
+	else
+		DBG("Source %p: Suspend_Cfm", sep);
+
+	vdp_sep->suspending = FALSE;
+
+	setup = find_setup_by_session(session);
+	if (!setup)
+		return;
+
+	start = setup->start;
+	setup->start = FALSE;
+
+	if (err) {
+		setup->stream = NULL;
+		setup->err = err;
+	}
+
+	finalize_suspend(setup);
+
+	if (!start)
+		return;
+
+	if (err) {
+		finalize_resume(setup);
+		return;
+	}
+
+	perr = avdtp_start(session, vdp_sep->stream);
+	if (perr < 0) {
+		error("Error on avdtp_start %s (%d)", strerror(-perr), -perr);
+		finalize_setup_errno(setup, -EIO, finalize_suspend, NULL);
+	}
+}
+
+static gboolean vdp_reconfigure(gpointer data)
+{
+	struct vdp_setup *setup = data;
+	struct vdp_sep *sep = setup->sep;
+	int posix_err;
+	struct avdtp_media_codec_capability *rsep_codec;
+	struct avdtp_service_capability *cap;
+
+	if (setup->rsep) {
+		cap = avdtp_get_codec(setup->rsep);
+		rsep_codec = (struct avdtp_media_codec_capability *) cap->data;
+	}
+
+	if (!setup->rsep || sep->codec != rsep_codec->media_codec_type)
+		setup->rsep = avdtp_find_remote_sep(setup->session, sep->lsep);
+
+	posix_err = avdtp_set_configuration(setup->session, setup->rsep,
+						sep->lsep,
+						setup->caps,
+						&setup->stream);
+	if (posix_err < 0) {
+		error("avdtp_set_configuration: %s", strerror(-posix_err));
+		goto failed;
+	}
+
+	return FALSE;
+
+failed:
+	finalize_setup_errno(setup, posix_err, finalize_config, NULL);
+	return FALSE;
+}
+
+static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct vdp_setup *setup;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Close_Cfm", sep);
+	else
+		DBG("Source %p: Close_Cfm", sep);
+
+	setup = find_setup_by_session(session);
+	if (!setup)
+		return;
+
+	if (err) {
+		setup->stream = NULL;
+		setup->err = err;
+		finalize_config(setup);
+		return;
+	}
+
+	if (!setup->rsep)
+		setup->rsep = avdtp_stream_get_remote_sep(stream);
+
+	if (setup->reconfigure)
+		g_timeout_add(RECONFIGURE_TIMEOUT, vdp_reconfigure, setup);
+}
+
+static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct vdp_setup *setup;
+
+	DBG("");
+	
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Abort_Cfm", sep);
+	else
+		DBG("Source %p: Abort_Cfm", sep);
+
+	setup = find_setup_by_session(session);
+	if (!setup)
+		return;
+
+	setup_unref(setup);
+}
+
+static void reconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+			struct avdtp_stream *stream, struct avdtp_error *err,
+			void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct vdp_setup *setup;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: ReConfigure_Cfm", sep);
+	else
+		DBG("Source %p: ReConfigure_Cfm", sep);
+
+	setup = find_setup_by_session(session);
+	if (!setup)
+		return;
+
+	if (err) {
+		setup->stream = NULL;
+		setup->err = err;
+	}
+
+	finalize_config(setup);
+}
+
+static void delay_report_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream,
+				struct avdtp_error *err, void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: DelayReport_Cfm", sep);
+	else
+		DBG("Source %p: DelayReport_Cfm", sep);
+}
+
+
+static struct avdtp_sep_cfm cfm = {
+	.set_configuration	= setconf_cfm,
+	.get_configuration	= getconf_cfm,
+	.open			= open_cfm,
+	.start			= start_cfm,
+	.suspend		= suspend_cfm,
+	.close			= close_cfm,
+	.abort			= abort_cfm,
+	.reconfigure		= reconf_cfm,
+	.delay_report		= delay_report_cfm,
+};
+
+static gboolean endpoint_getcap_ind(struct avdtp *session,
+					struct avdtp_local_sep *sep,
+					gboolean get_all, GSList **caps,
+					uint8_t *err, void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct avdtp_service_capability *media_transport, *media_codec;
+	struct avdtp_media_codec_capability *codec_caps;
+	uint8_t *capabilities;
+	size_t length;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Get_Capability_Ind", sep);
+	else
+		DBG("Source %p: Get_Capability_Ind", sep);
+
+	*caps = NULL;
+
+	media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+						NULL, 0);
+
+	*caps = g_slist_append(*caps, media_transport);
+
+	length = vdp_sep->endpoint->get_capabilities(vdp_sep, &capabilities,
+							vdp_sep->user_data);
+	codec_caps = g_malloc0(sizeof(*codec_caps) + length);
+	codec_caps->media_type = AVDTP_MEDIA_TYPE_VIDEO;
+	codec_caps->media_codec_type = vdp_sep->codec;
+	memcpy(codec_caps->data, capabilities, length);
+
+	media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, codec_caps,
+						sizeof(*codec_caps) + length);
+
+	*caps = g_slist_append(*caps, media_codec);
+	g_free(codec_caps);
+
+	if (get_all) {
+		struct avdtp_service_capability *delay_reporting;
+		delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
+								NULL, 0);
+		*caps = g_slist_append(*caps, delay_reporting);
+	}
+
+	return TRUE;
+}
+
+static void endpoint_setconf_cb(struct vdp_sep *sep, guint setup_id,
+								gboolean ret)
+{
+	struct vdp_setup *setup = GUINT_TO_POINTER(setup_id);
+
+	if (ret == FALSE) {
+		setup->err = g_new(struct avdtp_error, 1);
+		avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC,
+					AVDTP_UNSUPPORTED_CONFIGURATION);
+	}
+
+	auto_config(setup);
+}
+
+static gboolean endpoint_setconf_ind(struct avdtp *session,
+						struct avdtp_local_sep *sep,
+						struct avdtp_stream *stream,
+						GSList *caps,
+						avdtp_set_configuration_cb cb,
+						void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct vdp_setup *setup;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Set_Configuration_Ind", sep);
+	else
+		DBG("Source %p: Set_Configuration_Ind", sep);
+
+	setup = vdp_setup_get(session);
+	if (!session)
+		return FALSE;
+
+	vdp_sep->stream = stream;
+	setup->sep = vdp_sep;
+	setup->stream = stream;
+	setup->setconf_cb = cb;
+
+	for (; caps != NULL; caps = g_slist_next(caps)) {
+		struct avdtp_service_capability *cap = caps->data;
+		struct avdtp_media_codec_capability *codec;
+		gboolean ret;
+
+		if (cap->category == AVDTP_DELAY_REPORTING &&
+					!vdp_sep->delay_reporting) {
+			setup->err = g_new(struct avdtp_error, 1);
+			avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING,
+					AVDTP_UNSUPPORTED_CONFIGURATION);
+			goto done;
+		}
+
+		if (cap->category != AVDTP_MEDIA_CODEC)
+			continue;
+
+		codec = (struct avdtp_media_codec_capability *) cap->data;
+
+		if (codec->media_codec_type != vdp_sep->codec) {
+			setup->err = g_new(struct avdtp_error, 1);
+			avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC,
+					AVDTP_UNSUPPORTED_CONFIGURATION);
+			goto done;
+		}
+
+		ret = vdp_sep->endpoint->set_configuration(vdp_sep,
+						setup->dev, codec->data,
+						cap->length - sizeof(*codec),
+						GPOINTER_TO_UINT(setup),
+						endpoint_setconf_cb,
+						vdp_sep->user_data);
+		if (ret == 0)
+			return TRUE;
+
+		avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC,
+					AVDTP_UNSUPPORTED_CONFIGURATION);
+		break;
+	}
+
+done:
+	g_idle_add(auto_config, setup);
+	return TRUE;
+}
+
+static gboolean getconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+				uint8_t *err, void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Get_Configuration_Ind", sep);
+	else
+		DBG("Source %p: Get_Configuration_Ind", sep);
+	return TRUE;
+}
+
+static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Open_Ind", sep);
+	else
+		DBG("Source %p: Open_Ind", sep);
+	return TRUE;
+}
+
+static gboolean suspend_timeout(struct vdp_sep *sep)
+{
+	if (avdtp_suspend(sep->session, sep->stream) == 0)
+		sep->suspending = TRUE;
+
+	sep->suspend_timer = 0;
+
+	avdtp_unref(sep->session);
+	sep->session = NULL;
+
+	return FALSE;
+}
+
+
+static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct vdp_setup *setup;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Start_Ind", sep);
+	else
+		DBG("Source %p: Start_Ind", sep);
+
+	setup = find_setup_by_session(session);
+	if (setup)
+		finalize_resume(setup);
+
+	if (!vdp_sep->locked) {
+		vdp_sep->session = avdtp_ref(session);
+		vdp_sep->suspend_timer = g_timeout_add_seconds(SUSPEND_TIMEOUT,
+						(GSourceFunc) suspend_timeout,
+						vdp_sep);
+	}
+
+	return TRUE;
+}
+
+static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Suspend_Ind", sep);
+	else
+		DBG("Source %p: Suspend_Ind", sep);
+
+	if (vdp_sep->suspend_timer) {
+		g_source_remove(vdp_sep->suspend_timer);
+		vdp_sep->suspend_timer = 0;
+		avdtp_unref(vdp_sep->session);
+		vdp_sep->session = NULL;
+	}
+
+	return TRUE;
+}
+
+static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct vdp_setup *setup;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Close_Ind", sep);
+	else
+		DBG("Source %p: Close_Ind", sep);
+
+	setup = find_setup_by_session(session);
+	if (!setup)
+		return TRUE;
+
+	finalize_setup_errno(setup, -ECONNRESET, finalize_suspend,
+							finalize_resume, NULL);
+
+	return TRUE;
+}
+
+static gboolean abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream, uint8_t *err,
+				void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Abort_Ind", sep);
+	else
+		DBG("Source %p: Abort_Ind", sep);
+
+	vdp_sep->stream = NULL;
+
+	return TRUE;
+}
+
+static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+				uint8_t *err, void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: ReConfigure_Ind", sep);
+	else
+		DBG("Source %p: ReConfigure_Ind", sep);
+
+	return TRUE;
+}
+
+static gboolean delayreport_ind(struct avdtp *session,
+				struct avdtp_local_sep *sep,
+				uint8_t rseid, uint16_t delay,
+				uint8_t *err, void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct audio_device *dev = vdp_get_dev(session);
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: DelayReport_Ind", sep);
+	else
+		DBG("Source %p: DelayReport_Ind", sep);
+
+	unix_delay_report(dev, rseid, delay);
+
+	return TRUE;
+}
+
+static gboolean endpoint_delayreport_ind(struct avdtp *session,
+						struct avdtp_local_sep *sep,
+						uint8_t rseid, uint16_t delay,
+						uint8_t *err, void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: DelayReport_Ind", sep);
+	else
+		DBG("Source %p: DelayReport_Ind", sep);
+
+	if (vdp_sep->endpoint == NULL ||
+				vdp_sep->endpoint->set_delay == NULL)
+		return FALSE;
+
+	vdp_sep->endpoint->set_delay(vdp_sep, delay, vdp_sep->user_data);
+
+	return TRUE;
+}
+
+static struct avdtp_sep_ind endpoint_ind = {
+	.get_capability		= endpoint_getcap_ind,
+	.set_configuration	= endpoint_setconf_ind,
+	.get_configuration	= getconf_ind,
+	.open			= open_ind,
+	.start			= start_ind,
+	.suspend		= suspend_ind,
+	.close			= close_ind,
+	.abort			= abort_ind,
+	.reconfigure		= reconf_ind,
+	.delayreport		= endpoint_delayreport_ind,
+};
+
+static gboolean h263_baseline_getcap_ind(struct avdtp *session,
+				struct avdtp_local_sep *sep, gboolean get_all,
+				GSList **caps, uint8_t *err, void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct avdtp_service_capability *media_transport, *media_codec;
+	struct h263_baseline_codec_cap h263_cap;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Get_Capability_Ind", sep);
+	else
+		DBG("Source %p: Get_Capability_Ind", sep);
+
+	*caps = NULL;
+
+	media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+						NULL, 0);
+
+	*caps = g_slist_append(*caps, media_transport);
+
+	memset(&h263_cap, 0, sizeof(struct h263_baseline_codec_cap));
+
+	h263_cap.cap.media_type = AVDTP_MEDIA_TYPE_VIDEO;
+	h263_cap.cap.media_codec_type = VDP_CODEC_H263_BASELINE;
+
+	h263_cap.level = ( H263_LEVEL_10 |
+				H263_LEVEL_20 |
+				H263_LEVEL_30 );
+
+	media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &h263_cap,
+						sizeof(h263_cap));
+
+	*caps = g_slist_append(*caps, media_codec);
+
+	if (get_all) {
+		struct avdtp_service_capability *delay_reporting;
+		delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
+								NULL, 0);
+		*caps = g_slist_append(*caps, delay_reporting);
+	}
+
+	return TRUE;
+}
+
+static gboolean h263_baseline_setconf_ind(struct avdtp *session,
+					struct avdtp_local_sep *sep,
+					struct avdtp_stream *stream,
+					GSList *caps,
+					avdtp_set_configuration_cb cb,
+					void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct vdp_setup *setup;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Set_Configuration_Ind", sep);
+	else
+		DBG("Source %p: Set_Configuration_Ind", sep);
+
+	setup = vdp_setup_get(session);
+	if (!setup)
+		return FALSE;
+
+	vdp_sep->stream = stream;
+	setup->sep = vdp_sep;
+	setup->stream = stream;
+	setup->setconf_cb = cb;
+
+	/* Check valid settings */
+	for (; caps != NULL; caps = g_slist_next(caps)) {
+		struct avdtp_service_capability *cap = caps->data;
+		struct avdtp_media_codec_capability *codec_cap;
+
+		if (cap->category == AVDTP_DELAY_REPORTING &&
+					!vdp_sep->delay_reporting) {
+			setup->err = g_new(struct avdtp_error, 1);
+			avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING,
+						AVDTP_UNSUPPORTED_CONFIGURATION);
+			goto done;
+		}
+
+		if (cap->category != AVDTP_MEDIA_CODEC)
+			continue;
+
+		if (cap->length < sizeof(struct h263_baseline_codec_cap))
+			continue;
+
+		codec_cap = (void *) cap->data;
+
+		if (codec_cap->media_codec_type != VDP_CODEC_H263_BASELINE)
+			continue;
+
+	}
+
+done:
+	g_idle_add(auto_config, setup);
+	return TRUE;
+}
+
+static struct avdtp_sep_ind h263_baseline_ind = {
+	.get_capability		= h263_baseline_getcap_ind,
+	.set_configuration	= h263_baseline_setconf_ind,
+	.get_configuration	= getconf_ind,
+	.open			= open_ind,
+	.start			= start_ind,
+	.suspend		= suspend_ind,
+	.close			= close_ind,
+	.abort			= abort_ind,
+	.reconfigure		= reconf_ind,
+	.delayreport		= delayreport_ind,
+};
+
+static gboolean mpeg4_getcap_ind(struct avdtp *session,
+				struct avdtp_local_sep *sep, gboolean get_all,
+				GSList **caps, uint8_t *err, void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct avdtp_service_capability *media_transport, *media_codec;
+	struct mpeg4_codec_cap mpeg4_cap;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Get_Capability_Ind", sep);
+	else
+		DBG("Source %p: Get_Capability_Ind", sep);
+
+	*caps = NULL;
+
+	media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+						NULL, 0);
+
+	*caps = g_slist_append(*caps, media_transport);
+
+	memset(&mpeg4_cap, 0, sizeof(struct mpeg4_codec_cap));
+
+	mpeg4_cap.cap.media_type = AVDTP_MEDIA_TYPE_VIDEO;
+	mpeg4_cap.cap.media_codec_type = VDP_CODEC_MPEG4_VISUAL_SAMPLE;
+
+	mpeg4_cap.level = ( MPEG4_LEVEL_0 |
+				MPEG4_LEVEL_1 |
+				MPEG4_LEVEL_2 );
+
+	media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &mpeg4_cap,
+						sizeof(mpeg4_cap));
+
+	*caps = g_slist_append(*caps, media_codec);
+
+	if (get_all) {
+		struct avdtp_service_capability *delay_reporting;
+		delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
+								NULL, 0);
+		*caps = g_slist_append(*caps, delay_reporting);
+	}
+
+	return TRUE;
+}
+
+static gboolean mpeg4_setconf_ind(struct avdtp *session,
+					struct avdtp_local_sep *sep,
+					struct avdtp_stream *stream,
+					GSList *caps,
+					avdtp_set_configuration_cb cb,
+					void *user_data)
+{
+	struct vdp_sep *vdp_sep = user_data;
+	struct vdp_setup *setup;
+
+	if (vdp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: Set_Configuration_Ind", sep);
+	else
+		DBG("Source %p: Set_Configuration_Ind", sep);
+
+	setup = vdp_setup_get(session);
+	if (!setup)
+		return FALSE;
+
+	vdp_sep->stream = stream;
+	setup->sep = vdp_sep;
+	setup->stream = stream;
+	setup->setconf_cb = cb;
+
+	/* Check valid settings */
+	for (; caps != NULL; caps = g_slist_next(caps)) {
+		struct avdtp_service_capability *cap = caps->data;
+		struct avdtp_media_codec_capability *codec_cap;
+
+		if (cap->category == AVDTP_DELAY_REPORTING &&
+					!vdp_sep->delay_reporting) {
+			setup->err = g_new(struct avdtp_error, 1);
+			avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING,
+						AVDTP_UNSUPPORTED_CONFIGURATION);
+			goto done;
+		}
+
+		if (cap->category != AVDTP_MEDIA_CODEC)
+			continue;
+
+		if (cap->length < sizeof(struct h263_baseline_codec_cap))
+			continue;
+
+		codec_cap = (void *) cap->data;
+
+		if (codec_cap->media_codec_type != VDP_CODEC_H263_BASELINE)
+			continue;
+
+	}
+
+done:
+	g_idle_add(auto_config, setup);
+	return TRUE;
+}
+
+static struct avdtp_sep_ind mpeg4_ind = {
+        .get_capability         = mpeg4_getcap_ind,
+        .set_configuration      = mpeg4_setconf_ind,
+        .get_configuration      = getconf_ind,
+        .open                   = open_ind,
+        .start                  = start_ind,
+        .suspend                = suspend_ind,
+        .close                  = close_ind,
+        .abort                  = abort_ind,
+        .reconfigure            = reconf_ind,
+        .delayreport            = delayreport_ind,
+};
+
+static sdp_record_t *vdp_record(uint8_t type, uint16_t avdtp_ver)
+{
+	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+	uuid_t root_uuid, l2cap_uuid, avdtp_uuid, vdp_uuid;
+	sdp_profile_desc_t profile[1];
+	sdp_list_t *aproto, *proto[2];
+	sdp_record_t *record;
+	sdp_data_t *psm, *version, *features;
+	uint16_t lp = AVDTP_UUID;
+	uint16_t vdp_ver = 0x0001, feat = 0x000f;
+
+	DBG("VDP record");
+	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);
+
+	if (type == AVDTP_SEP_TYPE_SOURCE)
+		sdp_uuid16_create(&vdp_uuid, VIDEO_SOURCE_SVCLASS_ID);
+	else
+		sdp_uuid16_create(&vdp_uuid, VIDEO_SINK_SVCLASS_ID);
+	svclass_id = sdp_list_append(0, &vdp_uuid);
+	sdp_set_service_classes(record, svclass_id);
+
+	sdp_uuid16_create(&profile[0].uuid, VIDEO_DISTRIBUTION_PROFILE_ID);
+	profile[0].version = vdp_ver;
+	pfseq = sdp_list_append(0, &profile[0]);
+	sdp_set_profile_descs(record, pfseq);
+
+	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+	proto[0] = sdp_list_append(0, &l2cap_uuid);
+	psm = sdp_data_alloc(SDP_UINT16, &lp);
+	proto[0] = sdp_list_append(proto[0], psm);
+	apseq = sdp_list_append(0, proto[0]);
+
+	sdp_uuid16_create(&avdtp_uuid, AVDTP_UUID);
+	proto[1] = sdp_list_append(0, &avdtp_uuid);
+	version = sdp_data_alloc(SDP_UINT16, &avdtp_ver);
+	proto[1] = sdp_list_append(proto[1], version);
+	apseq = sdp_list_append(apseq, proto[1]);
+
+	aproto = sdp_list_append(0, apseq);
+	sdp_set_access_protos(record, aproto);
+
+	features = sdp_data_alloc(SDP_UINT16, &feat);
+	sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+	if (type == AVDTP_SEP_TYPE_SOURCE)
+		sdp_set_info_attr(record, "Video Source", 0, 0);
+	else
+		sdp_set_info_attr(record, "Video Sink", 0, 0);
+
+	free(psm);
+	free(version);
+	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;
+}
+
+struct vdp_sep *vdp_add_sep(const bdaddr_t *src, uint8_t type,
+				uint8_t codec, gboolean delay_reporting,
+				struct vdp_endpoint *endpoint,
+				void *user_data, GDestroyNotify destroy,
+				int *err)
+{
+	struct vdp_server *server;
+	struct vdp_sep *sep;
+	GSList **l;
+	uint32_t *record_id;
+	sdp_record_t *record;
+	struct avdtp_sep_ind *ind;
+
+	server = find_server(servers, src);
+	if (server == NULL) {
+		if (err)
+			*err = -EINVAL;
+		return NULL;
+	}
+
+	if (type == AVDTP_SEP_TYPE_SINK && !server->sink_enabled) {
+		if (err)
+			*err = -EPROTONOSUPPORT;
+		return NULL;
+	}
+
+	if (type == AVDTP_SEP_TYPE_SOURCE && !server->source_enabled) {
+		if (err)
+			*err = -EPROTONOSUPPORT;
+		return NULL;
+	}
+
+	sep = g_new0(struct vdp_sep, 1);
+
+	if (endpoint) {
+		ind = &endpoint_ind;
+		goto proceed;
+	}
+
+	ind = (codec == VDP_CODEC_H263_BASELINE) ? &h263_baseline_ind: &mpeg4_ind;
+
+proceed:
+	sep->lsep = avdtp_register_sep(&server->src, type,
+					AVDTP_MEDIA_TYPE_VIDEO, codec,
+					delay_reporting, ind,&cfm, sep);
+	if (sep->lsep == NULL) {
+		g_free(sep);
+		if (err)
+			*err = -EINVAL;
+		return NULL;
+	}
+
+	sep->server = server;
+	sep->endpoint = endpoint;
+	sep->codec = codec;
+	sep->type = type;
+	sep->delay_reporting = delay_reporting;
+	sep->user_data = user_data;
+	sep->destroy = destroy;
+
+	if (type == AVDTP_SEP_TYPE_SOURCE) {
+		l = &server->sources;
+		record_id = &server->source_record_id;
+	} else {
+		l = &server->sinks;
+		record_id = &server->sink_record_id;
+	}
+
+	if (*record_id != 0)
+		goto add;
+
+	record = vdp_record(type, server->version);
+	if (!record) {
+		error("Unable to allocate new service record");
+		avdtp_unregister_sep(sep->lsep);
+		g_free(sep);
+		if (err)
+			*err = -EINVAL;
+		return NULL;
+	}
+
+	if (add_record_to_server(&server->src, record) < 0) {
+		error("Unable to register VDP service record");
+		sdp_record_free(record);
+		avdtp_unregister_sep(sep->lsep);
+		g_free(sep);
+		if (err)
+			*err = -EINVAL;
+		return NULL;
+	}
+	*record_id = record->handle;
+
+add:
+	*l = g_slist_append(*l, sep);
+
+	if (err)
+		*err = 0;
+	return sep;
+}
+
+int vdp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)
+{
+	int h263_baseline_srcs = 1, h263_baseline_sinks = 1;
+	int mpeg4_srcs = 0, mpeg4_sinks = 0;
+	gboolean source = TRUE, sink = FALSE;
+	struct vdp_server *server;
+	int i;
+	char *str;
+	GError *err = NULL;
+
+	if (!config)
+		goto proceed;
+
+	str = g_key_file_get_string(config, "General", "Enable", &err);
+
+	if (err) {
+		DBG("audio.conf: %s", err->message);
+		g_clear_error(&err);
+	} else {
+		if (strstr(str, "VideoSink"))
+			source = TRUE;
+		if (strstr(str, "VideoSource"))
+			sink = TRUE;
+		g_free(str);
+	}
+
+	str = g_key_file_get_string(config, "General", "Disable", &err);
+
+	if (err) {
+		DBG("audio.conf: %s", err->message);
+		g_clear_error(&err);
+	} else {
+		if (strstr(str, "VideoSink"))
+			source = FALSE;
+		if (strstr(str, "VideoSource"))
+			sink = FALSE;
+		g_free(str);
+	}
+
+	str = g_key_file_get_string(config, "VDP", "H263BaselineSources", &err);
+	if (err) {
+		DBG("audio.conf: %s", err->message);
+		g_clear_error(&err);
+	} else {
+		h263_baseline_srcs = atoi(str);
+		g_free(str);
+	}
+
+	str = g_key_file_get_string(config, "VDP", "MPEG4Sources", &err);
+	if (err) {
+		DBG("audio.conf: %s", err->message);
+		g_clear_error(&err);
+	} else {
+		mpeg4_srcs = atoi(str);
+		g_free(str);
+	}
+
+	str = g_key_file_get_string(config, "VDP", "H263BaselineSinks", &err);
+	if (err) {
+		DBG("audio.conf: %s", err->message);
+		g_clear_error(&err);
+	} else {
+		h263_baseline_sinks = atoi(str);
+		g_free(str);
+	}
+
+	str = g_key_file_get_string(config, "VDP", "MPEG4Sinks", &err);
+	if (err) {
+		DBG("audio.conf: %s", err->message);
+		g_clear_error(&err);
+	} else {
+		mpeg4_sinks = atoi(str);
+		g_free(str);
+	}
+
+proceed:
+
+	if(!conn)
+		connection = dbus_connection_ref(conn);
+	server = find_server(servers, src);
+
+	if (!server) {
+		int av_err;
+
+		server = g_new0(struct vdp_server, 1);
+		if (!server)
+			return -ENOMEM;
+
+		av_err = avdtp_init(src, config, &server->version);
+		if (av_err < 0) {
+			g_free(server);
+			return av_err;
+		}
+
+		bacpy(&server->src, src);
+		servers = g_slist_append(servers, server);
+	}
+
+	server->source_enabled = source;
+	if (source) {
+		for (i = 0; i < h263_baseline_srcs; i++)
+			vdp_add_sep(src, AVDTP_SEP_TYPE_SOURCE,
+				VDP_CODEC_H263_BASELINE, FALSE,
+					NULL, NULL, NULL, NULL);
+		
+		for (i = 0; i < mpeg4_srcs; i++)
+			vdp_add_sep(src, AVDTP_SEP_TYPE_SOURCE,
+				VDP_CODEC_MPEG4_VISUAL_SAMPLE, FALSE,
+					NULL, NULL, NULL, NULL);
+	}
+	server->sink_enabled = sink;
+	if (sink) {
+		for (i = 0; i < h263_baseline_sinks; i++)
+			vdp_add_sep(src, AVDTP_SEP_TYPE_SINK,
+				VDP_CODEC_H263_BASELINE, FALSE, 
+					NULL, NULL, NULL, NULL);
+		
+		for (i = 0; i < mpeg4_sinks; i++)
+			vdp_add_sep(src, AVDTP_SEP_TYPE_SINK,
+                                VDP_CODEC_MPEG4_VISUAL_SAMPLE, FALSE,
+					NULL, NULL, NULL, NULL);
+	}
+
+	return 0;
+}
+
+static void vdp_unregister_sep(struct vdp_sep *sep)
+{
+	if (sep->destroy) {
+		sep->destroy(sep->user_data);
+		sep->endpoint = NULL;
+	}
+
+	avdtp_unregister_sep(sep->lsep);
+	g_free(sep);
+}
+
+void vdp_remove_sep(struct vdp_sep *sep)
+{
+	struct vdp_server *server = sep->server;
+
+	if (sep->type == AVDTP_SEP_TYPE_SOURCE) {
+		if (g_slist_find(server->sources, sep) == NULL)
+			return;
+		server->sources = g_slist_remove(server->sources, sep);
+		if (server->sources == NULL && server->source_record_id) {
+			remove_record_from_server(server->source_record_id);
+			server->source_record_id = 0;
+		}
+	} else {
+		if (g_slist_find(server->sinks, sep) == NULL)
+			return;
+		server->sinks = g_slist_remove(server->sinks, sep);
+		if (server->sinks == NULL && server->sink_record_id) {
+			remove_record_from_server(server->sink_record_id);
+			server->sink_record_id = 0;
+		}
+	}
+
+	if (sep->locked)
+		return;
+
+	vdp_unregister_sep(sep);
+}
+
+void vdp_unregister(const bdaddr_t *src)
+{
+	struct vdp_server *server;
+
+	server = find_server(servers, src);
+	if (!server)
+		return;
+
+	g_slist_foreach(server->sinks, (GFunc) vdp_remove_sep, NULL);
+	g_slist_free(server->sinks);
+
+	g_slist_foreach(server->sources, (GFunc) vdp_remove_sep, NULL);
+	g_slist_free(server->sources);
+
+	avdtp_exit(src);
+
+	servers = g_slist_remove(servers, server);
+	g_free(server);
+
+	if (servers)
+		return;
+
+	dbus_connection_unref(connection);
+	connection = NULL;
+}
+
+gboolean vdp_cancel(struct audio_device *dev, unsigned int id)
+{
+	struct vdp_setup *setup;
+	GSList *l;
+
+	DBG("");
+	
+	setup = find_setup_by_dev(dev);
+	if (!setup)
+		return FALSE;
+
+	for (l = setup->cb; l != NULL; l = g_slist_next(l)) {
+		struct vdp_setup_cb *cb = l->data;
+
+		if (cb->id != id)
+			continue;
+
+		setup_ref(setup);
+		setup_cb_free(cb);
+
+		if (!setup->cb) {
+			DBG("aborting setup %p", setup);
+			avdtp_abort(setup->session, setup->stream);
+			return TRUE;
+		}
+
+		setup_unref(setup);
+		return TRUE;
+	}
+
+	return FALSE;
+}
diff --git a/audio/vdp.h b/audio/vdp.h
new file mode 100644
index 0000000..bc81838
--- /dev/null
+++ b/audio/vdp.h
@@ -0,0 +1,112 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#define VDP_CODEC_H263_BASELINE		0x01
+#define VDP_CODEC_MPEG4_VISUAL_SAMPLE	0x02
+#define VDP_CODEC_H263_PROFILE_3	0x03
+#define VDP_CODEC_H263_PROFILE_8	0x04
+
+#define H263_LEVEL_10			(1 << 7)
+#define H263_LEVEL_20			(1 << 6)
+#define H263_LEVEL_30			(1 << 5)
+
+#define MPEG4_LEVEL_0			(1 << 7)
+#define MPEG4_LEVEL_1			(1 << 6)
+#define MPEG4_LEVEL_2			(1 << 5)
+
+struct h263_baseline_codec_cap {
+        struct avdtp_media_codec_capability cap;
+        uint8_t level;
+} __attribute__ ((packed));
+
+struct mpeg4_codec_cap {
+	struct avdtp_media_codec_capability cap;
+	uint8_t level;
+} __attribute__ ((packed));
+
+struct vdp_sep;
+
+typedef void (*vdp_endpoint_select_t) (struct vdp_sep *sep, guint setup_id,
+							void *ret, int size);
+typedef void (*vdp_endpoint_config_t) (struct vdp_sep *sep, guint setup_id,
+								gboolean ret);
+
+struct vdp_endpoint {
+	const char *(*get_name) (struct vdp_sep *sep, void *user_data);
+	size_t (*get_capabilities) (struct vdp_sep *sep,
+						uint8_t **capabilities,
+						void *user_data);
+	int (*select_configuration) (struct vdp_sep *sep,
+						uint8_t *capabilities,
+						size_t length,
+						guint setup_id,
+						vdp_endpoint_select_t cb,
+						void *user_data);
+	int (*set_configuration) (struct vdp_sep *sep,
+						struct audio_device *dev,
+						uint8_t *configuration,
+						size_t length,
+						guint setup_id,
+						vdp_endpoint_config_t cb,
+						void *user_data);
+	void (*clear_configuration) (struct vdp_sep *sep, void *user_data);
+	void (*set_delay) (struct vdp_sep *sep, uint16_t delay,
+							void *user_data);
+};
+
+typedef void (*vdp_select_cb_t) (struct avdtp *session,
+					struct vdp_sep *sep, GSList *caps,
+					void *user_data);
+typedef void (*vdp_config_cb_t) (struct avdtp *session, struct vdp_sep *sep,
+					struct avdtp_stream *stream,
+					struct avdtp_error *err,
+					void *user_data);
+typedef void (*vdp_stream_cb_t) (struct avdtp *session,
+					struct avdtp_error *err,
+					void *user_data);
+
+int vdp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config);
+void vdp_unregister(const bdaddr_t *src);
+struct vdp_sep *vdp_add_sep(const bdaddr_t *src, uint8_t type,
+				uint8_t codec, gboolean delay_reporting,
+				struct vdp_endpoint *endpoint,
+				void *user_data, GDestroyNotify destroy,
+				int *err);
+void vdp_remove_sep(struct vdp_sep *sep);
+
+struct vdp_sep *vdp_get(struct avdtp *session, struct avdtp_remote_sep *sep);
+
+unsigned int vdp_select_capabilities(struct avdtp *session, uint8_t type,
+					const char *sender, vdp_select_cb_t cb,
+					void *user_data);
+unsigned int vdp_config(struct avdtp *session, struct vdp_sep *sep,
+				vdp_config_cb_t cb, GSList *caps,
+				void *user_data);
+gboolean vdp_sep_lock(struct vdp_sep *sep, struct avdtp *session);
+gboolean vdp_sep_unlock(struct vdp_sep *sep, struct avdtp *session);
+gboolean vdp_sep_get_lock(struct vdp_sep *sep);
+struct avdtp_stream *vdp_sep_get_stream(struct vdp_sep *sep);
+struct vdp_sep *vdp_get_sep(struct avdtp *session,
+				struct avdtp_stream *stream);
+gboolean vdp_cancel(struct audio_device *dev, unsigned int id);
-- 
1.7.6


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH BlueZ 2/6] Implementation of video-sink for VDP
  2011-08-16 13:43 [PATCH BlueZ 1/6] Initial VDP implementation Prasad Bhat
@ 2011-08-16 13:43 ` Prasad Bhat
  2011-08-18  7:14   ` Luiz Augusto von Dentz
  2011-08-16 13:43 ` [PATCH BlueZ 3/6] Initial video-source implementation " Prasad Bhat
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Prasad Bhat @ 2011-08-16 13:43 UTC (permalink / raw)
  To: linux-bluetooth

---
 Makefile.am        |    1 +
 audio/video-sink.c |  677 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 audio/video-sink.h |   44 ++++
 3 files changed, 722 insertions(+), 0 deletions(-)
 create mode 100644 audio/video-sink.c
 create mode 100644 audio/video-sink.h

diff --git a/Makefile.am b/Makefile.am
index f1c9003..87b32a4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -142,6 +142,7 @@ builtin_sources += audio/main.c \
 			audio/sink.h audio/sink.c \
 			audio/a2dp.h audio/a2dp.c \
 			audio/vdp.h audio/vdp.c \
+			audio/video-sink.h audio/video-sink.c \
 			audio/avdtp.h audio/avdtp.c \
 			audio/ipc.h audio/ipc.c \
 			audio/unix.h audio/unix.c \
diff --git a/audio/video-sink.c b/audio/video-sink.c
new file mode 100644
index 0000000..a879c0c
--- /dev/null
+++ b/audio/video-sink.c
@@ -0,0 +1,677 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+#include "device.h"
+#include "media.h"
+#include "log.h"
+#include "avdtp.h"
+#include "vdp.h"
+#include "error.h"
+#include "video-sink.h"
+#include "dbus-common.h"
+#include "../src/adapter.h"
+#include "../src/device.h"
+
+#define STREAM_SETUP_RETRY_TIMER 2
+
+struct pending_request {
+	DBusConnection *conn;
+	DBusMessage *msg;
+	unsigned int id;
+};
+
+struct video_sink {
+	struct audio_device *dev;
+	struct avdtp *session;
+	struct avdtp_stream *stream;
+	unsigned int cb_id;
+	guint retry_id;
+	avdtp_session_state_t session_state;
+	avdtp_state_t stream_state;
+	video_sink_state_t state;
+	struct pending_request *connect;
+	struct pending_request *disconnect;
+	DBusConnection *conn;
+};
+
+struct video_sink_state_callback {
+	video_sink_state_cb cb;
+	void *user_data;
+	unsigned int id;
+};
+
+static GSList *sink_callbacks = NULL;
+
+static unsigned int avdtp_callback_id = 0;
+
+static char *str_state[] = {
+	"VIDEO_SINK_STATE_DISCONNECTED",
+	"VIDEO_SINK_STATE_CONNECTING",
+	"VIDEO_SINK_STATE_CONNECTED",
+	"VIDEO_SINK_STATE_PLAYING",
+};
+
+static const char *state2str(video_sink_state_t state)
+{
+	switch (state) {
+	case VIDEO_SINK_STATE_DISCONNECTED:
+		return "disconnected";
+	case VIDEO_SINK_STATE_CONNECTING:
+		return "connecting";
+	case VIDEO_SINK_STATE_CONNECTED:
+		return "connected";
+	case VIDEO_SINK_STATE_PLAYING:
+		return "playing";
+	default:
+		error("Invalid sink state %d", state);
+		return NULL;
+	}
+}
+
+static void sink_set_state(struct audio_device *dev, video_sink_state_t new_state)
+{
+	struct video_sink *sink = dev->video_sink;
+	const char *state_str;
+	video_sink_state_t old_state = sink->state;
+	GSList *l;
+
+	sink->state = new_state;
+
+	state_str = state2str(new_state);
+	if (state_str)
+		emit_property_changed(dev->conn, dev->path,
+					VIDEO_SINK_INTERFACE, "State",
+					DBUS_TYPE_STRING, &state_str);
+
+	DBG("State changed %s: %s -> %s", dev->path, str_state[old_state],
+		str_state[new_state]);
+
+	for (l = sink_callbacks; l != NULL; l = l->next) {
+		struct video_sink_state_callback *cb = l->data;
+		cb->cb(dev, old_state, new_state, cb->user_data);
+	}
+}
+
+static void avdtp_state_callback(struct audio_device *dev,
+					struct avdtp *session,
+					avdtp_session_state_t old_state,
+					avdtp_session_state_t new_state,
+					void *user_data)
+{
+	struct video_sink *sink = dev->video_sink;
+
+	if (sink == NULL)
+		return;
+
+	switch (new_state) {
+	case AVDTP_SESSION_STATE_DISCONNECTED:
+		if (sink->state != VIDEO_SINK_STATE_CONNECTING) {
+			gboolean value = FALSE;
+			g_dbus_emit_signal(dev->conn, dev->path,
+					VIDEO_SINK_INTERFACE, "Disconnected",
+					DBUS_TYPE_INVALID);
+			emit_property_changed(dev->conn, dev->path,
+					VIDEO_SINK_INTERFACE, "Connected",
+					DBUS_TYPE_BOOLEAN, &value);
+		}
+		sink_set_state(dev, VIDEO_SINK_STATE_DISCONNECTED);
+		break;
+	case AVDTP_SESSION_STATE_CONNECTING:
+		sink_set_state(dev, VIDEO_SINK_STATE_CONNECTING);
+		break;
+	case AVDTP_SESSION_STATE_CONNECTED:
+		break;
+	}
+
+	sink->session_state = new_state;
+}
+
+static void pending_request_free(struct audio_device *dev,
+					struct pending_request *pending)
+{
+	if (pending->conn)
+		dbus_connection_unref(pending->conn);
+	if (pending->msg)
+		dbus_message_unref(pending->msg);
+	if (pending->id)
+		vdp_cancel(dev, pending->id);
+
+	g_free(pending);
+}
+
+static void stream_state_changed(struct avdtp_stream *stream,
+					avdtp_state_t old_state,
+					avdtp_state_t new_state,
+					struct avdtp_error *err,
+					void *user_data)
+{
+	struct audio_device *dev = user_data;
+	struct video_sink *sink = dev->video_sink;
+	gboolean value;
+
+	if (err)
+		return;
+
+	switch (new_state) {
+	case AVDTP_STATE_IDLE:
+		if (sink->disconnect) {
+			DBusMessage *reply;
+			struct pending_request *p;
+
+			p = sink->disconnect;
+			sink->disconnect = NULL;
+
+			reply = dbus_message_new_method_return(p->msg);
+			g_dbus_send_message(p->conn, reply);
+			pending_request_free(dev, p);
+		}
+
+		if (sink->session) {
+			avdtp_unref(sink->session);
+			sink->session = NULL;
+		}
+		sink->stream = NULL;
+		sink->cb_id = 0;
+		break;
+	case AVDTP_STATE_OPEN:
+		if (old_state == AVDTP_STATE_CONFIGURED &&
+				sink->state == VIDEO_SINK_STATE_CONNECTING) {
+			value = TRUE;
+			g_dbus_emit_signal(dev->conn, dev->path,
+						VIDEO_SINK_INTERFACE,
+						"Connected",
+						DBUS_TYPE_INVALID);
+			emit_property_changed(dev->conn, dev->path,
+						VIDEO_SINK_INTERFACE,
+						"Connected",
+						DBUS_TYPE_BOOLEAN, &value);
+		} else if (old_state == AVDTP_STATE_STREAMING) {
+			value = FALSE;
+			g_dbus_emit_signal(dev->conn, dev->path,
+						VIDEO_SINK_INTERFACE,
+						"Stopped",
+						DBUS_TYPE_INVALID);
+			emit_property_changed(dev->conn, dev->path,
+						VIDEO_SINK_INTERFACE,
+						"Playing",
+						DBUS_TYPE_BOOLEAN, &value);
+		}
+		sink_set_state(dev, VIDEO_SINK_STATE_CONNECTED);
+		break;
+	case AVDTP_STATE_STREAMING:
+		value = TRUE;
+		g_dbus_emit_signal(dev->conn, dev->path, VIDEO_SINK_INTERFACE,
+					"Playing", DBUS_TYPE_INVALID);
+		emit_property_changed(dev->conn, dev->path,
+					VIDEO_SINK_INTERFACE, "Playing",
+					DBUS_TYPE_BOOLEAN, &value);
+		sink_set_state(dev, VIDEO_SINK_STATE_PLAYING);
+		break;
+	case AVDTP_STATE_CONFIGURED:
+	case AVDTP_STATE_CLOSING:
+	case AVDTP_STATE_ABORTING:
+	default:
+		break;
+	}
+
+	sink->stream_state = new_state;
+}
+
+static void error_failed(DBusConnection *conn, DBusMessage *msg,
+							const char *desc)
+{
+	DBusMessage *reply = btd_error_failed(msg, desc);
+	g_dbus_send_message(conn, reply);
+}
+
+
+
+static gboolean stream_setup_retry(gpointer user_data)
+{
+	struct video_sink *sink = user_data;
+	struct pending_request *pending = sink->connect;
+
+	sink->retry_id = 0;
+
+	if (sink->stream_state >= AVDTP_STATE_OPEN) {
+		DBG("Stream successfully created, after XCASE connect:connect");
+		if (pending->msg) {
+			DBusMessage *reply;
+			reply = dbus_message_new_method_return(pending->msg);
+			g_dbus_send_message(pending->conn, reply);
+		}
+	} else {
+		DBG("Stream setup failed, after XCASE connect:connect");
+		if (pending->msg)
+			error_failed(pending->conn, pending->msg, "Stream setup failed");
+	}
+
+	sink->connect = NULL;
+	pending_request_free(sink->dev, pending);
+
+	return FALSE;
+}
+
+
+static void stream_setup_complete(struct avdtp *session, struct vdp_sep *sep,
+					struct avdtp_stream *stream,
+					struct avdtp_error *err, void *user_data)
+{
+	struct video_sink *sink = user_data;
+	struct pending_request *pending;
+
+	pending = sink->connect;
+
+	pending->id = 0;
+
+	if (stream) {
+		DBG("Stream successfully created");
+
+		if (pending->msg) {
+			DBusMessage *reply;
+			reply = dbus_message_new_method_return(pending->msg);
+			g_dbus_send_message(pending->conn, reply);
+		}
+
+		sink->connect = NULL;
+		pending_request_free(sink->dev, pending);
+
+		return;
+	}
+
+	avdtp_unref(sink->session);
+	sink->session = NULL;
+	if (avdtp_error_category(err) == AVDTP_ERRNO
+			&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
+		DBG("connect:connect XCASE detected");
+		sink->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
+							stream_setup_retry,
+							sink);
+	} else {
+		if (pending->msg)
+			error_failed(pending->conn, pending->msg, "Stream setup failed");
+		sink->connect = NULL;
+		pending_request_free(sink->dev, pending);
+		DBG("Stream setup failed : %s", avdtp_strerror(err));
+	}
+}
+
+static void select_complete(struct avdtp *session, struct vdp_sep *sep,
+			GSList *caps, void *user_data)
+{
+	struct video_sink *sink = user_data;
+	struct pending_request *pending;
+	int id;
+
+	pending = sink->connect;
+	pending->id = 0;
+
+	id = vdp_config(session, sep, stream_setup_complete, caps, sink);
+	if (id == 0){
+		DBG("id = 0");
+		goto failed;
+	}
+
+	pending->id = id;
+	return;
+
+failed:
+	if (pending->msg)
+		error_failed(pending->conn, pending->msg, "Stream setup failed");
+	pending_request_free(sink->dev, pending);
+	sink->connect = NULL;
+	avdtp_unref(sink->session);
+	sink->session = NULL;
+}
+
+static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
+				void *user_data)
+{
+	struct video_sink *sink = user_data;
+	struct pending_request *pending;
+	int id;
+
+	if (!sink->connect) {
+		avdtp_unref(sink->session);
+		sink->session = NULL;
+		return;
+	}
+
+	pending = sink->connect;
+
+	if (err) {
+		avdtp_unref(sink->session);
+		sink->session = NULL;
+		if (avdtp_error_category(err) == AVDTP_ERRNO
+				&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
+			DBG("connect:connect XCASE detected");
+			sink->retry_id =
+				g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
+							stream_setup_retry,
+							sink);
+		} else
+			goto failed;
+		return;
+	}
+
+	DBG("Discovery complete");
+
+	id = vdp_select_capabilities(sink->session, AVDTP_SEP_TYPE_SINK, NULL,
+						select_complete, sink);
+	if (id == 0)
+		goto failed;
+
+	pending->id = id;
+	return;
+
+failed:
+	if (pending->msg)
+		error_failed(pending->conn, pending->msg, "Stream setup failed");
+	pending_request_free(sink->dev, pending);
+	sink->connect = NULL;
+	avdtp_unref(sink->session);
+	sink->session = NULL;
+}
+
+gboolean video_sink_setup_stream(struct video_sink *sink, struct avdtp *session)
+{
+	if (sink->connect || sink->disconnect)
+		return FALSE;
+
+	if (session && !sink->session)
+		sink->session = avdtp_ref(session);
+
+	if (!sink->session)
+		return FALSE;
+
+	avdtp_set_auto_disconnect(sink->session, FALSE);
+
+	if (avdtp_discover(sink->session, discovery_complete, sink) < 0)
+		return FALSE;
+
+	sink->connect = g_new0(struct pending_request, 1);
+
+	return TRUE;
+}
+
+static DBusMessage *sink_connect(DBusConnection *conn,
+				DBusMessage *msg, void *data)
+{
+	struct audio_device *dev = data;
+	struct video_sink *sink = dev->video_sink;
+	struct pending_request *pending;
+	DBG("Hi sink connect called");
+	if (!conn)
+		DBG("No DBus connection found");
+      
+	if (!data){
+		DBG("no data as dev");
+		return NULL;
+	  
+	}
+	
+	if (!sink->session)
+		sink->session = avdtp_get(&dev->src, &dev->dst);
+
+	if (!sink->session)
+		return btd_error_failed(msg, "Unable to get a session");
+
+	if (sink->connect || sink->disconnect)
+		return btd_error_busy(msg);
+
+	if (sink->stream_state >= AVDTP_STATE_OPEN)
+		return btd_error_already_connected(msg);
+	
+	if (!video_sink_setup_stream(sink, NULL))
+		return btd_error_failed(msg, "Failed to create a stream");
+	
+	dev->auto_connect = FALSE;
+
+	pending = sink->connect;
+
+	pending->conn = dbus_connection_ref(conn);
+	pending->msg = dbus_message_ref(msg);
+
+	DBG("stream creation in progress");
+
+	return NULL;
+}
+
+static DBusMessage *sink_disconnect(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct audio_device *device = data;
+	struct video_sink *sink = device->video_sink;
+	struct pending_request *pending;
+	int err;
+
+	if (!sink->session)
+		return btd_error_not_connected(msg);
+
+	if (sink->connect || sink->disconnect)
+		return btd_error_busy(msg);
+
+	if (sink->stream_state < AVDTP_STATE_OPEN) {
+		DBusMessage *reply = dbus_message_new_method_return(msg);
+		if (!reply)
+			return NULL;
+		avdtp_unref(sink->session);
+		sink->session = NULL;
+		return reply;
+	}
+
+	err = avdtp_close(sink->session, sink->stream, FALSE);
+	if (err < 0)
+		return btd_error_failed(msg, strerror(-err));
+
+	pending = g_new0(struct pending_request, 1);
+	pending->conn = dbus_connection_ref(conn);
+	pending->msg = dbus_message_ref(msg);
+	sink->disconnect = pending;
+
+	return NULL;
+}
+
+static DBusMessage *sink_is_connected(DBusConnection *conn,
+					DBusMessage *msg,
+					void *data)
+{
+	
+	struct audio_device *device = data;
+	struct video_sink *sink = device->video_sink;
+	DBusMessage *reply;
+	dbus_bool_t connected;
+ 
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return NULL;
+
+	connected = (sink->stream_state >= AVDTP_STATE_CONFIGURED);
+
+	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
+					DBUS_TYPE_INVALID);
+	if (sink->stream_state == AVDTP_STATE_IDLE)
+		DBG("state is idle");
+	else if (sink->stream_state == AVDTP_STATE_CONFIGURED)
+		DBG("state is configured");
+	else if (sink->stream_state == AVDTP_STATE_OPEN)
+		DBG("state is open");
+	if (connected)
+		DBG("connected");
+	else 
+		DBG("not connected");
+	return reply;
+}
+
+
+
+static DBusMessage *sink_get_properties(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct audio_device *device = data;
+	struct video_sink *sink = device->video_sink;
+	DBusMessage *reply;
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	const char *state;
+	gboolean value;
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return NULL;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	/* Playing */
+	value = (sink->stream_state == AVDTP_STATE_STREAMING);
+	dict_append_entry(&dict, "Playing", DBUS_TYPE_BOOLEAN, &value);
+
+	/* Connected */
+	value = (sink->stream_state >= AVDTP_STATE_CONFIGURED);
+	dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);
+
+	/* State */
+	state = state2str(sink->state);
+	if (state)
+		dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	return reply;
+}
+
+static GDBusMethodTable sink_methods[] = {
+	{ "Connect",		"",	"",	sink_connect,
+						G_DBUS_METHOD_FLAG_ASYNC },
+	{ "Disconnect",		"",	"",	sink_disconnect,
+						G_DBUS_METHOD_FLAG_ASYNC },
+	{ "IsConnected",	"",	"b",	sink_is_connected,
+						G_DBUS_METHOD_FLAG_DEPRECATED },
+	{ "GetProperties",	"",	"a{sv}",sink_get_properties },
+	{ NULL, NULL, NULL, NULL }
+};
+
+static GDBusSignalTable sink_signals[] = {
+	{ "Connected",			"",	G_DBUS_SIGNAL_FLAG_DEPRECATED },
+	{ "Disconnected",		"",	G_DBUS_SIGNAL_FLAG_DEPRECATED },
+	{ "Playing",			"",	G_DBUS_SIGNAL_FLAG_DEPRECATED },
+	{ "Stopped",			"",	G_DBUS_SIGNAL_FLAG_DEPRECATED },
+	{ "PropertyChanged",		"sv"	},
+	{ NULL, NULL }
+};
+
+static void sink_free(struct audio_device *dev)
+{
+	struct video_sink *sink = dev->video_sink;
+
+	if (sink->cb_id)
+		avdtp_stream_remove_cb(sink->session, sink->stream,
+					sink->cb_id);
+
+	if (sink->session)
+		avdtp_unref(sink->session);
+
+	if (sink->connect)
+		pending_request_free(dev, sink->connect);
+
+	if (sink->disconnect)
+		pending_request_free(dev, sink->disconnect);
+
+	if (sink->retry_id)
+		g_source_remove(sink->retry_id);
+
+	g_free(sink);
+	dev->video_sink = NULL;
+}
+
+static void path_unregister(void *data)
+{
+	struct audio_device *dev = data;
+
+	DBG("Unregistered interface %s on path %s",
+		VIDEO_SINK_INTERFACE, dev->path);
+
+	sink_free(dev);
+}
+
+struct video_sink *video_sink_register(struct audio_device *dev)
+{
+	struct video_sink *sink;
+
+	if (!g_dbus_register_interface(dev->conn, dev->path,
+						VIDEO_SINK_INTERFACE,
+						sink_methods, sink_signals,
+						NULL, dev, path_unregister))
+		return NULL;
+
+	DBG("Registered interface %s on path %s", VIDEO_SINK_INTERFACE,
+								dev->path);
+
+	if (avdtp_callback_id == 0)
+		avdtp_callback_id = avdtp_add_state_cb(avdtp_state_callback,
+									NULL);
+
+	sink = g_new0(struct video_sink, 1);
+
+	sink->dev = dev;
+
+	return sink;
+}
+
+gboolean video_sink_new_stream(struct audio_device *dev, struct avdtp *session,
+				struct avdtp_stream *stream)
+{
+	struct video_sink *sink = dev->video_sink;
+
+	if (sink->stream)
+		return FALSE;
+
+	if (!sink->session)
+		sink->session = avdtp_ref(session);
+
+	sink->stream = stream;
+
+	sink->cb_id = avdtp_stream_add_cb(session, stream,
+						stream_state_changed, dev);
+
+	return TRUE;
+}
\ No newline at end of file
diff --git a/audio/video-sink.h b/audio/video-sink.h
new file mode 100644
index 0000000..0ecb840
--- /dev/null
+++ b/audio/video-sink.h
@@ -0,0 +1,44 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#define VIDEO_SINK_INTERFACE "org.bluez.VideoSink"
+
+typedef enum {
+	VIDEO_SINK_STATE_DISCONNECTED,
+	VIDEO_SINK_STATE_CONNECTING,
+	VIDEO_SINK_STATE_CONNECTED,
+	VIDEO_SINK_STATE_PLAYING,
+} video_sink_state_t;
+
+typedef void (*video_sink_state_cb) (struct audio_device *dev,
+				video_sink_state_t old_state,
+				video_sink_state_t new_state,
+				void *user_data);
+struct video_sink *video_sink_register(struct audio_device *dev);
+void video_sink_unregister(struct audio_device *dev);
+
+gboolean video_sink_new_stream(struct audio_device *dev, struct avdtp *session,
+						struct avdtp_stream *stream);
+gboolean video_sink_setup_stream(struct video_sink *sink, struct avdtp *session);
+ 
\ No newline at end of file
-- 
1.7.6


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH BlueZ 3/6] Initial video-source implementation for VDP
  2011-08-16 13:43 [PATCH BlueZ 1/6] Initial VDP implementation Prasad Bhat
  2011-08-16 13:43 ` [PATCH BlueZ 2/6] Implementation of video-sink for VDP Prasad Bhat
@ 2011-08-16 13:43 ` Prasad Bhat
  2011-08-18  7:17   ` Luiz Augusto von Dentz
  2011-08-16 13:43 ` [PATCH BlueZ 4/6] The changes in media.c required " Prasad Bhat
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Prasad Bhat @ 2011-08-16 13:43 UTC (permalink / raw)
  To: linux-bluetooth

---
 Makefile.am          |    1 +
 audio/video-source.c |  570 ++++++++++++++++++++++++++++++++++++++++++++++++++
 audio/video-source.h |   45 ++++
 3 files changed, 616 insertions(+), 0 deletions(-)
 create mode 100644 audio/video-source.c
 create mode 100644 audio/video-source.h

diff --git a/Makefile.am b/Makefile.am
index 87b32a4..5498543 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -143,6 +143,7 @@ builtin_sources += audio/main.c \
 			audio/a2dp.h audio/a2dp.c \
 			audio/vdp.h audio/vdp.c \
 			audio/video-sink.h audio/video-sink.c \
+			audio/video-source.h audio/video-source.c \
 			audio/avdtp.h audio/avdtp.c \
 			audio/ipc.h audio/ipc.c \
 			audio/unix.h audio/unix.c \
diff --git a/audio/video-source.c b/audio/video-source.c
new file mode 100644
index 0000000..aa71de7
--- /dev/null
+++ b/audio/video-source.c
@@ -0,0 +1,570 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2009  Joao Paulo Rechi Vita
+ *  Copyright (C) 2011 Prasad Bhat <prasadbhat22@gmail.com>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "log.h"
+
+#include "device.h"
+#include "avdtp.h"
+#include "media.h"
+#include "vdp.h"
+#include "error.h"
+#include "video-source.h"
+#include "dbus-common.h"
+#include "../src/adapter.h"
+#include "../src/device.h"
+
+#define STREAM_SETUP_RETRY_TIMER 2
+
+struct pending_request {
+	DBusConnection *conn;
+	DBusMessage *msg;
+	unsigned int id;
+};
+
+struct video_source {
+	struct audio_device *dev;
+	struct avdtp *session;
+	struct avdtp_stream *stream;
+	unsigned int cb_id;
+	guint retry_id;
+	avdtp_session_state_t session_state;
+	avdtp_state_t stream_state;
+	video_source_state_t state;
+	struct pending_request *connect;
+	struct pending_request *disconnect;
+	DBusConnection *conn;
+};
+
+struct video_source_state_callback {
+	video_source_state_cb cb;
+	void *user_data;
+	unsigned int id;
+};
+
+static GSList *source_callbacks = NULL;
+
+static unsigned int avdtp_callback_id = 0;
+
+static const char *state2str(video_source_state_t state)
+{
+	switch (state) {
+	case VIDEO_SOURCE_STATE_DISCONNECTED:
+		return "disconnected";
+	case VIDEO_SOURCE_STATE_CONNECTING:
+		return "connecting";
+	case VIDEO_SOURCE_STATE_CONNECTED:
+		return "connected";
+	case VIDEO_SOURCE_STATE_PLAYING:
+		return "playing";
+	default:
+		error("Invalid source state %d", state);
+		return NULL;
+	}
+}
+
+static void source_set_state(struct audio_device *dev, video_source_state_t new_state)
+{
+	struct video_source *source = dev->video_source;
+	const char *state_str;
+	video_source_state_t old_state = source->state;
+	GSList *l;
+
+	source->state = new_state;
+
+	state_str = state2str(new_state);
+	if (state_str)
+		emit_property_changed(dev->conn, dev->path,
+					VIDEO_SOURCE_INTERFACE, "State",
+					DBUS_TYPE_STRING, &state_str);
+
+	for (l = source_callbacks; l != NULL; l = l->next) {
+		struct video_source_state_callback *cb = l->data;
+		cb->cb(dev, old_state, new_state, cb->user_data);
+	}
+}
+
+static void avdtp_state_callback(struct audio_device *dev,
+					struct avdtp *session,
+					avdtp_session_state_t old_state,
+					avdtp_session_state_t new_state,
+					void *user_data)
+{
+	struct video_source *source = dev->video_source;
+
+	if (source == NULL)
+		return;
+
+	switch (new_state) {
+	case AVDTP_SESSION_STATE_DISCONNECTED:
+		source_set_state(dev, VIDEO_SOURCE_STATE_DISCONNECTED);
+		break;
+	case AVDTP_SESSION_STATE_CONNECTING:
+		source_set_state(dev, VIDEO_SOURCE_STATE_CONNECTING);
+		break;
+	case AVDTP_SESSION_STATE_CONNECTED:
+		break;
+	}
+
+	source->session_state = new_state;
+}
+
+static void pending_request_free(struct audio_device *dev,
+					struct pending_request *pending)
+{
+	if (pending->conn)
+		dbus_connection_unref(pending->conn);
+	if (pending->msg)
+		dbus_message_unref(pending->msg);
+	if (pending->id)
+		vdp_cancel(dev, pending->id);
+
+	g_free(pending);
+}
+
+static void stream_state_changed(struct avdtp_stream *stream,
+					avdtp_state_t old_state,
+					avdtp_state_t new_state,
+					struct avdtp_error *err,
+					void *user_data)
+{
+	struct audio_device *dev = user_data;
+	struct video_source *source = dev->video_source;
+
+	if (err)
+		return;
+
+	switch (new_state) {
+	case AVDTP_STATE_IDLE:
+		if (source->disconnect) {
+			DBusMessage *reply;
+			struct pending_request *p;
+
+			p = source->disconnect;
+			source->disconnect = NULL;
+
+			reply = dbus_message_new_method_return(p->msg);
+			g_dbus_send_message(p->conn, reply);
+			pending_request_free(dev, p);
+		}
+
+		if (source->session) {
+			avdtp_unref(source->session);
+			source->session = NULL;
+		}
+		source->stream = NULL;
+		source->cb_id = 0;
+		break;
+	case AVDTP_STATE_OPEN:
+		source_set_state(dev, VIDEO_SOURCE_STATE_CONNECTED);
+		break;
+	case AVDTP_STATE_STREAMING:
+		source_set_state(dev, VIDEO_SOURCE_STATE_PLAYING);
+		break;
+	case AVDTP_STATE_CONFIGURED:
+	case AVDTP_STATE_CLOSING:
+	case AVDTP_STATE_ABORTING:
+	default:
+		break;
+	}
+
+	source->stream_state = new_state;
+}
+
+static void error_failed(DBusConnection *conn, DBusMessage *msg,
+							const char *desc)
+{
+	DBusMessage *reply = btd_error_failed(msg, desc);
+	g_dbus_send_message(conn, reply);
+}
+
+static gboolean stream_setup_retry(gpointer user_data)
+{
+	struct video_source *source = user_data;
+	struct pending_request *pending = source->connect;
+
+	source->retry_id = 0;
+
+	if (source->stream_state >= AVDTP_STATE_OPEN) {
+		DBG("Stream successfully created, after XCASE connect:connect");
+		if (pending->msg) {
+			DBusMessage *reply;
+			reply = dbus_message_new_method_return(pending->msg);
+			g_dbus_send_message(pending->conn, reply);
+		}
+	} else {
+		DBG("Stream setup failed, after XCASE connect:connect");
+		if (pending->msg)
+			error_failed(pending->conn, pending->msg, "Stream setup failed");
+	}
+
+	source->connect = NULL;
+	pending_request_free(source->dev, pending);
+
+	return FALSE;
+}
+
+static void stream_setup_complete(struct avdtp *session, struct vdp_sep *sep,
+					struct avdtp_stream *stream,
+					struct avdtp_error *err, void *user_data)
+{
+	struct video_source *source = user_data;
+	struct pending_request *pending;
+
+	pending = source->connect;
+
+	pending->id = 0;
+
+	if (stream) {
+		DBG("Stream successfully created");
+
+		if (pending->msg) {
+			DBusMessage *reply;
+			reply = dbus_message_new_method_return(pending->msg);
+			g_dbus_send_message(pending->conn, reply);
+		}
+
+		source->connect = NULL;
+		pending_request_free(source->dev, pending);
+
+		return;
+	}
+
+	avdtp_unref(source->session);
+	source->session = NULL;
+	if (avdtp_error_category(err) == AVDTP_ERRNO
+			&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
+		DBG("connect:connect XCASE detected");
+		source->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
+							stream_setup_retry,
+							source);
+	} else {
+		if (pending->msg)
+			error_failed(pending->conn, pending->msg, "Stream setup failed");
+		source->connect = NULL;
+		pending_request_free(source->dev, pending);
+		DBG("Stream setup failed : %s", avdtp_strerror(err));
+	}
+}
+
+static void select_complete(struct avdtp *session, struct vdp_sep *sep,
+			GSList *caps, void *user_data)
+{
+	struct video_source *source = user_data;
+	struct pending_request *pending;
+	int id;
+
+	pending = source->connect;
+
+	pending->id = 0;
+
+	if (caps == NULL)
+		goto failed;
+
+	id = vdp_config(session, sep, stream_setup_complete, caps, source);
+	if (id == 0)
+		goto failed;
+
+	pending->id = id;
+	return;
+
+failed:
+	if (pending->msg)
+		error_failed(pending->conn, pending->msg, "Stream setup failed");
+	pending_request_free(source->dev, pending);
+	source->connect = NULL;
+	avdtp_unref(source->session);
+	source->session = NULL;
+}
+
+static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
+				void *user_data)
+{
+	struct video_source *source = user_data;
+	struct pending_request *pending;
+	int id;
+
+	pending = source->connect;
+
+	if (err) {
+		avdtp_unref(source->session);
+		source->session = NULL;
+		if (avdtp_error_category(err) == AVDTP_ERRNO
+				&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
+			DBG("connect:connect XCASE detected");
+			source->retry_id =
+				g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
+							stream_setup_retry,
+							source);
+		} else
+			goto failed;
+		return;
+	}
+
+	DBG("Discovery complete");
+
+	id = vdp_select_capabilities(source->session, AVDTP_SEP_TYPE_SOURCE, NULL,
+						select_complete, source);
+	if (id == 0)
+		goto failed;
+
+	pending->id = id;
+	return;
+
+failed:
+	if (pending->msg)
+		error_failed(pending->conn, pending->msg, "Stream setup failed");
+	pending_request_free(source->dev, pending);
+	source->connect = NULL;
+	avdtp_unref(source->session);
+	source->session = NULL;
+}
+
+gboolean video_source_setup_stream(struct video_source *source, struct avdtp *session)
+{
+	if (source->connect || source->disconnect)
+		return FALSE;
+
+	if (session && !source->session)
+		source->session = avdtp_ref(session);
+
+	if (!source->session)
+		return FALSE;
+
+	avdtp_set_auto_disconnect(source->session, FALSE);
+
+	if (avdtp_discover(source->session, discovery_complete, source) < 0)
+		return FALSE;
+
+	source->connect = g_new0(struct pending_request, 1);
+
+	return TRUE;
+}
+
+static DBusMessage *source_connect(DBusConnection *conn,
+				DBusMessage *msg, void *data)
+{
+	struct audio_device *dev = data;
+	struct video_source *source = dev->video_source;
+	struct pending_request *pending;
+
+	if (!source->session)
+		source->session = avdtp_get(&dev->src, &dev->dst);
+
+	if (!source->session)
+		return btd_error_failed(msg, "Unable to get a session");
+
+	if (source->connect || source->disconnect)
+		return btd_error_busy(msg);
+
+	if (source->stream_state >= AVDTP_STATE_OPEN)
+		return btd_error_already_connected(msg);
+
+	if (!video_source_setup_stream(source, NULL))
+		return btd_error_failed(msg, "Failed to create a stream");
+
+	dev->auto_connect = FALSE;
+
+	pending = source->connect;
+
+	pending->conn = dbus_connection_ref(conn);
+	pending->msg = dbus_message_ref(msg);
+
+	DBG("stream creation in progress");
+
+	return NULL;
+}
+
+static DBusMessage *source_disconnect(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct audio_device *device = data;
+	struct video_source *source = device->video_source;
+	struct pending_request *pending;
+	int err;
+
+	if (!source->session)
+		return btd_error_not_connected(msg);
+
+	if (source->connect || source->disconnect)
+		return btd_error_busy(msg);
+
+	if (source->stream_state < AVDTP_STATE_OPEN) {
+		DBusMessage *reply = dbus_message_new_method_return(msg);
+		if (!reply)
+			return NULL;
+		avdtp_unref(source->session);
+		source->session = NULL;
+		return reply;
+	}
+
+	err = avdtp_close(source->session, source->stream, FALSE);
+	if (err < 0)
+		return btd_error_failed(msg, strerror(-err));
+
+	pending = g_new0(struct pending_request, 1);
+	pending->conn = dbus_connection_ref(conn);
+	pending->msg = dbus_message_ref(msg);
+	source->disconnect = pending;
+
+	return NULL;
+}
+
+static DBusMessage *source_get_properties(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct audio_device *device = data;
+	struct video_source *source = device->video_source;
+	DBusMessage *reply;
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	const char *state;
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return NULL;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	/* State */
+	state = state2str(source->state);
+	if (state)
+		dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	return reply;
+}
+
+static GDBusMethodTable source_methods[] = {
+	{ "Connect",		"",	"",	source_connect,
+						G_DBUS_METHOD_FLAG_ASYNC },
+	{ "Disconnect",		"",	"",	source_disconnect,
+						G_DBUS_METHOD_FLAG_ASYNC },
+	{ "GetProperties",	"",	"a{sv}",source_get_properties },
+	{ NULL, NULL, NULL, NULL }
+};
+
+
+static GDBusSignalTable source_signals[] = {
+	{ "PropertyChanged",		"sv"	},
+	{ NULL, NULL }
+};
+
+static void video_source_free(struct audio_device *dev)
+{
+	struct video_source *source = dev->video_source;
+
+	if (source->cb_id)
+		avdtp_stream_remove_cb(source->session, source->stream,
+					source->cb_id);
+
+	if (source->session)
+		avdtp_unref(source->session);
+
+	if (source->connect)
+		pending_request_free(dev, source->connect);
+
+	if (source->disconnect)
+		pending_request_free(dev, source->disconnect);
+
+	if (source->retry_id)
+		g_source_remove(source->retry_id);
+
+	g_free(source);
+	dev->source = NULL;
+}
+ 
+static void path_unregister(void *data)
+{
+	struct audio_device *dev = data;
+
+	DBG("Unregistered interface %s on path %s",
+		VIDEO_SOURCE_INTERFACE, dev->path);
+
+	video_source_free(dev);
+}
+
+struct video_source *video_source_register(struct audio_device *dev)
+{
+	struct video_source *source;
+
+	if (!g_dbus_register_interface(dev->conn, dev->path,
+					VIDEO_SOURCE_INTERFACE,
+					source_methods, source_signals, NULL,
+					dev, path_unregister))
+		return NULL;
+
+	DBG("Registered interface %s on path %s", VIDEO_SOURCE_INTERFACE,
+								dev->path);
+
+	if (avdtp_callback_id == 0)
+		avdtp_callback_id = avdtp_add_state_cb(avdtp_state_callback,
+									NULL);
+
+	source = g_new0(struct video_source, 1);
+
+	source->dev = dev;
+
+	return source;
+}
+
+gboolean video_source_new_stream(struct audio_device *dev, struct avdtp *session,
+				struct avdtp_stream *stream)
+{
+	struct video_source *source = dev->video_source;
+
+	if (source->stream)
+		return FALSE;
+
+	if (!source->session)
+		source->session = avdtp_ref(session);
+
+	source->stream = stream;
+
+	source->cb_id = avdtp_stream_add_cb(session, stream,
+						stream_state_changed, dev);
+
+	return TRUE;
+}
diff --git a/audio/video-source.h b/audio/video-source.h
new file mode 100644
index 0000000..97af55f
--- /dev/null
+++ b/audio/video-source.h
@@ -0,0 +1,45 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011 Prasad Bhat <prasadbhat22@gmail.com>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#define VIDEO_SOURCE_INTERFACE "org.bluez.VideoSource"
+
+typedef enum {
+	VIDEO_SOURCE_STATE_DISCONNECTED,
+	VIDEO_SOURCE_STATE_CONNECTING,
+	VIDEO_SOURCE_STATE_CONNECTED,
+	VIDEO_SOURCE_STATE_PLAYING,
+} video_source_state_t;
+
+typedef void (*video_source_state_cb) (struct audio_device *dev,
+				video_source_state_t old_state,
+				video_source_state_t new_state,
+				void *user_data);
+struct video_source *video_source_register(struct audio_device *dev);
+void video_source_unregister(struct audio_device *dev);
+
+gboolean video_source_new_stream(struct audio_device *dev,
+					struct avdtp *session,
+					struct avdtp_stream *stream);
+gboolean video_source_setup_stream(struct video_source *source, struct avdtp *session);
-- 
1.7.6


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH BlueZ 4/6] The changes in media.c required for VDP.
  2011-08-16 13:43 [PATCH BlueZ 1/6] Initial VDP implementation Prasad Bhat
  2011-08-16 13:43 ` [PATCH BlueZ 2/6] Implementation of video-sink for VDP Prasad Bhat
  2011-08-16 13:43 ` [PATCH BlueZ 3/6] Initial video-source implementation " Prasad Bhat
@ 2011-08-16 13:43 ` Prasad Bhat
  2011-08-18  7:20   ` Luiz Augusto von Dentz
  2011-08-16 13:43 ` [PATCH BlueZ 5/6] This adds video-sink and video-source interfaces and vdp_server_driver to audio/manager{.c, .h} Prasad Bhat
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Prasad Bhat @ 2011-08-16 13:43 UTC (permalink / raw)
  To: linux-bluetooth

---
 audio/media.c |  142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 141 insertions(+), 1 deletions(-)

diff --git a/audio/media.c b/audio/media.c
index 42d8637..0aff0d4 100644
--- a/audio/media.c
+++ b/audio/media.c
@@ -42,6 +42,7 @@
 #include "media.h"
 #include "transport.h"
 #include "a2dp.h"
+#include "vdp.h"
 #include "headset.h"
 #include "manager.h"
 
@@ -71,6 +72,7 @@ struct endpoint_request {
 
 struct media_endpoint {
 	struct a2dp_sep		*sep;
+	struct vdp_sep		*vdp_sep;
 	char			*sender;	/* Endpoint DBus bus id */
 	char			*path;		/* Endpoint object path */
 	char			*uuid;		/* Endpoint property UUID */
@@ -141,6 +143,10 @@ static void media_endpoint_remove(struct media_endpoint *endpoint)
 		return;
 	}
 
+	if (endpoint->vdp_sep) {
+		vdp_remove_sep(endpoint->vdp_sep);
+		return;
+	}
 	info("Endpoint unregistered: sender=%s path=%s", endpoint->sender,
 			endpoint->path);
 
@@ -539,6 +545,113 @@ static struct a2dp_endpoint a2dp_endpoint = {
 	.set_delay = set_delay
 };
 
+static const char *vdp_get_name(struct vdp_sep *sep, void *user_data)
+{
+	struct media_endpoint *endpoint = user_data;
+
+	return endpoint->sender;
+}
+
+static size_t vdp_get_capabilities(struct vdp_sep *sep, uint8_t **capabilities,
+							void *user_data)
+{
+	struct media_endpoint *endpoint = user_data;
+
+	*capabilities = endpoint->capabilities;
+	return endpoint->size;
+}
+
+struct vdp_config_data {
+	guint setup_id;
+	vdp_endpoint_config_t cb;
+};
+
+struct vdp_select_data {
+	guint setup_id;
+	vdp_endpoint_select_t cb;
+};
+
+static void vdp_select_cb(struct media_endpoint *endpoint, void *ret, int size,
+							void *user_data)
+{
+	struct vdp_select_data *data = user_data;
+
+	data->cb(endpoint->vdp_sep, data->setup_id, ret, size);
+}
+
+static int vdp_select_config(struct vdp_sep *sep, uint8_t *capabilities,
+				size_t length, guint setup_id,
+				vdp_endpoint_select_t cb, void *user_data)
+{
+	struct media_endpoint *endpoint = user_data;
+	struct vdp_select_data *data;
+
+	data = g_new0(struct vdp_select_data, 1);
+	data->setup_id = setup_id;
+	data->cb = cb;
+
+	if (select_configuration(endpoint, capabilities, length,
+					vdp_select_cb, data, g_free) == TRUE)
+		return 0;
+
+	g_free(data);
+	return -ENOMEM;
+}
+
+static void vdp_config_cb(struct media_endpoint *endpoint, void *ret, int size,
+							void *user_data)
+{
+	struct vdp_config_data *data = user_data;
+
+	data->cb(endpoint->vdp_sep, data->setup_id, ret ? TRUE : FALSE);
+}
+
+static int vdp_set_config(struct vdp_sep *sep, struct audio_device *dev,
+				uint8_t *configuration, size_t length,
+				guint setup_id, vdp_endpoint_config_t cb,
+				void *user_data)
+{
+	struct media_endpoint *endpoint = user_data;
+	struct vdp_config_data *data;
+
+	data = g_new0(struct vdp_config_data, 1);
+	data->setup_id = setup_id;
+	data->cb = cb;
+
+	if (set_configuration(endpoint, dev, configuration, length,
+					vdp_config_cb, data, g_free) == TRUE)
+		return 0;
+
+	g_free(data);
+	return -ENOMEM;
+}
+
+static void vdp_clear_config(struct vdp_sep *sep, void *user_data)
+{
+	struct media_endpoint *endpoint = user_data;
+
+	clear_configuration(endpoint);
+}
+
+static void vdp_set_delay(struct vdp_sep *sep, uint16_t delay, void *user_data)
+{
+	struct media_endpoint *endpoint = user_data;
+
+	if (endpoint->transport == NULL)
+		return;
+
+	media_transport_update_delay(endpoint->transport, delay);
+}
+
+static struct vdp_endpoint vdp_endpoint = {
+	.get_name = vdp_get_name,
+	.get_capabilities = vdp_get_capabilities,
+	.select_configuration = vdp_select_config,
+	.set_configuration = vdp_set_config,
+	.clear_configuration = vdp_clear_config,
+	.set_delay = vdp_set_delay
+};
+
 static void a2dp_destroy_endpoint(void *user_data)
 {
 	struct media_endpoint *endpoint = user_data;
@@ -552,6 +665,19 @@ static void a2dp_destroy_endpoint(void *user_data)
 	release_endpoint(endpoint);
 }
 
+static void vdp_destroy_endpoint(void *user_data)
+{
+	struct media_endpoint *endpoint = user_data;
+
+	if (endpoint->transport) {
+		media_transport_destroy(endpoint->transport);
+		endpoint->transport = NULL;
+	}
+
+	endpoint->sep = NULL;
+	release_endpoint(endpoint);
+}
+
 static struct media_endpoint *media_endpoint_create(struct media_adapter *adapter,
 						const char *sender,
 						const char *path,
@@ -592,7 +718,21 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
 					endpoint, a2dp_destroy_endpoint, err);
 		if (endpoint->sep == NULL)
 			goto failed;
-	} else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
+	} else if (strcasecmp(uuid, VDP_SOURCE_UUID) == 0) {
+ 		endpoint->vdp_sep = vdp_add_sep(&adapter->src,
+					AVDTP_SEP_TYPE_SOURCE, codec,
+					delay_reporting, &vdp_endpoint,
+					endpoint, vdp_destroy_endpoint, err);
+		if (endpoint->vdp_sep == NULL)
+			goto failed;
+	} else if (strcasecmp(uuid, VDP_SINK_UUID) == 0) {
+		endpoint->vdp_sep = vdp_add_sep(&adapter->src,
+					AVDTP_SEP_TYPE_SINK, codec,
+					delay_reporting, &vdp_endpoint,
+					endpoint, vdp_destroy_endpoint, err);
+		if (endpoint->vdp_sep == NULL)
+			goto failed;
+	}else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
 					g_strcmp0(uuid, HSP_AG_UUID) == 0) {
 		struct audio_device *dev;
 
-- 
1.7.6


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH BlueZ 5/6] This adds video-sink and video-source interfaces and vdp_server_driver to audio/manager{.c, .h}
  2011-08-16 13:43 [PATCH BlueZ 1/6] Initial VDP implementation Prasad Bhat
                   ` (2 preceding siblings ...)
  2011-08-16 13:43 ` [PATCH BlueZ 4/6] The changes in media.c required " Prasad Bhat
@ 2011-08-16 13:43 ` Prasad Bhat
  2011-08-18  7:21   ` Luiz Augusto von Dentz
  2011-08-16 13:43 ` [PATCH BlueZ 6/6] This adds video_sink and video_source to audio_device Prasad Bhat
  2011-08-18  7:11 ` [PATCH BlueZ 1/6] Initial VDP implementation Luiz Augusto von Dentz
  5 siblings, 1 reply; 12+ messages in thread
From: Prasad Bhat @ 2011-08-16 13:43 UTC (permalink / raw)
  To: linux-bluetooth

---
 audio/manager.c |   87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 audio/manager.h |    2 +
 2 files changed, 89 insertions(+), 0 deletions(-)

diff --git a/audio/manager.c b/audio/manager.c
index 6e583cf..352d91d 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -59,10 +59,13 @@
 #include "avdtp.h"
 #include "media.h"
 #include "a2dp.h"
+#include "vdp.h"
 #include "headset.h"
 #include "gateway.h"
 #include "sink.h"
 #include "source.h"
+#include "video-sink.h"
+#include "video-source.h"
 #include "control.h"
 #include "manager.h"
 #include "sdpd.h"
@@ -119,6 +122,8 @@ static struct enabled_interfaces enabled = {
 	.socket		= TRUE,
 	.media		= FALSE,
 	.media_player	= FALSE,
+	.video_sink	= FALSE,
+	.video_source	= FALSE,
 };
 
 static struct audio_adapter *find_adapter(GSList *list,
@@ -149,6 +154,10 @@ gboolean server_is_enabled(bdaddr_t *src, uint16_t svc)
 		return enabled.sink;
 	case AUDIO_SOURCE_SVCLASS_ID:
 		return enabled.source;
+	case VIDEO_SINK_SVCLASS_ID:
+		return enabled.video_sink;
+	case VIDEO_SOURCE_SVCLASS_ID:
+		return enabled.video_source;
 	case AV_REMOTE_TARGET_SVCLASS_ID:
 	case AV_REMOTE_SVCLASS_ID:
 		return enabled.control;
@@ -214,6 +223,16 @@ static void handle_uuid(const char *uuidstr, struct audio_device *device)
 		if (device->source == NULL)
 			device->source = source_init(device);
 		break;
+	case VIDEO_SINK_SVCLASS_ID:
+		DBG("Found Video Sink");
+		if (device->video_sink == NULL)
+			device->video_sink = video_sink_register(device);
+		break;
+	case VIDEO_SOURCE_SVCLASS_ID:
+		DBG("Found Video Source");
+		if (device->video_source == NULL)	
+			device->video_source = video_source_register(device);
+		break;
 	case AV_REMOTE_SVCLASS_ID:
 	case AV_REMOTE_TARGET_SVCLASS_ID:
 		DBG("Found AV %s", uuid16 == AV_REMOTE_SVCLASS_ID ?
@@ -1035,6 +1054,45 @@ static void a2dp_server_remove(struct btd_adapter *adapter)
 	audio_adapter_unref(adp);
 }
 
+static int vdp_server_probe(struct btd_adapter *adapter)
+{
+	struct audio_adapter *adp;
+	const gchar *path = adapter_get_path(adapter);
+	bdaddr_t src;
+	int err;
+
+	DBG("path %s", path);
+
+	adp = audio_adapter_get(adapter);
+	if (!adp)
+		return -EINVAL;
+
+	adapter_get_address(adapter, &src);
+
+	err = vdp_register(connection, &src, config);
+	if (err < 0)
+		audio_adapter_unref(adp);
+
+	return err;
+}
+
+static void vdp_server_remove(struct btd_adapter *adapter)
+{
+	struct audio_adapter *adp;
+	const gchar *path = adapter_get_path(adapter);
+	bdaddr_t src;
+
+	DBG("path %s", path);
+
+	adp = find_adapter(adapters, adapter);
+	if (!adp)
+		return;
+
+	adapter_get_address(adapter, &src);
+	vdp_unregister(&src);
+	audio_adapter_unref(adp);
+}
+
 static int avrcp_server_probe(struct btd_adapter *adapter)
 {
 	struct audio_adapter *adp;
@@ -1105,6 +1163,7 @@ static struct btd_device_driver audio_driver = {
 	.name	= "audio",
 	.uuids	= BTD_UUIDS(HSP_HS_UUID, HFP_HS_UUID, HSP_AG_UUID, HFP_AG_UUID,
 			ADVANCED_AUDIO_UUID, A2DP_SOURCE_UUID, A2DP_SINK_UUID,
+			VIDEO_DISTRIBUTION_UUID, VDP_SOURCE_UUID, VDP_SINK_UUID,
 			AVRCP_TARGET_UUID, AVRCP_REMOTE_UUID),
 	.probe	= audio_probe,
 	.remove	= audio_remove,
@@ -1128,6 +1187,12 @@ static struct btd_adapter_driver a2dp_server_driver = {
 	.remove	= a2dp_server_remove,
 };
 
+static struct btd_adapter_driver vdp_server_driver = {
+	.name	= "video-vdp",
+	.probe	= vdp_server_probe,
+	.remove	= vdp_server_remove,
+};
+
 static struct btd_adapter_driver avrcp_server_driver = {
 	.name	= "audio-control",
 	.probe	= avrcp_server_probe,
@@ -1166,6 +1231,10 @@ int audio_manager_init(DBusConnection *conn, GKeyFile *conf,
 			enabled.sink = TRUE;
 		else if (g_str_equal(list[i], "Source"))
 			enabled.source = TRUE;
+		else if (g_str_equal(list[i], "VideoSink"))
+			enabled.video_sink = TRUE;
+		else if (g_str_equal(list[i], "VideoSource"))
+			enabled.video_source = TRUE;
 		else if (g_str_equal(list[i], "Control"))
 			enabled.control = TRUE;
 		else if (g_str_equal(list[i], "Socket"))
@@ -1189,6 +1258,10 @@ int audio_manager_init(DBusConnection *conn, GKeyFile *conf,
 			enabled.sink = FALSE;
 		else if (g_str_equal(list[i], "Source"))
 			enabled.source = FALSE;
+		else if (g_str_equal(list[i], "VideoSink"))
+			enabled.video_sink = FALSE;
+		else if (g_str_equal(list[i], "VideoSource"))
+			enabled.video_source = FALSE;
 		else if (g_str_equal(list[i], "Control"))
 			enabled.control = FALSE;
 		else if (g_str_equal(list[i], "Socket"))
@@ -1239,6 +1312,9 @@ proceed:
 	if (enabled.source || enabled.sink)
 		btd_register_adapter_driver(&a2dp_server_driver);
 
+	if (enabled.video_source || enabled.video_sink)
+		btd_register_adapter_driver(&vdp_server_driver);
+
 	if (enabled.control)
 		btd_register_adapter_driver(&avrcp_server_driver);
 
@@ -1278,6 +1354,9 @@ void audio_manager_exit(void)
 	if (enabled.source || enabled.sink)
 		btd_unregister_adapter_driver(&a2dp_server_driver);
 
+	if (enabled.video_source || enabled.video_sink)
+		btd_unregister_adapter_driver(&vdp_server_driver);
+
 	if (enabled.control)
 		btd_unregister_adapter_driver(&avrcp_server_driver);
 
@@ -1320,6 +1399,14 @@ struct audio_device *manager_find_device(const char *path,
 				&& !dev->source)
 			continue;
 
+		if (interface && !strcmp(VIDEO_SINK_INTERFACE, interface)
+				&& !dev->video_sink)
+			continue;
+	
+		if (interface && !strcmp(VIDEO_SOURCE_INTERFACE, interface)
+				&& !dev->video_source)
+			continue;
+
 		if (interface && !strcmp(AUDIO_CONTROL_INTERFACE, interface)
 				&& !dev->control)
 			continue;
diff --git a/audio/manager.h b/audio/manager.h
index cfc646c..6c61da4 100644
--- a/audio/manager.h
+++ b/audio/manager.h
@@ -28,6 +28,8 @@ struct enabled_interfaces {
 	gboolean gateway;
 	gboolean sink;
 	gboolean source;
+	gboolean video_sink;
+	gboolean video_source;
 	gboolean control;
 	gboolean socket;
 	gboolean media;
-- 
1.7.6


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH BlueZ 6/6] This adds video_sink and video_source to audio_device.
  2011-08-16 13:43 [PATCH BlueZ 1/6] Initial VDP implementation Prasad Bhat
                   ` (3 preceding siblings ...)
  2011-08-16 13:43 ` [PATCH BlueZ 5/6] This adds video-sink and video-source interfaces and vdp_server_driver to audio/manager{.c, .h} Prasad Bhat
@ 2011-08-16 13:43 ` Prasad Bhat
  2011-08-18  7:31   ` Luiz Augusto von Dentz
  2011-08-18  7:11 ` [PATCH BlueZ 1/6] Initial VDP implementation Luiz Augusto von Dentz
  5 siblings, 1 reply; 12+ messages in thread
From: Prasad Bhat @ 2011-08-16 13:43 UTC (permalink / raw)
  To: linux-bluetooth

---
 audio/device.h |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/audio/device.h b/audio/device.h
index 5117fca..661f112 100644
--- a/audio/device.h
+++ b/audio/device.h
@@ -38,6 +38,11 @@
 #define AVRCP_REMOTE_UUID	"0000110e-0000-1000-8000-00805f9b34fb"
 #define AVRCP_TARGET_UUID	"0000110c-0000-1000-8000-00805f9b34fb"
 
+#define VIDEO_DISTRIBUTION_UUID "00001305-0000-1000-8000-00805f9b34fb"
+
+#define VDP_SOURCE_UUID	"00001303-0000-1000-8000-00805f9b34fb"
+#define VDP_SINK_UUID		"00001304-0000-1000-8000-00805f9b34fb"
+
 struct source;
 struct control;
 struct target;
@@ -62,6 +67,8 @@ struct audio_device {
 	struct source *source;
 	struct control *control;
 	struct target *target;
+	struct video_sink *video_sink;
+	struct video_source *video_source;
 
 	guint hs_preauth_id;
 
-- 
1.7.6


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH BlueZ 1/6] Initial VDP implementation
  2011-08-16 13:43 [PATCH BlueZ 1/6] Initial VDP implementation Prasad Bhat
                   ` (4 preceding siblings ...)
  2011-08-16 13:43 ` [PATCH BlueZ 6/6] This adds video_sink and video_source to audio_device Prasad Bhat
@ 2011-08-18  7:11 ` Luiz Augusto von Dentz
  5 siblings, 0 replies; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2011-08-18  7:11 UTC (permalink / raw)
  To: Prasad Bhat; +Cc: linux-bluetooth

Hi

On Tue, Aug 16, 2011 at 4:43 PM, Prasad Bhat <prasadbhat22@gmail.com> wrote:
> ---
>  Makefile.am |    1 +
>  audio/vdp.c | 2026 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  audio/vdp.h |  112 ++++
>  3 files changed, 2139 insertions(+), 0 deletions(-)
>  create mode 100644 audio/vdp.c
>  create mode 100644 audio/vdp.h
>

This is pretty much a duplicate of a2dp.{c,h}, so it would be nice to
have this in a common file e.g. sep.{c,h} as suggested last time.

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH BlueZ 2/6] Implementation of video-sink for VDP
  2011-08-16 13:43 ` [PATCH BlueZ 2/6] Implementation of video-sink for VDP Prasad Bhat
@ 2011-08-18  7:14   ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2011-08-18  7:14 UTC (permalink / raw)
  To: Prasad Bhat; +Cc: linux-bluetooth

Hi,

On Tue, Aug 16, 2011 at 4:43 PM, Prasad Bhat <prasadbhat22@gmail.com> wrote:
> +static GDBusMethodTable sink_methods[] = {
> +       { "Connect",            "",     "",     sink_connect,
> +                                               G_DBUS_METHOD_FLAG_ASYNC },
> +       { "Disconnect",         "",     "",     sink_disconnect,
> +                                               G_DBUS_METHOD_FLAG_ASYNC },
> +       { "IsConnected",        "",     "b",    sink_is_connected,
> +                                               G_DBUS_METHOD_FLAG_DEPRECATED },

I guess we won't need a deprecated method here.

> +       { "GetProperties",      "",     "a{sv}",sink_get_properties },
> +       { NULL, NULL, NULL, NULL }
> +};
> +
> +static GDBusSignalTable sink_signals[] = {
> +       { "Connected",                  "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
> +       { "Disconnected",               "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
> +       { "Playing",                    "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
> +       { "Stopped",                    "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },

And here too. Please remember to remove in other parts of the code too.

> +       { "PropertyChanged",            "sv"    },
> +       { NULL, NULL }
> +};
> +

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH BlueZ 3/6] Initial video-source implementation for VDP
  2011-08-16 13:43 ` [PATCH BlueZ 3/6] Initial video-source implementation " Prasad Bhat
@ 2011-08-18  7:17   ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2011-08-18  7:17 UTC (permalink / raw)
  To: Prasad Bhat; +Cc: linux-bluetooth

Hi,

On Tue, Aug 16, 2011 at 4:43 PM, Prasad Bhat <prasadbhat22@gmail.com> wrote:
> ---
>  Makefile.am          |    1 +
>  audio/video-source.c |  570 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  audio/video-source.h |   45 ++++
>  3 files changed, 616 insertions(+), 0 deletions(-)
>  create mode 100644 audio/video-source.c
>  create mode 100644 audio/video-source.h
>
> diff --git a/Makefile.am b/Makefile.am
> index 87b32a4..5498543 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -143,6 +143,7 @@ builtin_sources += audio/main.c \
>                        audio/a2dp.h audio/a2dp.c \
>                        audio/vdp.h audio/vdp.c \
>                        audio/video-sink.h audio/video-sink.c \
> +                       audio/video-source.h audio/video-source.c \
>                        audio/avdtp.h audio/avdtp.c \
>                        audio/ipc.h audio/ipc.c \
>                        audio/unix.h audio/unix.c \
> diff --git a/audio/video-source.c b/audio/video-source.c
> new file mode 100644
> index 0000000..aa71de7
> --- /dev/null
> +++ b/audio/video-source.c
> @@ -0,0 +1,570 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2006-2010  Nokia Corporation
> + *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
> + *  Copyright (C) 2009  Joao Paulo Rechi Vita
> + *  Copyright (C) 2011 Prasad Bhat <prasadbhat22@gmail.com>
> + *
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdint.h>
> +#include <errno.h>
> +
> +#include <bluetooth/bluetooth.h>
> +#include <bluetooth/sdp.h>
> +
> +#include <glib.h>
> +#include <dbus/dbus.h>
> +#include <gdbus.h>
> +
> +#include "log.h"
> +
> +#include "device.h"
> +#include "avdtp.h"
> +#include "media.h"
> +#include "vdp.h"
> +#include "error.h"
> +#include "video-source.h"
> +#include "dbus-common.h"
> +#include "../src/adapter.h"
> +#include "../src/device.h"
> +
> +#define STREAM_SETUP_RETRY_TIMER 2
> +
> +struct pending_request {
> +       DBusConnection *conn;
> +       DBusMessage *msg;
> +       unsigned int id;
> +};
> +
> +struct video_source {
> +       struct audio_device *dev;
> +       struct avdtp *session;
> +       struct avdtp_stream *stream;
> +       unsigned int cb_id;
> +       guint retry_id;
> +       avdtp_session_state_t session_state;
> +       avdtp_state_t stream_state;
> +       video_source_state_t state;
> +       struct pending_request *connect;
> +       struct pending_request *disconnect;
> +       DBusConnection *conn;
> +};
> +
> +struct video_source_state_callback {
> +       video_source_state_cb cb;
> +       void *user_data;
> +       unsigned int id;
> +};
> +
> +static GSList *source_callbacks = NULL;
> +
> +static unsigned int avdtp_callback_id = 0;
> +
> +static const char *state2str(video_source_state_t state)
> +{
> +       switch (state) {
> +       case VIDEO_SOURCE_STATE_DISCONNECTED:
> +               return "disconnected";
> +       case VIDEO_SOURCE_STATE_CONNECTING:
> +               return "connecting";
> +       case VIDEO_SOURCE_STATE_CONNECTED:
> +               return "connected";
> +       case VIDEO_SOURCE_STATE_PLAYING:
> +               return "playing";
> +       default:
> +               error("Invalid source state %d", state);
> +               return NULL;
> +       }
> +}
> +
> +static void source_set_state(struct audio_device *dev, video_source_state_t new_state)
> +{
> +       struct video_source *source = dev->video_source;
> +       const char *state_str;
> +       video_source_state_t old_state = source->state;
> +       GSList *l;
> +
> +       source->state = new_state;
> +
> +       state_str = state2str(new_state);
> +       if (state_str)
> +               emit_property_changed(dev->conn, dev->path,
> +                                       VIDEO_SOURCE_INTERFACE, "State",
> +                                       DBUS_TYPE_STRING, &state_str);
> +
> +       for (l = source_callbacks; l != NULL; l = l->next) {
> +               struct video_source_state_callback *cb = l->data;
> +               cb->cb(dev, old_state, new_state, cb->user_data);
> +       }
> +}
> +
> +static void avdtp_state_callback(struct audio_device *dev,
> +                                       struct avdtp *session,
> +                                       avdtp_session_state_t old_state,
> +                                       avdtp_session_state_t new_state,
> +                                       void *user_data)
> +{
> +       struct video_source *source = dev->video_source;
> +
> +       if (source == NULL)
> +               return;
> +
> +       switch (new_state) {
> +       case AVDTP_SESSION_STATE_DISCONNECTED:
> +               source_set_state(dev, VIDEO_SOURCE_STATE_DISCONNECTED);
> +               break;
> +       case AVDTP_SESSION_STATE_CONNECTING:
> +               source_set_state(dev, VIDEO_SOURCE_STATE_CONNECTING);
> +               break;
> +       case AVDTP_SESSION_STATE_CONNECTED:
> +               break;
> +       }
> +
> +       source->session_state = new_state;
> +}
> +
> +static void pending_request_free(struct audio_device *dev,
> +                                       struct pending_request *pending)
> +{
> +       if (pending->conn)
> +               dbus_connection_unref(pending->conn);
> +       if (pending->msg)
> +               dbus_message_unref(pending->msg);
> +       if (pending->id)
> +               vdp_cancel(dev, pending->id);
> +
> +       g_free(pending);
> +}
> +
> +static void stream_state_changed(struct avdtp_stream *stream,
> +                                       avdtp_state_t old_state,
> +                                       avdtp_state_t new_state,
> +                                       struct avdtp_error *err,
> +                                       void *user_data)
> +{
> +       struct audio_device *dev = user_data;
> +       struct video_source *source = dev->video_source;
> +
> +       if (err)
> +               return;
> +
> +       switch (new_state) {
> +       case AVDTP_STATE_IDLE:
> +               if (source->disconnect) {
> +                       DBusMessage *reply;
> +                       struct pending_request *p;
> +
> +                       p = source->disconnect;
> +                       source->disconnect = NULL;
> +
> +                       reply = dbus_message_new_method_return(p->msg);
> +                       g_dbus_send_message(p->conn, reply);
> +                       pending_request_free(dev, p);
> +               }
> +
> +               if (source->session) {
> +                       avdtp_unref(source->session);
> +                       source->session = NULL;
> +               }
> +               source->stream = NULL;
> +               source->cb_id = 0;
> +               break;
> +       case AVDTP_STATE_OPEN:
> +               source_set_state(dev, VIDEO_SOURCE_STATE_CONNECTED);
> +               break;
> +       case AVDTP_STATE_STREAMING:
> +               source_set_state(dev, VIDEO_SOURCE_STATE_PLAYING);
> +               break;
> +       case AVDTP_STATE_CONFIGURED:
> +       case AVDTP_STATE_CLOSING:
> +       case AVDTP_STATE_ABORTING:
> +       default:
> +               break;
> +       }
> +
> +       source->stream_state = new_state;
> +}
> +
> +static void error_failed(DBusConnection *conn, DBusMessage *msg,
> +                                                       const char *desc)
> +{
> +       DBusMessage *reply = btd_error_failed(msg, desc);
> +       g_dbus_send_message(conn, reply);
> +}
> +
> +static gboolean stream_setup_retry(gpointer user_data)
> +{
> +       struct video_source *source = user_data;
> +       struct pending_request *pending = source->connect;
> +
> +       source->retry_id = 0;
> +
> +       if (source->stream_state >= AVDTP_STATE_OPEN) {
> +               DBG("Stream successfully created, after XCASE connect:connect");
> +               if (pending->msg) {
> +                       DBusMessage *reply;
> +                       reply = dbus_message_new_method_return(pending->msg);
> +                       g_dbus_send_message(pending->conn, reply);
> +               }
> +       } else {
> +               DBG("Stream setup failed, after XCASE connect:connect");
> +               if (pending->msg)
> +                       error_failed(pending->conn, pending->msg, "Stream setup failed");
> +       }
> +
> +       source->connect = NULL;
> +       pending_request_free(source->dev, pending);
> +
> +       return FALSE;
> +}
> +
> +static void stream_setup_complete(struct avdtp *session, struct vdp_sep *sep,
> +                                       struct avdtp_stream *stream,
> +                                       struct avdtp_error *err, void *user_data)
> +{
> +       struct video_source *source = user_data;
> +       struct pending_request *pending;
> +
> +       pending = source->connect;
> +
> +       pending->id = 0;
> +
> +       if (stream) {
> +               DBG("Stream successfully created");
> +
> +               if (pending->msg) {
> +                       DBusMessage *reply;
> +                       reply = dbus_message_new_method_return(pending->msg);
> +                       g_dbus_send_message(pending->conn, reply);
> +               }
> +
> +               source->connect = NULL;
> +               pending_request_free(source->dev, pending);
> +
> +               return;
> +       }
> +
> +       avdtp_unref(source->session);
> +       source->session = NULL;
> +       if (avdtp_error_category(err) == AVDTP_ERRNO
> +                       && avdtp_error_posix_errno(err) != EHOSTDOWN) {
> +               DBG("connect:connect XCASE detected");
> +               source->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
> +                                                       stream_setup_retry,
> +                                                       source);
> +       } else {
> +               if (pending->msg)
> +                       error_failed(pending->conn, pending->msg, "Stream setup failed");
> +               source->connect = NULL;
> +               pending_request_free(source->dev, pending);
> +               DBG("Stream setup failed : %s", avdtp_strerror(err));
> +       }
> +}
> +
> +static void select_complete(struct avdtp *session, struct vdp_sep *sep,
> +                       GSList *caps, void *user_data)
> +{
> +       struct video_source *source = user_data;
> +       struct pending_request *pending;
> +       int id;
> +
> +       pending = source->connect;
> +
> +       pending->id = 0;
> +
> +       if (caps == NULL)
> +               goto failed;
> +
> +       id = vdp_config(session, sep, stream_setup_complete, caps, source);
> +       if (id == 0)
> +               goto failed;
> +
> +       pending->id = id;
> +       return;
> +
> +failed:
> +       if (pending->msg)
> +               error_failed(pending->conn, pending->msg, "Stream setup failed");
> +       pending_request_free(source->dev, pending);
> +       source->connect = NULL;
> +       avdtp_unref(source->session);
> +       source->session = NULL;
> +}
> +
> +static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
> +                               void *user_data)
> +{
> +       struct video_source *source = user_data;
> +       struct pending_request *pending;
> +       int id;
> +
> +       pending = source->connect;
> +
> +       if (err) {
> +               avdtp_unref(source->session);
> +               source->session = NULL;
> +               if (avdtp_error_category(err) == AVDTP_ERRNO
> +                               && avdtp_error_posix_errno(err) != EHOSTDOWN) {
> +                       DBG("connect:connect XCASE detected");
> +                       source->retry_id =
> +                               g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
> +                                                       stream_setup_retry,
> +                                                       source);
> +               } else
> +                       goto failed;
> +               return;
> +       }
> +
> +       DBG("Discovery complete");
> +
> +       id = vdp_select_capabilities(source->session, AVDTP_SEP_TYPE_SOURCE, NULL,
> +                                               select_complete, source);
> +       if (id == 0)
> +               goto failed;
> +
> +       pending->id = id;
> +       return;
> +
> +failed:
> +       if (pending->msg)
> +               error_failed(pending->conn, pending->msg, "Stream setup failed");
> +       pending_request_free(source->dev, pending);
> +       source->connect = NULL;
> +       avdtp_unref(source->session);
> +       source->session = NULL;
> +}
> +
> +gboolean video_source_setup_stream(struct video_source *source, struct avdtp *session)
> +{
> +       if (source->connect || source->disconnect)
> +               return FALSE;
> +
> +       if (session && !source->session)
> +               source->session = avdtp_ref(session);
> +
> +       if (!source->session)
> +               return FALSE;
> +
> +       avdtp_set_auto_disconnect(source->session, FALSE);
> +
> +       if (avdtp_discover(source->session, discovery_complete, source) < 0)
> +               return FALSE;
> +
> +       source->connect = g_new0(struct pending_request, 1);
> +
> +       return TRUE;
> +}
> +
> +static DBusMessage *source_connect(DBusConnection *conn,
> +                               DBusMessage *msg, void *data)
> +{
> +       struct audio_device *dev = data;
> +       struct video_source *source = dev->video_source;
> +       struct pending_request *pending;
> +
> +       if (!source->session)
> +               source->session = avdtp_get(&dev->src, &dev->dst);
> +
> +       if (!source->session)
> +               return btd_error_failed(msg, "Unable to get a session");
> +
> +       if (source->connect || source->disconnect)
> +               return btd_error_busy(msg);
> +
> +       if (source->stream_state >= AVDTP_STATE_OPEN)
> +               return btd_error_already_connected(msg);
> +
> +       if (!video_source_setup_stream(source, NULL))
> +               return btd_error_failed(msg, "Failed to create a stream");
> +
> +       dev->auto_connect = FALSE;
> +
> +       pending = source->connect;
> +
> +       pending->conn = dbus_connection_ref(conn);
> +       pending->msg = dbus_message_ref(msg);
> +
> +       DBG("stream creation in progress");
> +
> +       return NULL;
> +}
> +
> +static DBusMessage *source_disconnect(DBusConnection *conn,
> +                                       DBusMessage *msg, void *data)
> +{
> +       struct audio_device *device = data;
> +       struct video_source *source = device->video_source;
> +       struct pending_request *pending;
> +       int err;
> +
> +       if (!source->session)
> +               return btd_error_not_connected(msg);
> +
> +       if (source->connect || source->disconnect)
> +               return btd_error_busy(msg);
> +
> +       if (source->stream_state < AVDTP_STATE_OPEN) {
> +               DBusMessage *reply = dbus_message_new_method_return(msg);
> +               if (!reply)
> +                       return NULL;
> +               avdtp_unref(source->session);
> +               source->session = NULL;
> +               return reply;
> +       }
> +
> +       err = avdtp_close(source->session, source->stream, FALSE);
> +       if (err < 0)
> +               return btd_error_failed(msg, strerror(-err));
> +
> +       pending = g_new0(struct pending_request, 1);
> +       pending->conn = dbus_connection_ref(conn);
> +       pending->msg = dbus_message_ref(msg);
> +       source->disconnect = pending;
> +
> +       return NULL;
> +}
> +
> +static DBusMessage *source_get_properties(DBusConnection *conn,
> +                                       DBusMessage *msg, void *data)
> +{
> +       struct audio_device *device = data;
> +       struct video_source *source = device->video_source;
> +       DBusMessage *reply;
> +       DBusMessageIter iter;
> +       DBusMessageIter dict;
> +       const char *state;
> +
> +       reply = dbus_message_new_method_return(msg);
> +       if (!reply)
> +               return NULL;
> +
> +       dbus_message_iter_init_append(reply, &iter);
> +
> +       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
> +                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
> +                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
> +                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
> +
> +       /* State */
> +       state = state2str(source->state);
> +       if (state)
> +               dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state);
> +
> +       dbus_message_iter_close_container(&iter, &dict);
> +
> +       return reply;
> +}
> +
> +static GDBusMethodTable source_methods[] = {
> +       { "Connect",            "",     "",     source_connect,
> +                                               G_DBUS_METHOD_FLAG_ASYNC },
> +       { "Disconnect",         "",     "",     source_disconnect,
> +                                               G_DBUS_METHOD_FLAG_ASYNC },
> +       { "GetProperties",      "",     "a{sv}",source_get_properties },
> +       { NULL, NULL, NULL, NULL }
> +};
> +
> +
> +static GDBusSignalTable source_signals[] = {
> +       { "PropertyChanged",            "sv"    },
> +       { NULL, NULL }
> +};
> +
> +static void video_source_free(struct audio_device *dev)
> +{
> +       struct video_source *source = dev->video_source;
> +
> +       if (source->cb_id)
> +               avdtp_stream_remove_cb(source->session, source->stream,
> +                                       source->cb_id);
> +
> +       if (source->session)
> +               avdtp_unref(source->session);
> +
> +       if (source->connect)
> +               pending_request_free(dev, source->connect);
> +
> +       if (source->disconnect)
> +               pending_request_free(dev, source->disconnect);
> +
> +       if (source->retry_id)
> +               g_source_remove(source->retry_id);
> +
> +       g_free(source);
> +       dev->source = NULL;
> +}
> +
> +static void path_unregister(void *data)
> +{
> +       struct audio_device *dev = data;
> +
> +       DBG("Unregistered interface %s on path %s",
> +               VIDEO_SOURCE_INTERFACE, dev->path);
> +
> +       video_source_free(dev);
> +}
> +
> +struct video_source *video_source_register(struct audio_device *dev)
> +{
> +       struct video_source *source;
> +
> +       if (!g_dbus_register_interface(dev->conn, dev->path,
> +                                       VIDEO_SOURCE_INTERFACE,
> +                                       source_methods, source_signals, NULL,
> +                                       dev, path_unregister))
> +               return NULL;
> +
> +       DBG("Registered interface %s on path %s", VIDEO_SOURCE_INTERFACE,
> +                                                               dev->path);
> +
> +       if (avdtp_callback_id == 0)
> +               avdtp_callback_id = avdtp_add_state_cb(avdtp_state_callback,
> +                                                                       NULL);
> +
> +       source = g_new0(struct video_source, 1);
> +
> +       source->dev = dev;
> +
> +       return source;
> +}
> +
> +gboolean video_source_new_stream(struct audio_device *dev, struct avdtp *session,
> +                               struct avdtp_stream *stream)
> +{
> +       struct video_source *source = dev->video_source;
> +
> +       if (source->stream)
> +               return FALSE;
> +
> +       if (!source->session)
> +               source->session = avdtp_ref(session);
> +
> +       source->stream = stream;
> +
> +       source->cb_id = avdtp_stream_add_cb(session, stream,
> +                                               stream_state_changed, dev);
> +
> +       return TRUE;
> +}
> diff --git a/audio/video-source.h b/audio/video-source.h
> new file mode 100644
> index 0000000..97af55f
> --- /dev/null
> +++ b/audio/video-source.h
> @@ -0,0 +1,45 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2006-2010  Nokia Corporation
> + *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
> + *  Copyright (C) 2011 Prasad Bhat <prasadbhat22@gmail.com>
> + *
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
> + *
> + */
> +
> +#define VIDEO_SOURCE_INTERFACE "org.bluez.VideoSource"
> +
> +typedef enum {
> +       VIDEO_SOURCE_STATE_DISCONNECTED,
> +       VIDEO_SOURCE_STATE_CONNECTING,
> +       VIDEO_SOURCE_STATE_CONNECTED,
> +       VIDEO_SOURCE_STATE_PLAYING,
> +} video_source_state_t;
> +
> +typedef void (*video_source_state_cb) (struct audio_device *dev,
> +                               video_source_state_t old_state,
> +                               video_source_state_t new_state,
> +                               void *user_data);
> +struct video_source *video_source_register(struct audio_device *dev);
> +void video_source_unregister(struct audio_device *dev);
> +
> +gboolean video_source_new_stream(struct audio_device *dev,
> +                                       struct avdtp *session,
> +                                       struct avdtp_stream *stream);
> +gboolean video_source_setup_stream(struct video_source *source, struct avdtp *session);
> --
> 1.7.6

Ack, note that this does not contain any deprecated code.

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH BlueZ 4/6] The changes in media.c required for VDP.
  2011-08-16 13:43 ` [PATCH BlueZ 4/6] The changes in media.c required " Prasad Bhat
@ 2011-08-18  7:20   ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2011-08-18  7:20 UTC (permalink / raw)
  To: Prasad Bhat; +Cc: linux-bluetooth

Hi,

On Tue, Aug 16, 2011 at 4:43 PM, Prasad Bhat <prasadbhat22@gmail.com> wrote:
> ---
>  audio/media.c |  142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 141 insertions(+), 1 deletions(-)
>
> diff --git a/audio/media.c b/audio/media.c
> index 42d8637..0aff0d4 100644
> --- a/audio/media.c
> +++ b/audio/media.c
> @@ -42,6 +42,7 @@
>  #include "media.h"
>  #include "transport.h"
>  #include "a2dp.h"
> +#include "vdp.h"
>  #include "headset.h"
>  #include "manager.h"
>
> @@ -71,6 +72,7 @@ struct endpoint_request {
>
>  struct media_endpoint {
>        struct a2dp_sep         *sep;
> +       struct vdp_sep          *vdp_sep;
>        char                    *sender;        /* Endpoint DBus bus id */
>        char                    *path;          /* Endpoint object path */
>        char                    *uuid;          /* Endpoint property UUID */
> @@ -141,6 +143,10 @@ static void media_endpoint_remove(struct media_endpoint *endpoint)
>                return;
>        }
>
> +       if (endpoint->vdp_sep) {
> +               vdp_remove_sep(endpoint->vdp_sep);
> +               return;
> +       }
>        info("Endpoint unregistered: sender=%s path=%s", endpoint->sender,
>                        endpoint->path);
>
> @@ -539,6 +545,113 @@ static struct a2dp_endpoint a2dp_endpoint = {
>        .set_delay = set_delay
>  };
>
> +static const char *vdp_get_name(struct vdp_sep *sep, void *user_data)
> +{
> +       struct media_endpoint *endpoint = user_data;
> +
> +       return endpoint->sender;
> +}
> +
> +static size_t vdp_get_capabilities(struct vdp_sep *sep, uint8_t **capabilities,
> +                                                       void *user_data)
> +{
> +       struct media_endpoint *endpoint = user_data;
> +
> +       *capabilities = endpoint->capabilities;
> +       return endpoint->size;
> +}
> +
> +struct vdp_config_data {
> +       guint setup_id;
> +       vdp_endpoint_config_t cb;
> +};
> +
> +struct vdp_select_data {
> +       guint setup_id;
> +       vdp_endpoint_select_t cb;
> +};
> +
> +static void vdp_select_cb(struct media_endpoint *endpoint, void *ret, int size,
> +                                                       void *user_data)
> +{
> +       struct vdp_select_data *data = user_data;
> +
> +       data->cb(endpoint->vdp_sep, data->setup_id, ret, size);
> +}
> +
> +static int vdp_select_config(struct vdp_sep *sep, uint8_t *capabilities,
> +                               size_t length, guint setup_id,
> +                               vdp_endpoint_select_t cb, void *user_data)
> +{
> +       struct media_endpoint *endpoint = user_data;
> +       struct vdp_select_data *data;
> +
> +       data = g_new0(struct vdp_select_data, 1);
> +       data->setup_id = setup_id;
> +       data->cb = cb;
> +
> +       if (select_configuration(endpoint, capabilities, length,
> +                                       vdp_select_cb, data, g_free) == TRUE)
> +               return 0;
> +
> +       g_free(data);
> +       return -ENOMEM;
> +}
> +
> +static void vdp_config_cb(struct media_endpoint *endpoint, void *ret, int size,
> +                                                       void *user_data)
> +{
> +       struct vdp_config_data *data = user_data;
> +
> +       data->cb(endpoint->vdp_sep, data->setup_id, ret ? TRUE : FALSE);
> +}
> +
> +static int vdp_set_config(struct vdp_sep *sep, struct audio_device *dev,
> +                               uint8_t *configuration, size_t length,
> +                               guint setup_id, vdp_endpoint_config_t cb,
> +                               void *user_data)
> +{
> +       struct media_endpoint *endpoint = user_data;
> +       struct vdp_config_data *data;
> +
> +       data = g_new0(struct vdp_config_data, 1);
> +       data->setup_id = setup_id;
> +       data->cb = cb;
> +
> +       if (set_configuration(endpoint, dev, configuration, length,
> +                                       vdp_config_cb, data, g_free) == TRUE)
> +               return 0;
> +
> +       g_free(data);
> +       return -ENOMEM;
> +}
> +
> +static void vdp_clear_config(struct vdp_sep *sep, void *user_data)
> +{
> +       struct media_endpoint *endpoint = user_data;
> +
> +       clear_configuration(endpoint);
> +}
> +
> +static void vdp_set_delay(struct vdp_sep *sep, uint16_t delay, void *user_data)
> +{
> +       struct media_endpoint *endpoint = user_data;
> +
> +       if (endpoint->transport == NULL)
> +               return;
> +
> +       media_transport_update_delay(endpoint->transport, delay);
> +}
> +
> +static struct vdp_endpoint vdp_endpoint = {
> +       .get_name = vdp_get_name,
> +       .get_capabilities = vdp_get_capabilities,
> +       .select_configuration = vdp_select_config,
> +       .set_configuration = vdp_set_config,
> +       .clear_configuration = vdp_clear_config,
> +       .set_delay = vdp_set_delay
> +};
> +
>  static void a2dp_destroy_endpoint(void *user_data)
>  {
>        struct media_endpoint *endpoint = user_data;
> @@ -552,6 +665,19 @@ static void a2dp_destroy_endpoint(void *user_data)
>        release_endpoint(endpoint);
>  }
>
> +static void vdp_destroy_endpoint(void *user_data)
> +{
> +       struct media_endpoint *endpoint = user_data;
> +
> +       if (endpoint->transport) {
> +               media_transport_destroy(endpoint->transport);
> +               endpoint->transport = NULL;
> +       }
> +
> +       endpoint->sep = NULL;
> +       release_endpoint(endpoint);
> +}
> +
>  static struct media_endpoint *media_endpoint_create(struct media_adapter *adapter,
>                                                const char *sender,
>                                                const char *path,
> @@ -592,7 +718,21 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
>                                        endpoint, a2dp_destroy_endpoint, err);
>                if (endpoint->sep == NULL)
>                        goto failed;
> -       } else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
> +       } else if (strcasecmp(uuid, VDP_SOURCE_UUID) == 0) {
> +               endpoint->vdp_sep = vdp_add_sep(&adapter->src,
> +                                       AVDTP_SEP_TYPE_SOURCE, codec,
> +                                       delay_reporting, &vdp_endpoint,
> +                                       endpoint, vdp_destroy_endpoint, err);
> +               if (endpoint->vdp_sep == NULL)
> +                       goto failed;
> +       } else if (strcasecmp(uuid, VDP_SINK_UUID) == 0) {
> +               endpoint->vdp_sep = vdp_add_sep(&adapter->src,
> +                                       AVDTP_SEP_TYPE_SINK, codec,
> +                                       delay_reporting, &vdp_endpoint,
> +                                       endpoint, vdp_destroy_endpoint, err);
> +               if (endpoint->vdp_sep == NULL)
> +                       goto failed;
> +       }else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
>                                        g_strcmp0(uuid, HSP_AG_UUID) == 0) {
>                struct audio_device *dev;
>
> --
> 1.7.6

This is another reason why we want a common code to handle the seps,
so a2dp_sep and vdp_sep could be merged, in fact they represent the
same thing an AVDTP sep.

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH BlueZ 5/6] This adds video-sink and video-source interfaces and vdp_server_driver to audio/manager{.c, .h}
  2011-08-16 13:43 ` [PATCH BlueZ 5/6] This adds video-sink and video-source interfaces and vdp_server_driver to audio/manager{.c, .h} Prasad Bhat
@ 2011-08-18  7:21   ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2011-08-18  7:21 UTC (permalink / raw)
  To: Prasad Bhat; +Cc: linux-bluetooth

Hi,

On Tue, Aug 16, 2011 at 4:43 PM, Prasad Bhat <prasadbhat22@gmail.com> wrote:
> ---
>  audio/manager.c |   87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  audio/manager.h |    2 +
>  2 files changed, 89 insertions(+), 0 deletions(-)
>
> diff --git a/audio/manager.c b/audio/manager.c
> index 6e583cf..352d91d 100644
> --- a/audio/manager.c
> +++ b/audio/manager.c
> @@ -59,10 +59,13 @@
>  #include "avdtp.h"
>  #include "media.h"
>  #include "a2dp.h"
> +#include "vdp.h"
>  #include "headset.h"
>  #include "gateway.h"
>  #include "sink.h"
>  #include "source.h"
> +#include "video-sink.h"
> +#include "video-source.h"
>  #include "control.h"
>  #include "manager.h"
>  #include "sdpd.h"
> @@ -119,6 +122,8 @@ static struct enabled_interfaces enabled = {
>        .socket         = TRUE,
>        .media          = FALSE,
>        .media_player   = FALSE,
> +       .video_sink     = FALSE,
> +       .video_source   = FALSE,
>  };
>
>  static struct audio_adapter *find_adapter(GSList *list,
> @@ -149,6 +154,10 @@ gboolean server_is_enabled(bdaddr_t *src, uint16_t svc)
>                return enabled.sink;
>        case AUDIO_SOURCE_SVCLASS_ID:
>                return enabled.source;
> +       case VIDEO_SINK_SVCLASS_ID:
> +               return enabled.video_sink;
> +       case VIDEO_SOURCE_SVCLASS_ID:
> +               return enabled.video_source;
>        case AV_REMOTE_TARGET_SVCLASS_ID:
>        case AV_REMOTE_SVCLASS_ID:
>                return enabled.control;
> @@ -214,6 +223,16 @@ static void handle_uuid(const char *uuidstr, struct audio_device *device)
>                if (device->source == NULL)
>                        device->source = source_init(device);
>                break;
> +       case VIDEO_SINK_SVCLASS_ID:
> +               DBG("Found Video Sink");
> +               if (device->video_sink == NULL)
> +                       device->video_sink = video_sink_register(device);
> +               break;
> +       case VIDEO_SOURCE_SVCLASS_ID:
> +               DBG("Found Video Source");
> +               if (device->video_source == NULL)
> +                       device->video_source = video_source_register(device);
> +               break;
>        case AV_REMOTE_SVCLASS_ID:
>        case AV_REMOTE_TARGET_SVCLASS_ID:
>                DBG("Found AV %s", uuid16 == AV_REMOTE_SVCLASS_ID ?
> @@ -1035,6 +1054,45 @@ static void a2dp_server_remove(struct btd_adapter *adapter)
>        audio_adapter_unref(adp);
>  }
>
> +static int vdp_server_probe(struct btd_adapter *adapter)
> +{
> +       struct audio_adapter *adp;
> +       const gchar *path = adapter_get_path(adapter);
> +       bdaddr_t src;
> +       int err;
> +
> +       DBG("path %s", path);
> +
> +       adp = audio_adapter_get(adapter);
> +       if (!adp)
> +               return -EINVAL;
> +
> +       adapter_get_address(adapter, &src);
> +
> +       err = vdp_register(connection, &src, config);
> +       if (err < 0)
> +               audio_adapter_unref(adp);
> +
> +       return err;
> +}
> +
> +static void vdp_server_remove(struct btd_adapter *adapter)
> +{
> +       struct audio_adapter *adp;
> +       const gchar *path = adapter_get_path(adapter);
> +       bdaddr_t src;
> +
> +       DBG("path %s", path);
> +
> +       adp = find_adapter(adapters, adapter);
> +       if (!adp)
> +               return;
> +
> +       adapter_get_address(adapter, &src);
> +       vdp_unregister(&src);
> +       audio_adapter_unref(adp);
> +}
> +
>  static int avrcp_server_probe(struct btd_adapter *adapter)
>  {
>        struct audio_adapter *adp;
> @@ -1105,6 +1163,7 @@ static struct btd_device_driver audio_driver = {
>        .name   = "audio",
>        .uuids  = BTD_UUIDS(HSP_HS_UUID, HFP_HS_UUID, HSP_AG_UUID, HFP_AG_UUID,
>                        ADVANCED_AUDIO_UUID, A2DP_SOURCE_UUID, A2DP_SINK_UUID,
> +                       VIDEO_DISTRIBUTION_UUID, VDP_SOURCE_UUID, VDP_SINK_UUID,
>                        AVRCP_TARGET_UUID, AVRCP_REMOTE_UUID),
>        .probe  = audio_probe,
>        .remove = audio_remove,
> @@ -1128,6 +1187,12 @@ static struct btd_adapter_driver a2dp_server_driver = {
>        .remove = a2dp_server_remove,
>  };
>
> +static struct btd_adapter_driver vdp_server_driver = {
> +       .name   = "video-vdp",
> +       .probe  = vdp_server_probe,
> +       .remove = vdp_server_remove,
> +};
> +
>  static struct btd_adapter_driver avrcp_server_driver = {
>        .name   = "audio-control",
>        .probe  = avrcp_server_probe,
> @@ -1166,6 +1231,10 @@ int audio_manager_init(DBusConnection *conn, GKeyFile *conf,
>                        enabled.sink = TRUE;
>                else if (g_str_equal(list[i], "Source"))
>                        enabled.source = TRUE;
> +               else if (g_str_equal(list[i], "VideoSink"))
> +                       enabled.video_sink = TRUE;
> +               else if (g_str_equal(list[i], "VideoSource"))
> +                       enabled.video_source = TRUE;
>                else if (g_str_equal(list[i], "Control"))
>                        enabled.control = TRUE;
>                else if (g_str_equal(list[i], "Socket"))
> @@ -1189,6 +1258,10 @@ int audio_manager_init(DBusConnection *conn, GKeyFile *conf,
>                        enabled.sink = FALSE;
>                else if (g_str_equal(list[i], "Source"))
>                        enabled.source = FALSE;
> +               else if (g_str_equal(list[i], "VideoSink"))
> +                       enabled.video_sink = FALSE;
> +               else if (g_str_equal(list[i], "VideoSource"))
> +                       enabled.video_source = FALSE;
>                else if (g_str_equal(list[i], "Control"))
>                        enabled.control = FALSE;
>                else if (g_str_equal(list[i], "Socket"))
> @@ -1239,6 +1312,9 @@ proceed:
>        if (enabled.source || enabled.sink)
>                btd_register_adapter_driver(&a2dp_server_driver);
>
> +       if (enabled.video_source || enabled.video_sink)
> +               btd_register_adapter_driver(&vdp_server_driver);
> +
>        if (enabled.control)
>                btd_register_adapter_driver(&avrcp_server_driver);
>
> @@ -1278,6 +1354,9 @@ void audio_manager_exit(void)
>        if (enabled.source || enabled.sink)
>                btd_unregister_adapter_driver(&a2dp_server_driver);
>
> +       if (enabled.video_source || enabled.video_sink)
> +               btd_unregister_adapter_driver(&vdp_server_driver);
> +
>        if (enabled.control)
>                btd_unregister_adapter_driver(&avrcp_server_driver);
>
> @@ -1320,6 +1399,14 @@ struct audio_device *manager_find_device(const char *path,
>                                && !dev->source)
>                        continue;
>
> +               if (interface && !strcmp(VIDEO_SINK_INTERFACE, interface)
> +                               && !dev->video_sink)
> +                       continue;
> +
> +               if (interface && !strcmp(VIDEO_SOURCE_INTERFACE, interface)
> +                               && !dev->video_source)
> +                       continue;
> +
>                if (interface && !strcmp(AUDIO_CONTROL_INTERFACE, interface)
>                                && !dev->control)
>                        continue;
> diff --git a/audio/manager.h b/audio/manager.h
> index cfc646c..6c61da4 100644
> --- a/audio/manager.h
> +++ b/audio/manager.h
> @@ -28,6 +28,8 @@ struct enabled_interfaces {
>        gboolean gateway;
>        gboolean sink;
>        gboolean source;
> +       gboolean video_sink;
> +       gboolean video_source;
>        gboolean control;
>        gboolean socket;
>        gboolean media;
> --
> 1.7.6

Looks good, ack

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH BlueZ 6/6] This adds video_sink and video_source to audio_device.
  2011-08-16 13:43 ` [PATCH BlueZ 6/6] This adds video_sink and video_source to audio_device Prasad Bhat
@ 2011-08-18  7:31   ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 12+ messages in thread
From: Luiz Augusto von Dentz @ 2011-08-18  7:31 UTC (permalink / raw)
  To: Prasad Bhat; +Cc: linux-bluetooth

Hi,

On Tue, Aug 16, 2011 at 4:43 PM, Prasad Bhat <prasadbhat22@gmail.com> wrote:
> ---
>  audio/device.h |    7 +++++++
>  1 files changed, 7 insertions(+), 0 deletions(-)
>
> diff --git a/audio/device.h b/audio/device.h
> index 5117fca..661f112 100644
> --- a/audio/device.h
> +++ b/audio/device.h
> @@ -38,6 +38,11 @@
>  #define AVRCP_REMOTE_UUID      "0000110e-0000-1000-8000-00805f9b34fb"
>  #define AVRCP_TARGET_UUID      "0000110c-0000-1000-8000-00805f9b34fb"
>
> +#define VIDEO_DISTRIBUTION_UUID "00001305-0000-1000-8000-00805f9b34fb"
> +
> +#define VDP_SOURCE_UUID        "00001303-0000-1000-8000-00805f9b34fb"
> +#define VDP_SINK_UUID          "00001304-0000-1000-8000-00805f9b34fb"
> +
>  struct source;
>  struct control;
>  struct target;
> @@ -62,6 +67,8 @@ struct audio_device {
>        struct source *source;
>        struct control *control;
>        struct target *target;
> +       struct video_sink *video_sink;
> +       struct video_source *video_source;

This looks wrong, you should merge those changes where they are necessary.

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-08-18  7:31 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-16 13:43 [PATCH BlueZ 1/6] Initial VDP implementation Prasad Bhat
2011-08-16 13:43 ` [PATCH BlueZ 2/6] Implementation of video-sink for VDP Prasad Bhat
2011-08-18  7:14   ` Luiz Augusto von Dentz
2011-08-16 13:43 ` [PATCH BlueZ 3/6] Initial video-source implementation " Prasad Bhat
2011-08-18  7:17   ` Luiz Augusto von Dentz
2011-08-16 13:43 ` [PATCH BlueZ 4/6] The changes in media.c required " Prasad Bhat
2011-08-18  7:20   ` Luiz Augusto von Dentz
2011-08-16 13:43 ` [PATCH BlueZ 5/6] This adds video-sink and video-source interfaces and vdp_server_driver to audio/manager{.c, .h} Prasad Bhat
2011-08-18  7:21   ` Luiz Augusto von Dentz
2011-08-16 13:43 ` [PATCH BlueZ 6/6] This adds video_sink and video_source to audio_device Prasad Bhat
2011-08-18  7:31   ` Luiz Augusto von Dentz
2011-08-18  7:11 ` [PATCH BlueZ 1/6] Initial VDP implementation Luiz Augusto von Dentz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.