2012-11-20 16:10:48

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v3 0/3] Adopt btd_profile for A2DP

From: Mikel Astiz <[email protected]>

The proposal is to split A2DP roles into different btd_profile instances, in order to expose .connect and .disconnect.

v3 includes the remaning patches -without changes- rebased on the latest master.

Mikel Astiz (3):
audio: Split A2DP into three btd_profile
source: Add profile .connect and .disconnect
sink: Add profile .connect and .disconnect

profiles/audio/a2dp.c | 74 +++++++--------
profiles/audio/a2dp.h | 4 +-
profiles/audio/manager.c | 242 +++++++++++++++++++++++++++++++++++++++++++----
3 files changed, 263 insertions(+), 57 deletions(-)

--
1.7.11.7



2012-11-20 16:10:51

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v3 3/3] sink: Add profile .connect and .disconnect

From: Mikel Astiz <[email protected]>

Add the connection and disconnection hooks to the a2dp_sink btd_profile.
---
profiles/audio/manager.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)

diff --git a/profiles/audio/manager.c b/profiles/audio/manager.c
index 64df824..38e3c2b 100644
--- a/profiles/audio/manager.c
+++ b/profiles/audio/manager.c
@@ -261,6 +261,56 @@ static int a2dp_source_disconnect(struct btd_device *dev,
return 0;
}

+static int a2dp_sink_connect(struct btd_device *dev,
+ struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ struct audio_device *audio_dev;
+ struct profile_req *req;
+ int err;
+
+ audio_dev = get_audio_dev(dev);
+ if (!audio_dev) {
+ DBG("unable to get a device object");
+ return -1;
+ }
+
+ req = new_profile_request(dev, profile, cb);
+
+ err = sink_connect(audio_dev, profile_cb, req);
+ if (err < 0) {
+ g_free(req);
+ return err;
+ }
+
+ return 0;
+}
+
+static int a2dp_sink_disconnect(struct btd_device *dev,
+ struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ struct audio_device *audio_dev;
+ struct profile_req *req;
+ int err;
+
+ audio_dev = get_audio_dev(dev);
+ if (!audio_dev) {
+ DBG("unable to get a device object");
+ return -1;
+ }
+
+ req = new_profile_request(dev, profile, cb);
+
+ err = sink_disconnect(audio_dev, FALSE, profile_cb, req);
+ if (err < 0) {
+ g_free(req);
+ return err;
+ }
+
+ return 0;
+}
+
static struct audio_adapter *audio_adapter_ref(struct audio_adapter *adp)
{
adp->ref++;
@@ -480,6 +530,9 @@ static struct btd_profile a2dp_sink_profile = {
.device_probe = a2dp_sink_probe,
.device_remove = audio_remove,

+ .connect = a2dp_sink_connect,
+ .disconnect = a2dp_sink_disconnect,
+
.adapter_probe = a2dp_sink_server_probe,
};

--
1.7.11.7


2012-11-20 16:10:50

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v3 2/3] source: Add profile .connect and .disconnect

From: Mikel Astiz <[email protected]>

Add the connection and disconnection hooks to the a2dp_source
btd_profile.
---
profiles/audio/manager.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)

diff --git a/profiles/audio/manager.c b/profiles/audio/manager.c
index d7c1717..64df824 100644
--- a/profiles/audio/manager.c
+++ b/profiles/audio/manager.c
@@ -80,6 +80,12 @@ struct audio_adapter {
gint ref;
};

+struct profile_req {
+ struct btd_device *device;
+ struct btd_profile *profile;
+ btd_profile_cb cb;
+};
+
static gboolean auto_connect = TRUE;
static int max_connected_headsets = 1;
static GKeyFile *config = NULL;
@@ -182,6 +188,79 @@ static int avrcp_probe(struct btd_profile *p, struct btd_device *device,
return 0;
}

