[RFC 0/7] A2DP MP3 support with media API

9 messages, 2 authors, 2012-03-23 · open the first message on its own page

[RFC 0/7] A2DP MP3 support with media API

From: Frédéric Dalleau <hidden>
Date: 2012-03-22 16:37:48

Hi,

I'm trying to make A2DP MP3 work in pulseaudio using media API.
In contrast to Unix API, media API lacks the possibility to reconfigure the
transport BT_SET_CONFIGURATION. So I've defined a dbus API that offers a
similar functionnality.
First there is a MediaTransport.Codecs property to list supported codecs on a
transport.
Then there is a Reconfigure method that tries to reconfigure the transport
to use a specified endpoint.

I'm sending a patch on pulseaudio list for using this new APIs at same time.

This is an RFC so feel free to comment, especially on the way a configuration
could be specified.

Regards,
Frédéric


Frédéric Dalleau (7):
  media: Remove unimplemented declaration
  doc: document MediaTransport.Codecs property
  doc: document MediaTransport.Reconfigure
  media: Add Codecs property to MediaTransport
  media: add dbus method MediaTransport.Reconfigure
  media: implement media_endpoint_find function
  media: implement a2dp reconfiguration

 audio/media.c     |   16 +++++
 audio/media.h     |    3 +-
 audio/transport.c |  164 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 doc/media-api.txt |   12 ++++
 4 files changed, 193 insertions(+), 2 deletions(-)

-- 
1.7.5.4

[RFC 1/7] media: Remove unimplemented declaration

From: Frédéric Dalleau <hidden>
Date: 2012-03-22 16:37:49

---
 audio/media.h |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/audio/media.h b/audio/media.h
index ee9a51e..84fc1bc 100644
--- a/audio/media.h
+++ b/audio/media.h
@@ -33,5 +33,3 @@ void media_unregister(const char *path);
 struct a2dp_sep *media_endpoint_get_sep(struct media_endpoint *endpoint);
 const char *media_endpoint_get_uuid(struct media_endpoint *endpoint);
 uint8_t media_endpoint_get_codec(struct media_endpoint *endpoint);
-struct media_transport *media_endpoint_get_transport(
-					struct media_endpoint *endpoint);
-- 
1.7.5.4

[RFC 2/7] doc: document MediaTransport.Codecs property

From: Frédéric Dalleau <hidden>
Date: 2012-03-22 16:37:50

---
 doc/media-api.txt |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/doc/media-api.txt b/doc/media-api.txt
index c53ab7b..b32636b 100644
--- a/doc/media-api.txt
+++ b/doc/media-api.txt
@@ -312,6 +312,12 @@ Properties	object Device [readonly]
 			The values should match the profile specification which
 			is indicated by the UUID.
 
+		array{byte} Codecs [readonly, experimental]
+
+			Codecs list, contains assigned numbers for all codecs
+			that the transport support. The values should match the
+			profile specification which is indicated by the UUID.
+
 		array{byte} Configuration [readonly]
 
 			Configuration blob, it is used as it is so the size and
-- 
1.7.5.4

[RFC 3/7] doc: document MediaTransport.Reconfigure

From: Frédéric Dalleau <hidden>
Date: 2012-03-22 16:37:51

---
 doc/media-api.txt |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/doc/media-api.txt b/doc/media-api.txt
index b32636b..cd3363d 100644
--- a/doc/media-api.txt
+++ b/doc/media-api.txt
@@ -286,6 +286,12 @@ Methods		dict GetProperties()
 
 			Releases file descriptor.
 
+		void Reconfigure(object endpoint)  [experimental]
+
+			Reconfigure the transport to use the specified endpoint.
+			The stream will be reconfigured and the transport
+			recreated.
+
 		void SetProperty(string name, variant value)
 
 			Changes the value of the specified property. Only
-- 
1.7.5.4

[RFC 4/7] media: Add Codecs property to MediaTransport

From: Frédéric Dalleau <hidden>
Date: 2012-03-22 16:37:52

---
 audio/transport.c |   29 +++++++++++++++++++++++++++++
 1 files changed, 29 insertions(+), 0 deletions(-)