+static struct profile_req *new_profile_request(struct btd_device *dev,
+ struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ struct profile_req *req;
+
+ req = g_new0(struct profile_req, 1);
+ req->device = dev;
+ req->profile = profile;
+ req->cb = cb;
+
+ return req;
+}
+
+static void profile_cb(struct audio_device *dev, int err, void *data)
+{
+ struct profile_req *req = data;
+
+ req->cb(req->profile, req->device, err);
+
+ g_free(req);
+}
+
+static int a2dp_source_connect(struct btd_device *dev,
+ struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ struct audio_device *audio_dev;
+ struct profile_req *req;
+ int err;
+
+ audio_dev = get_audio_dev(dev);
+ if (!audio_dev) {
+ DBG("unable to get a device object");
+ return -1;
+ }
+
+ req = new_profile_request(dev, profile, cb);
+
+ err = source_connect(audio_dev, profile_cb, req);
+ if (err < 0) {
+ g_free(req);
+ return err;
+ }
+
+ return 0;
+}
+
+static int a2dp_source_disconnect(struct btd_device *dev,
+ struct btd_profile *profile,
+ btd_profile_cb cb)
+{
+ struct audio_device *audio_dev;
+ struct profile_req *req;
+ int err;
+
+ audio_dev = get_audio_dev(dev);
+ if (!audio_dev) {
+ DBG("unable to get a device object");
+ return -1;
+ }
+
+ req = new_profile_request(dev, profile, cb);
+
+ err = source_disconnect(audio_dev, FALSE, profile_cb, req);
+ if (err < 0) {
+ g_free(req);
+ return err;
+ }
+
+ return 0;
+}
+
static struct audio_adapter *audio_adapter_ref(struct audio_adapter *adp)
{
adp->ref++;
@@ -387,6 +466,9 @@ static struct btd_profile a2dp_source_profile = {
.device_probe = a2dp_source_probe,
.device_remove = audio_remove,

+ .connect = a2dp_source_connect,
+ .disconnect = a2dp_source_disconnect,
+
.adapter_probe = a2dp_source_server_probe,
};

--
1.7.11.7


2012-11-20 16:10:49

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v3 1/3] audio: Split A2DP into three btd_profile

From: Mikel Astiz <[email protected]>

Merging the three audio profiles (AVDTP, A2DP sink and A2DP source)
into one was convenient in the past was doesn't fit very well the new
btd_profile approach. The split is also more consistent with other
existing profiles.
---
profiles/audio/a2dp.c | 74 +++++++++++++++-----------------
profiles/audio/a2dp.h | 4 +-
profiles/audio/manager.c | 107 ++++++++++++++++++++++++++++++++++++++++-------
3 files changed, 128 insertions(+), 57 deletions(-)

diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c
index 50c0f43..e199849 100644
--- a/profiles/audio/a2dp.c
+++ b/profiles/audio/a2dp.c
@@ -1166,63 +1166,57 @@ static struct a2dp_server *find_server(GSList *list, const bdaddr_t *src)
return NULL;
}

-int a2dp_register(const bdaddr_t *src, GKeyFile *config)
+int a2dp_server_register(const bdaddr_t *src, GKeyFile *config)
{
- gboolean source = TRUE, sink = FALSE;
- char *str;
- GError *err = NULL;
struct a2dp_server *server;
+ int av_err;

- if (!config)
- goto proceed;
+ server = find_server(servers, src);
+ if (server)
+ return 0;

- str = g_key_file_get_string(config, "General", "Enable", &err);
+ server = g_new0(struct a2dp_server, 1);

- if (err) {
- DBG("audio.conf: %s", err->message);
- g_clear_error(&err);
- } else {
- if (strstr(str, "Sink"))
- source = TRUE;
- if (strstr(str, "Source"))
- sink = TRUE;
- g_free(str);
+ av_err = avdtp_init(src, config);
+ if (av_err < 0) {
+ g_free(server);
+ return av_err;
}

- str = g_key_file_get_string(config, "General", "Disable", &err);
+ bacpy(&server->src, src);
+ servers = g_slist_append(servers, server);

- if (err) {
- DBG("audio.conf: %s", err->message);
- g_clear_error(&err);
- } else {
- if (strstr(str, "Sink"))
- source = FALSE;
- if (strstr(str, "Source"))
- sink = FALSE;
- g_free(str);
- }
+ return 0;
+}

-proceed:
+int a2dp_source_register(const bdaddr_t *src, GKeyFile *config)
+{
+ struct a2dp_server *server;

server = find_server(servers, src);
if (!server) {
- int av_err;
+ DBG("AVDTP not registered");
+ return -EPROTONOSUPPORT;

- server = g_new0(struct a2dp_server, 1);
+ }

- av_err = avdtp_init(src, config);
- if (av_err < 0) {
- g_free(server);
- return av_err;
- }
+ server->source_enabled = TRUE;

- bacpy(&server->src, src);
- servers = g_slist_append(servers, server);
- }
+ return 0;
+}

- server->source_enabled = source;
+int a2dp_sink_register(const bdaddr_t *src, GKeyFile *config)
+{
+ struct a2dp_server *server;
+
+ server = find_server(servers, src);
+ if (!server) {
+ DBG("AVDTP not registered");
+ return -EPROTONOSUPPORT;
+
+ }

- server->sink_enabled = sink;
+ server->sink_enabled = TRUE;

return 0;
}
diff --git a/profiles/audio/a2dp.h b/profiles/audio/a2dp.h
index 736bc66..c471499 100644
--- a/profiles/audio/a2dp.h
+++ b/profiles/audio/a2dp.h
@@ -64,7 +64,9 @@ typedef void (*a2dp_stream_cb_t) (struct avdtp *session,
struct avdtp_error *err,
void *user_data);

-int a2dp_register(const bdaddr_t *src, GKeyFile *config);
+int a2dp_server_register(const bdaddr_t *src, GKeyFile *config);
+int a2dp_source_register(const bdaddr_t *src, GKeyFile *config);
+int a2dp_sink_register(const bdaddr_t *src, GKeyFile *config);
void a2dp_unregister(const bdaddr_t *src);

struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
diff --git a/profiles/audio/manager.c b/profiles/audio/manager.c
index 19aeb24..d7c1717 100644
--- a/profiles/audio/manager.c
+++ b/profiles/audio/manager.c
@@ -128,7 +128,7 @@ static void audio_remove(struct btd_profile *p, struct btd_device *device)
audio_device_unregister(dev);
}