diff --git a/audio/transport.c b/audio/transport.c
index 7bf7309..38e44c2 100644
--- a/audio/transport.c
+++ b/audio/transport.c
@@ -840,7 +840,36 @@ static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
 static void get_properties_a2dp(struct media_transport *transport,
 						DBusMessageIter *dict)
 {
+	struct audio_device *device = transport->device;
+	uint8_t codecs[8];
+	void *pcodecs = codecs;
+	int ncodecs = 0, seid = 1;
+	struct avdtp_remote_sep *sep;
+	struct avdtp_service_capability *cap;
+	struct avdtp_media_codec_capability *ccap;
+
 	dict_append_entry(dict, "Delay", DBUS_TYPE_UINT16, &transport->delay);
+
+	if (transport->session == NULL)
+		transport->session = avdtp_get(&device->src, &device->dst);
+
+	if (transport->session == NULL)
+		return;
+
+	sep = avdtp_get_remote_sep(transport->session, seid);
+	while (sep) {
+		cap = avdtp_get_codec(sep);
+		ccap = (struct avdtp_media_codec_capability *) cap->data;
+
+		codecs[ncodecs++] = ccap->media_codec_type;
+
+		seid++;
+		sep = avdtp_get_remote_sep(transport->session, seid);
+	}
+
+	if (ncodecs > 0)
+		dict_append_array(dict, "Codecs",
+					DBUS_TYPE_BYTE, &pcodecs, ncodecs);
 }
 
 static void get_properties_headset(struct media_transport *transport,
-- 
1.7.5.4

[RFC 5/7] media: add dbus method MediaTransport.Reconfigure

From: Frédéric Dalleau <hidden>
Date: 2012-03-22 16:37:53

---
 audio/transport.c |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/audio/transport.c b/audio/transport.c
index 38e44c2..f9b924a 100644
--- a/audio/transport.c
+++ b/audio/transport.c
@@ -837,6 +837,22 @@ static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
 	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
+static DBusMessage *reconfigure(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	DBusMessageIter iter;
+	const char *endpoint;
+
+	if (!dbus_message_iter_init(msg, &iter))
+		return btd_error_invalid_args(msg);
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+		return btd_error_invalid_args(msg);
+	dbus_message_iter_get_basic(&iter, &endpoint);
+
+
+	return NULL;
+}
+
 static void get_properties_a2dp(struct media_transport *transport,
 						DBusMessageIter *dict)
 {
@@ -950,6 +966,8 @@ static GDBusMethodTable transport_methods[] = {
 	{ "Release",		"s",	"",		release,
 						G_DBUS_METHOD_FLAG_ASYNC},
 	{ "SetProperty",	"sv",	"",		set_property },
+	{ "Reconfigure",	"s",	"",		reconfigure,
+						G_DBUS_METHOD_FLAG_ASYNC},
 	{ },
 };
 
-- 
1.7.5.4

[RFC 6/7] media: implement media_endpoint_find function

From: Frédéric Dalleau <hidden>
Date: 2012-03-22 16:37:54

---
 audio/media.c |   16 ++++++++++++++++
 audio/media.h |    1 +
 2 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/audio/media.c b/audio/media.c
index c0fd0c3..05019f3 100644
--- a/audio/media.c
+++ b/audio/media.c
@@ -1782,3 +1782,19 @@ uint8_t media_endpoint_get_codec(struct media_endpoint *endpoint)
 {
 	return endpoint->codec;
 }
+
+struct media_endpoint *media_endpoint_find(const char *path)
+{
+	GSList *l;
+	struct media_endpoint *endpoint;
+
+	for (l = adapters; l; l = l->next) {
+		struct media_adapter *adapter = l->data;
+
+		endpoint = media_adapter_find_endpoint(adapter,
+							NULL, path, NULL);
+		if (endpoint)
+			return endpoint;
+	}
+	return NULL;
+}
diff --git a/audio/media.h b/audio/media.h
index 84fc1bc..6747fc2 100644
--- a/audio/media.h
+++ b/audio/media.h
@@ -33,3 +33,4 @@ void media_unregister(const char *path);
 struct a2dp_sep *media_endpoint_get_sep(struct media_endpoint *endpoint);
 const char *media_endpoint_get_uuid(struct media_endpoint *endpoint);
 uint8_t media_endpoint_get_codec(struct media_endpoint *endpoint);
+struct media_endpoint *media_endpoint_find(const char *path);
-- 
1.7.5.4

[RFC 7/7] media: implement a2dp reconfiguration

From: Frédéric Dalleau <hidden>
Date: 2012-03-22 16:37:55

---
 audio/transport.c |  117 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 117 insertions(+), 0 deletions(-)
diff --git a/audio/transport.c b/audio/transport.c
index f9b924a..6dd3c58 100644
--- a/audio/transport.c
+++ b/audio/transport.c
@@ -43,6 +43,7 @@
 #include "a2dp.h"
 #include "headset.h"
 #include "gateway.h"
+#include "ipc.h"
 
 #ifndef DBUS_TYPE_UNIX_FD
 #define DBUS_TYPE_UNIX_FD -1
@@ -53,6 +54,7 @@
 struct media_request {
 	DBusMessage		*msg;
 	guint			id;
+	DBusConnection		*conn;
 };
 
 struct media_owner {
@@ -837,11 +839,123 @@ static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
 	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
+static GSList *handle_a2dp_transport(uint8_t codec)
+{
+	struct avdtp_service_capability *media_transport, *media_codec;
+	struct sbc_codec_cap sbc_cap;
+	struct mpeg_codec_cap mpg_cap;
+	GSList *caps = NULL;
+
+	if (codec == A2DP_CODEC_MPEG12) {
+		memset(&mpg_cap, 0, sizeof(mpg_cap));
+
+		/* FIXME: this code says MP3 and hope the receiver accept */
+		mpg_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
+		mpg_cap.cap.media_codec_type = A2DP_CODEC_MPEG12;
+		mpg_cap.channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
+		mpg_cap.crc = 0;
+		mpg_cap.layer = BT_MPEG_LAYER_3;
+		mpg_cap.frequency = MPEG_SAMPLING_FREQ_44100;
+		mpg_cap.mpf = 0;
+		mpg_cap.bitrate = 0x80;
+
+		media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &mpg_cap,
+							sizeof(mpg_cap));
+
+		DBG("Handling switch to MPEG transport");
+	} else if (codec == A2DP_CODEC_SBC) {
+		memset(&sbc_cap, 0, sizeof(sbc_cap));
+
+		/* FIXME: this is the mandatory SBC params for a source */
+		sbc_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
+		sbc_cap.cap.media_codec_type = A2DP_CODEC_SBC;
+		sbc_cap.channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
+		sbc_cap.frequency = BT_SBC_SAMPLING_FREQ_44100;
+		sbc_cap.allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;
+		sbc_cap.subbands = BT_A2DP_SUBBANDS_8;
+		sbc_cap.block_length = BT_A2DP_BLOCK_LENGTH_16;
+		sbc_cap.min_bitpool = 53;
+		sbc_cap.max_bitpool = 53;
+
+		media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
+							sizeof(sbc_cap));
+
+		DBG("Handling switch to SBC transport");
+	} else
+		return NULL;
+
+	media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+						NULL, 0);
+
+	caps = g_slist_append(caps, media_transport);
+	caps = g_slist_append(caps, media_codec);
+
+	return caps;
+}
+
+static void a2dp_config_complete(struct avdtp *session, struct a2dp_sep *sep,
+					struct avdtp_stream *stream,
+					struct avdtp_error *err,
+					void *user_data)
+{
+	struct media_request *req = user_data;
+
+	media_request_reply(req, req->conn, err ? -ENOTSUP : 0);
+
+	dbus_connection_unref(req->conn);
+
+	g_free(req);
+}
+
+static void media_transport_reconfigure(struct avdtp *session, const char *path,
+						struct media_request *req)
+{
+	int err;
+	GSList *caps;
+	uint8_t codec;
+	struct media_endpoint *endpoint;
+	struct a2dp_sep *sep;
+
+	endpoint = media_endpoint_find(path);
+	if (endpoint == NULL) {
+		err = -EEXIST;
+		goto failed;
+	}
+	sep = media_endpoint_get_sep(endpoint);
+	codec = media_endpoint_get_codec(endpoint);
+
+	DBG(" sep %p creating caps list for codec %d", sep, codec);
+
+	/* FIXME prevent usage on SCO transport */
+	caps = handle_a2dp_transport(codec);
+	if (caps == NULL) {
+		err = -EINVAL;
+		goto failed;
+	}
+
+	err = a2dp_config(session, sep, a2dp_config_complete,
+					caps, req);
+	if (err < 0)
+		goto failed;
+
+	req->id = err;
+	return;
+
+failed:
+	media_request_reply(req, req->conn, -err);
+
+	dbus_connection_unref(req->conn);
+
+	g_free(req);
+}
+
 static DBusMessage *reconfigure(DBusConnection *conn, DBusMessage *msg,
 								void *data)
 {
+	struct media_transport *transport = data;
 	DBusMessageIter iter;
 	const char *endpoint;
+	struct media_request *req;
 
 	if (!dbus_message_iter_init(msg, &iter))
 		return btd_error_invalid_args(msg);
@@ -849,6 +963,9 @@ static DBusMessage *reconfigure(DBusConnection *conn, DBusMessage *msg,
 		return btd_error_invalid_args(msg);
 	dbus_message_iter_get_basic(&iter, &endpoint);
 
+	req = media_request_create(msg, 0);
+	req->conn = dbus_connection_ref(conn);
+	media_transport_reconfigure(transport->session, endpoint, req);
 
 	return NULL;
 }
-- 
1.7.5.4

Re: [RFC 0/7] A2DP MP3 support with media API

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2012-03-23 14:14:55

Hi Frédéric,

2012/3/22 Frédéric Dalleau [off-list ref]:
Hi,

I'm trying to make A2DP MP3 work in pulseaudio using media API.
In contrast to Unix API, media API lacks the possibility to reconfigure the
transport BT_SET_CONFIGURATION. So I've defined a dbus API that offers a
similar functionnality.
First there is a MediaTransport.Codecs property to list supported codecs on a
transport.
Then there is a Reconfigure method that tries to reconfigure the transport
to use a specified endpoint.

I'm sending a patch on pulseaudio list for using this new APIs at same time.

This is an RFC so feel free to comment, especially on the way a configuration
could be specified.
I don't think reusing the same transport object is the best approach
here, I would prefer to create a new one and reconfigure transparently
when switching instead of trying to use the same transport. Btw with
A2DP we could in theory have multiple streams configured
simultaneously, so we could have multiple transports configured,
actually even active as AVDTP Start can take a list of seid, now we
could face some iop problems with such approach but we could rely on
AVDTP Close.


-- 
Luiz Augusto von Dentz
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help