-static int a2dp_probe(struct btd_profile *p, struct btd_device *device,
+static int a2dp_source_probe(struct btd_profile *p, struct btd_device *device,
GSList *uuids)
{
struct audio_device *audio_dev;
@@ -139,13 +139,23 @@ static int a2dp_probe(struct btd_profile *p, struct btd_device *device,
return -1;
}

- if (g_slist_find_custom(uuids, A2DP_SINK_UUID, bt_uuid_strcmp) &&
- audio_dev->sink == NULL)
- audio_dev->sink = sink_init(audio_dev);
+ audio_dev->source = source_init(audio_dev);

- if (g_slist_find_custom(uuids, A2DP_SOURCE_UUID, bt_uuid_strcmp) &&
- audio_dev->source == NULL)
- audio_dev->source = source_init(audio_dev);
+ return 0;
+}
+
+static int a2dp_sink_probe(struct btd_profile *p, struct btd_device *device,
+ GSList *uuids)
+{
+ struct audio_device *audio_dev;
+
+ audio_dev = get_audio_dev(device);
+ if (!audio_dev) {
+ DBG("unable to get a device object");
+ return -1;
+ }
+
+ audio_dev->sink = sink_init(audio_dev);

return 0;
}
@@ -232,7 +242,7 @@ static int a2dp_server_probe(struct btd_profile *p,
if (!adp)
return -EINVAL;

- err = a2dp_register(adapter_get_address(adapter), config);
+ err = a2dp_server_register(adapter_get_address(adapter), config);
if (err < 0)
audio_adapter_unref(adp);

@@ -255,6 +265,40 @@ static void a2dp_server_remove(struct btd_profile *p,
audio_adapter_unref(adp);
}

+static int a2dp_source_server_probe(struct btd_profile *p,
+ struct btd_adapter *adapter)
+{
+ struct audio_adapter *adp;
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ adp = audio_adapter_get(adapter);
+ if (!adp)
+ return -EINVAL;
+
+ audio_adapter_unref(adp); /* Referenced by a2dp server */
+
+ return a2dp_source_register(adapter_get_address(adapter), config);
+}
+
+static int a2dp_sink_server_probe(struct btd_profile *p,
+ struct btd_adapter *adapter)
+{
+ struct audio_adapter *adp;
+ const gchar *path = adapter_get_path(adapter);
+
+ DBG("path %s", path);
+
+ adp = audio_adapter_get(adapter);
+ if (!adp)
+ return -EINVAL;
+
+ audio_adapter_unref(adp); /* Referenced by a2dp server */
+
+ return a2dp_sink_register(adapter_get_address(adapter), config);
+}
+
static int avrcp_server_probe(struct btd_profile *p,
struct btd_adapter *adapter)
{
@@ -325,19 +369,38 @@ static void media_server_remove(struct btd_adapter *adapter)
audio_adapter_unref(adp);
}

-static struct btd_profile a2dp_profile = {
- .name = "audio-a2dp",
+static struct btd_profile avdtp_profile = {
+ .name = "audio-avdtp",
.priority = BTD_PROFILE_PRIORITY_MEDIUM,

- .remote_uuids = BTD_UUIDS(A2DP_SOURCE_UUID, A2DP_SINK_UUID,
- ADVANCED_AUDIO_UUID),
- .device_probe = a2dp_probe,
- .device_remove = audio_remove,
+ .remote_uuids = BTD_UUIDS(ADVANCED_AUDIO_UUID),

.adapter_probe = a2dp_server_probe,
.adapter_remove = a2dp_server_remove,
};

+static struct btd_profile a2dp_source_profile = {
+ .name = "audio-source",
+ .priority = BTD_PROFILE_PRIORITY_MEDIUM,
+
+ .remote_uuids = BTD_UUIDS(A2DP_SOURCE_UUID),
+ .device_probe = a2dp_source_probe,
+ .device_remove = audio_remove,
+
+ .adapter_probe = a2dp_source_server_probe,
+};
+
+static struct btd_profile a2dp_sink_profile = {
+ .name = "audio-sink",
+ .priority = BTD_PROFILE_PRIORITY_MEDIUM,
+
+ .remote_uuids = BTD_UUIDS(A2DP_SINK_UUID),
+ .device_probe = a2dp_sink_probe,
+ .device_remove = audio_remove,
+
+ .adapter_probe = a2dp_sink_server_probe,
+};
+
static struct btd_profile avrcp_profile = {
.name = "audio-avrcp",

@@ -409,7 +472,13 @@ int audio_manager_init(GKeyFile *conf)

proceed:
if (enabled.source || enabled.sink)
- btd_profile_register(&a2dp_profile);
+ btd_profile_register(&avdtp_profile);
+
+ if (enabled.source)
+ btd_profile_register(&a2dp_source_profile);
+
+ if (enabled.sink)
+ btd_profile_register(&a2dp_sink_profile);

if (enabled.control)
btd_profile_register(&avrcp_profile);
@@ -426,8 +495,14 @@ void audio_manager_exit(void)
config = NULL;
}

+ if (enabled.source)
+ btd_profile_unregister(&a2dp_source_profile);
+
+ if (enabled.sink)
+ btd_profile_unregister(&a2dp_sink_profile);
+
if (enabled.source || enabled.sink)
- btd_profile_unregister(&a2dp_profile);
+ btd_profile_unregister(&avdtp_profile);

if (enabled.control)
btd_profile_unregister(&avrcp_profile);
--
1.7.11.7