2012-11-15 07:27:32

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v2 0/8] 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.

The changes in v2 include:

- Renaming of functions as suggested by Luiz (avoid using local_xxx)
- Merge of source_shutdown and source_disconnect: they were quite similar and having a generalized function seems a better idea (to be discussed if we can get rid of the gboolean shutdown parameter)
- New patches have been added to address the sink part as well (v1 focused on the source role)

Mikel Astiz (8):
audio: Trivial function renames
sink: Generalize disconnection function
source: Add missing code in source_disconnect()
source: Expose internal connection API
sink: Expose internal connection API
audio: Split A2DP into three btd_profile
source: Add profile .connect and .disconnect
sink: Add profile .connect and .disconnect

profiles/audio/a2dp.c | 88 ++++++++---------
profiles/audio/a2dp.h | 4 +-
profiles/audio/device.c | 4 +-
profiles/audio/device.h | 3 +
profiles/audio/manager.c | 242 +++++++++++++++++++++++++++++++++++++++++++----
profiles/audio/sink.c | 179 ++++++++++++++++++-----------------
profiles/audio/sink.h | 4 +-
profiles/audio/source.c | 189 ++++++++++++++++++++----------------
profiles/audio/source.h | 4 +-
9 files changed, 480 insertions(+), 237 deletions(-)

--
1.7.11.7



2012-11-20 11:47:20

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH v2 0/8] Adopt btd_profile for A2DP

Hi Mikel,

On Thu, Nov 15, 2012 at 9:27 AM, Mikel Astiz <[email protected]> wrote:
> From: Mikel Astiz <[email protected]>
>
> The proposal is to split A2DP roles into different btd_profile instances, in order to expose .connect and .disconnect.
>
> The changes in v2 include:
>
> - Renaming of functions as suggested by Luiz (avoid using local_xxx)
> - Merge of source_shutdown and source_disconnect: they were quite similar and having a generalized function seems a better idea (to be discussed if we can get rid of the gboolean shutdown parameter)
> - New patches have been added to address the sink part as well (v1 focused on the source role)
>
> Mikel Astiz (8):
> audio: Trivial function renames
> sink: Generalize disconnection function
> source: Add missing code in source_disconnect()
> source: Expose internal connection API
> sink: Expose internal connection API
> audio: Split A2DP into three btd_profile
> source: Add profile .connect and .disconnect
> sink: Add profile .connect and .disconnect
>
> profiles/audio/a2dp.c | 88 ++++++++---------
> profiles/audio/a2dp.h | 4 +-
> profiles/audio/device.c | 4 +-
> profiles/audio/device.h | 3 +
> profiles/audio/manager.c | 242 +++++++++++++++++++++++++++++++++++++++++++----
> profiles/audio/sink.c | 179 ++++++++++++++++++-----------------
> profiles/audio/sink.h | 4 +-
> profiles/audio/source.c | 189 ++++++++++++++++++++----------------
> profiles/audio/source.h | 4 +-
> 9 files changed, 480 insertions(+), 237 deletions(-)
>
> --
> 1.7.11.7

First 5 patches are now pushed, I had to changed sink_disconnect and
source_disconnect since they were crashing. Please rebase the rest and
reasend.


--
Luiz Augusto von Dentz

2012-11-15 07:27:37

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v2 5/8] sink: Expose internal connection API

From: Mikel Astiz <[email protected]>

Separate the D-Bus code from the internal connection handling code,
exposing an internal API in case some internal codepath/plugin is
interested in using it.
---
profiles/audio/device.c | 4 +-
profiles/audio/sink.c | 159 ++++++++++++++++++++++++------------------------
profiles/audio/sink.h | 4 +-
3 files changed, 86 insertions(+), 81 deletions(-)

diff --git a/profiles/audio/device.c b/profiles/audio/device.c
index 09a1ed7..56239a4 100644
--- a/profiles/audio/device.c
+++ b/profiles/audio/device.c
@@ -203,7 +203,7 @@ static void disconnect_cb(struct btd_device *btd_dev, gboolean removal,
avrcp_disconnect(dev);

if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED)
- sink_disconnect(dev, TRUE);
+ sink_disconnect(dev, TRUE, NULL, NULL);
else
priv->disconnecting = FALSE;
}
@@ -390,7 +390,7 @@ static DBusMessage *dev_disconnect(DBusConnection *conn, DBusMessage *msg,
}

if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED)
- sink_disconnect(dev, TRUE);
+ sink_disconnect(dev, TRUE, NULL, NULL);
else {
dbus_message_unref(priv->dc_req);
priv->dc_req = NULL;
diff --git a/profiles/audio/sink.c b/profiles/audio/sink.c
index 7a08960..c3278cb 100644
--- a/profiles/audio/sink.c
+++ b/profiles/audio/sink.c
@@ -52,7 +52,8 @@
#define STREAM_SETUP_RETRY_TIMER 2

struct pending_request {
- DBusMessage *msg;
+ audio_device_cb cb;
+ void *cb_data;
unsigned int id;
};

@@ -161,10 +162,12 @@ static void avdtp_state_callback(struct audio_device *dev,
}

static void pending_request_free(struct audio_device *dev,
- struct pending_request *pending)
+ struct pending_request *pending,
+ int err)
{
- if (pending->msg)
- dbus_message_unref(pending->msg);
+ if (pending->cb)
+ pending->cb(dev, err, pending->cb_data);
+
if (pending->id)
a2dp_cancel(dev, pending->id);

@@ -177,7 +180,6 @@ static void stream_state_changed(struct avdtp_stream *stream,
struct avdtp_error *err,
void *user_data)
{
- DBusConnection *conn = btd_get_dbus_connection();
struct audio_device *dev = user_data;
struct sink *sink = dev->sink;

@@ -187,15 +189,12 @@ static void stream_state_changed(struct avdtp_stream *stream,
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(conn, reply);
- pending_request_free(dev, p);
+ pending_request_free(dev, p, 0);
}

if (sink->session) {
@@ -221,34 +220,24 @@ static void stream_state_changed(struct avdtp_stream *stream,
sink->stream_state = new_state;
}

-static void error_failed(DBusMessage *msg, const char *desc)
-{
- DBusMessage *reply = btd_error_failed(msg, desc);
- g_dbus_send_message(btd_get_dbus_connection(), reply);
-}
-
static gboolean stream_setup_retry(gpointer user_data)
{
struct sink *sink = user_data;
struct pending_request *pending = sink->connect;
+ int err;

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(btd_get_dbus_connection(), reply);
- }
+ err = 0;
} else {
DBG("Stream setup failed, after XCASE connect:connect");
- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
+ err = -EIO;
}

sink->connect = NULL;
- pending_request_free(sink->dev, pending);
+ pending_request_free(sink->dev, pending, err);

return FALSE;
}
@@ -267,14 +256,8 @@ static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
if (stream) {
DBG("Stream successfully created");

- if (pending->msg) {
- DBusMessage *reply;
- reply = dbus_message_new_method_return(pending->msg);
- g_dbus_send_message(btd_get_dbus_connection(), reply);
- }
-
sink->connect = NULL;
- pending_request_free(sink->dev, pending);
+ pending_request_free(sink->dev, pending, 0);

return;
}
@@ -288,11 +271,8 @@ static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
stream_setup_retry,
sink);
} else {
- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
sink->connect = NULL;
- pending_request_free(sink->dev, pending);
- DBG("Stream setup failed : %s", avdtp_strerror(err));
+ pending_request_free(sink->dev, pending, -EIO);
}
}

@@ -314,9 +294,7 @@ static void select_complete(struct avdtp *session, struct a2dp_sep *sep,
return;

failed:
- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
- pending_request_free(sink->dev, pending);
+ pending_request_free(sink->dev, pending, -EIO);
sink->connect = NULL;
avdtp_unref(sink->session);
sink->session = NULL;
@@ -363,9 +341,7 @@ static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp
return;

failed:
- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
- pending_request_free(sink->dev, pending);
+ pending_request_free(sink->dev, pending, -EIO);
sink->connect = NULL;
avdtp_unref(sink->session);
sink->session = NULL;
@@ -390,69 +366,85 @@ gboolean sink_setup_stream(struct sink *sink, struct avdtp *session)
return TRUE;
}

+static void generic_cb(struct audio_device *dev, int err, void *data)
+{
+ DBusMessage *msg = data;
+ DBusMessage *reply;
+
+ if (err < 0) {
+ reply = btd_error_failed(msg, strerror(-err));
+ g_dbus_send_message(btd_get_dbus_connection(), reply);
+ dbus_message_unref(msg);
+ return;
+ }
+
+ g_dbus_send_reply(btd_get_dbus_connection(), msg, DBUS_TYPE_INVALID);
+
+ dbus_message_unref(msg);
+}
+
static DBusMessage *connect_sink(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct audio_device *dev = data;
+ int err;
+
+ err = sink_connect(dev, generic_cb, msg);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ dbus_message_ref(msg);
+
+ return NULL;
+}
+
+int sink_connect(struct audio_device *dev, audio_device_cb cb, void *data)
+{
struct sink *sink = dev->sink;
struct pending_request *pending;

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->session) {
+ DBG("Unable to get a session");
+ return -EIO;
+ }

if (sink->connect || sink->disconnect)
- return btd_error_busy(msg);
+ return -EBUSY;

if (sink->stream_state >= AVDTP_STATE_OPEN)
- return btd_error_already_connected(msg);
+ return -EALREADY;

- if (!sink_setup_stream(sink, NULL))
- return btd_error_failed(msg, "Failed to create a stream");
+ if (!sink_setup_stream(sink, NULL)) {
+ DBG("Failed to create a stream");
+ return -EIO;
+ }

dev->auto_connect = FALSE;

pending = sink->connect;

- pending->msg = dbus_message_ref(msg);
+ pending->cb = cb;
+ pending->cb_data = data;

DBG("stream creation in progress");

- return NULL;
+ return 0;
}

static DBusMessage *disconnect_sink(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- struct audio_device *device = data;
- struct sink *sink = device->sink;
- struct pending_request *pending;
+ struct audio_device *dev = data;
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);
+ err = sink_disconnect(dev, FALSE, generic_cb, msg);
if (err < 0)
return btd_error_failed(msg, strerror(-err));

- pending = g_new0(struct pending_request, 1);
- pending->msg = dbus_message_ref(msg);
- sink->disconnect = pending;
+ dbus_message_ref(msg);

return NULL;
}
@@ -515,10 +507,10 @@ static void sink_free(struct audio_device *dev)
avdtp_unref(sink->session);

if (sink->connect)
- pending_request_free(dev, sink->connect);
+ pending_request_free(dev, sink->connect, -ECANCELED);

if (sink->disconnect)
- pending_request_free(dev, sink->disconnect);
+ pending_request_free(dev, sink->disconnect, -ECANCELED);

if (sink->retry_id)
g_source_remove(sink->retry_id);
@@ -604,9 +596,13 @@ gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
return TRUE;
}

-int sink_disconnect(struct audio_device *dev, gboolean shutdown)
+int sink_disconnect(struct audio_device *dev, gboolean shutdown,
+ audio_device_cb cb, void *data)
{
- struct sink *sink = dev->sink;
+ struct audio_device *device = data;
+ struct sink *sink = device->sink;
+ struct pending_request *pending;
+ int err;

if (!sink->session)
return -ENOTCONN;
@@ -618,9 +614,7 @@ int sink_disconnect(struct audio_device *dev, gboolean shutdown)
if (sink->connect) {
struct pending_request *pending = sink->connect;

- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
- pending_request_free(sink->dev, pending);
+ pending_request_free(sink->dev, pending, -ECANCELED);
sink->connect = NULL;

avdtp_unref(sink->session);
@@ -636,7 +630,16 @@ int sink_disconnect(struct audio_device *dev, gboolean shutdown)
if (!sink->stream)
return -ENOTCONN;

- return avdtp_close(sink->session, sink->stream, FALSE);
+ err = avdtp_close(sink->session, sink->stream, FALSE);
+ if (err < 0)
+ return err;
+
+ pending = g_new0(struct pending_request, 1);
+ pending->cb = cb;
+ pending->cb_data = data;
+ sink->disconnect = pending;
+
+ return 0;
}

unsigned int sink_add_state_cb(sink_state_cb cb, void *user_data)
diff --git a/profiles/audio/sink.h b/profiles/audio/sink.h
index 426d83f..38098f2 100644
--- a/profiles/audio/sink.h
+++ b/profiles/audio/sink.h
@@ -43,7 +43,9 @@ struct sink *sink_init(struct audio_device *dev);
void sink_unregister(struct audio_device *dev);
gboolean sink_is_active(struct audio_device *dev);
sink_state_t sink_get_state(struct audio_device *dev);
+int sink_connect(struct audio_device *dev, audio_device_cb cb, void *data);
gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
struct avdtp_stream *stream);
gboolean sink_setup_stream(struct sink *sink, struct avdtp *session);
-int sink_disconnect(struct audio_device *dev, gboolean shutdown);
+int sink_disconnect(struct audio_device *dev, gboolean shutdown,
+ audio_device_cb cb, void *data);
--
1.7.11.7


2012-11-15 07:27:39

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v2 7/8] 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-15 07:27:40

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v2 8/8] 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-15 07:27:38

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v2 6/8] 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 the
approach of the HFP/HSP profile.
---
profiles/audio/a2dp.c | 88 ++++++++++++++++++--------------------
profiles/audio/a2dp.h | 4 +-
profiles/audio/manager.c | 107 ++++++++++++++++++++++++++++++++++++++++-------
3 files changed, 135 insertions(+), 64 deletions(-)

diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c
index 7799420..6bfc8c2 100644
--- a/profiles/audio/a2dp.c
+++ b/profiles/audio/a2dp.c
@@ -1167,73 +1167,67 @@ 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;
gboolean delay_reporting = 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, &server->version);
+ 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);
- }
+ if (config)
+ delay_reporting = g_key_file_get_boolean(config, "A2DP",
+ "DelayReporting", NULL);

-proceed:
+ if (delay_reporting)
+ server->version = 0x0103;
+ else
+ server->version = 0x0102;
+
+ return 0;
+}
+
+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, &server->version);
- 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;
+}

- if (config)
- delay_reporting = g_key_file_get_boolean(config, "A2DP",
- "DelayReporting", NULL);
+int a2dp_sink_register(const bdaddr_t *src, GKeyFile *config)
+{
+ struct a2dp_server *server;

- if (delay_reporting)
- server->version = 0x0103;
- else
- server->version = 0x0102;
+ server = find_server(servers, src);
+ if (!server) {
+ DBG("AVDTP not registered");
+ return -EPROTONOSUPPORT;

- server->source_enabled = source;
+ }

- 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


2012-11-15 07:27:36

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v2 4/8] source: Expose internal connection API

From: Mikel Astiz <[email protected]>

Separate the D-Bus code from the internal connection handling code,
exposing an internal API in case some internal codepath/plugin is
interested in using it.
---
profiles/audio/device.h | 3 +
profiles/audio/source.c | 160 ++++++++++++++++++++++++------------------------
profiles/audio/source.h | 4 +-
3 files changed, 87 insertions(+), 80 deletions(-)

diff --git a/profiles/audio/device.h b/profiles/audio/device.h
index f0d178d..0801cda 100644
--- a/profiles/audio/device.h
+++ b/profiles/audio/device.h
@@ -22,6 +22,7 @@
*
*/

+struct audio_device;
struct source;
struct control;
struct target;
@@ -30,6 +31,8 @@ struct headset;
struct gateway;
struct dev_priv;

+typedef void (*audio_device_cb) (struct audio_device *dev, int err, void *data);
+
struct audio_device {
struct btd_device *btd_dev;

diff --git a/profiles/audio/source.c b/profiles/audio/source.c
index 9981d79..163f5b9 100644
--- a/profiles/audio/source.c
+++ b/profiles/audio/source.c
@@ -53,7 +53,8 @@
#define STREAM_SETUP_RETRY_TIMER 2

struct pending_request {
- DBusMessage *msg;
+ audio_device_cb cb;
+ void *cb_data;
unsigned int id;
};

@@ -152,10 +153,12 @@ static void avdtp_state_callback(struct audio_device *dev,
}

static void pending_request_free(struct audio_device *dev,
- struct pending_request *pending)
+ struct pending_request *pending,
+ int err)
{
- if (pending->msg)
- dbus_message_unref(pending->msg);
+ if (pending->cb)
+ pending->cb(dev, err, pending->cb_data);
+
if (pending->id)
a2dp_cancel(dev, pending->id);

@@ -177,15 +180,12 @@ static void stream_state_changed(struct avdtp_stream *stream,
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(btd_get_dbus_connection(), reply);
- pending_request_free(dev, p);
+ pending_request_free(dev, p, 0);
}

if (source->session) {
@@ -211,35 +211,24 @@ static void stream_state_changed(struct avdtp_stream *stream,
source->stream_state = new_state;
}

-static void error_failed(DBusMessage *msg,
- const char *desc)
-{
- DBusMessage *reply = btd_error_failed(msg, desc);
- g_dbus_send_message(btd_get_dbus_connection(), reply);
-}
-
static gboolean stream_setup_retry(gpointer user_data)
{
struct source *source = user_data;
struct pending_request *pending = source->connect;
+ int err;

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(btd_get_dbus_connection(), reply);
- }
+ err = 0;
} else {
DBG("Stream setup failed, after XCASE connect:connect");
- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
+ err = -EIO;
}

source->connect = NULL;
- pending_request_free(source->dev, pending);
+ pending_request_free(source->dev, pending, err);

return FALSE;
}
@@ -258,14 +247,8 @@ static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
if (stream) {
DBG("Stream successfully created");

- if (pending->msg) {
- DBusMessage *reply;
- reply = dbus_message_new_method_return(pending->msg);
- g_dbus_send_message(btd_get_dbus_connection(), reply);
- }
-
source->connect = NULL;
- pending_request_free(source->dev, pending);
+ pending_request_free(source->dev, pending, 0);

return;
}
@@ -279,10 +262,8 @@ static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
stream_setup_retry,
source);
} else {
- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
source->connect = NULL;
- pending_request_free(source->dev, pending);
+ pending_request_free(source->dev, pending, -EIO);
DBG("Stream setup failed : %s", avdtp_strerror(err));
}
}
@@ -309,9 +290,7 @@ static void select_complete(struct avdtp *session, struct a2dp_sep *sep,
return;

failed:
- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
- pending_request_free(source->dev, pending);
+ pending_request_free(source->dev, pending, -EIO);
source->connect = NULL;
avdtp_unref(source->session);
source->session = NULL;
@@ -352,9 +331,7 @@ static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp
return;

failed:
- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
- pending_request_free(source->dev, pending);
+ pending_request_free(source->dev, pending, -EIO);
source->connect = NULL;
avdtp_unref(source->session);
source->session = NULL;
@@ -379,69 +356,84 @@ gboolean source_setup_stream(struct source *source, struct avdtp *session)
return TRUE;
}

+static void generic_cb(struct audio_device *dev, int err, void *data)
+{
+ DBusMessage *msg = data;
+ DBusMessage *reply;
+
+ if (err < 0) {
+ reply = btd_error_failed(msg, strerror(-err));
+ g_dbus_send_message(btd_get_dbus_connection(), reply);
+ dbus_message_unref(msg);
+ return;
+ }
+
+ g_dbus_send_reply(btd_get_dbus_connection(), msg, DBUS_TYPE_INVALID);
+
+ dbus_message_unref(msg);
+}
+
static DBusMessage *connect_source(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct audio_device *dev = data;
+ int err;
+
+ err = source_connect(dev, generic_cb, msg);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ dbus_message_ref(msg);
+
+ return NULL;
+}
+
+int source_connect(struct audio_device *dev, audio_device_cb cb, void *data)
+{
struct source *source = dev->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->session) {
+ DBG("Unable to get a session");
+ return -EIO;
+ }

if (source->connect || source->disconnect)
- return btd_error_busy(msg);
+ return -EBUSY;

if (source->stream_state >= AVDTP_STATE_OPEN)
- return btd_error_already_connected(msg);
+ return -EALREADY;

- if (!source_setup_stream(source, NULL))
- return btd_error_failed(msg, "Failed to create a stream");
+ if (!source_setup_stream(source, NULL)) {
+ DBG("Failed to create a stream");
+ return -EIO;
+ }

dev->auto_connect = FALSE;

pending = source->connect;
-
- pending->msg = dbus_message_ref(msg);
+ pending->cb = cb;
+ pending->cb_data = data;

DBG("stream creation in progress");

- return NULL;
+ return 0;
}

static DBusMessage *disconnect_source(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- struct audio_device *device = data;
- struct source *source = device->source;
- struct pending_request *pending;
+ struct audio_device *dev = data;
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);
+ err = source_disconnect(dev, FALSE, generic_cb, msg);
if (err < 0)
return btd_error_failed(msg, strerror(-err));

- pending = g_new0(struct pending_request, 1);
- pending->msg = dbus_message_ref(msg);
- source->disconnect = pending;
+ dbus_message_ref(msg);

return NULL;
}
@@ -504,10 +496,10 @@ static void source_free(struct audio_device *dev)
avdtp_unref(source->session);

if (source->connect)
- pending_request_free(dev, source->connect);
+ pending_request_free(dev, source->connect, -ECANCELED);

if (source->disconnect)
- pending_request_free(dev, source->disconnect);
+ pending_request_free(dev, source->disconnect, -ECANCELED);

if (source->retry_id)
g_source_remove(source->retry_id);
@@ -593,9 +585,13 @@ gboolean source_new_stream(struct audio_device *dev, struct avdtp *session,
return TRUE;
}

-int source_disconnect(struct audio_device *dev, gboolean shutdown)
+int source_disconnect(struct audio_device *dev, gboolean shutdown,
+ audio_device_cb cb, void *data)
{
- struct source *source = dev->source;
+ struct audio_device *device = data;
+ struct source *source = device->source;
+ struct pending_request *pending;
+ int err;

if (!source->session)
return -ENOTCONN;
@@ -607,10 +603,7 @@ int source_disconnect(struct audio_device *dev, gboolean shutdown)
if (source->connect) {
struct pending_request *pending = source->connect;

- if (pending->msg)
- error_failed(pending->msg, "Stream setup failed");
-
- pending_request_free(source->dev, pending);
+ pending_request_free(source->dev, pending, -ECANCELED);
source->connect = NULL;

avdtp_unref(source->session);
@@ -626,7 +619,16 @@ int source_disconnect(struct audio_device *dev, gboolean shutdown)
if (!source->stream)
return -ENOTCONN;

- return avdtp_close(source->session, source->stream, FALSE);
+ err = avdtp_close(source->session, source->stream, FALSE);
+ if (err < 0)
+ return err;
+
+ pending = g_new0(struct pending_request, 1);
+ pending->cb = cb;
+ pending->cb_data = data;
+ source->disconnect = pending;
+
+ return 0;
}

unsigned int source_add_state_cb(source_state_cb cb, void *user_data)
diff --git a/profiles/audio/source.h b/profiles/audio/source.h
index 3406754..2d382b5 100644
--- a/profiles/audio/source.h
+++ b/profiles/audio/source.h
@@ -44,7 +44,9 @@ struct source *source_init(struct audio_device *dev);
void source_unregister(struct audio_device *dev);
gboolean source_is_active(struct audio_device *dev);
source_state_t source_get_state(struct audio_device *dev);
+int source_connect(struct audio_device *dev, audio_device_cb cb, void *data);
gboolean source_new_stream(struct audio_device *dev, struct avdtp *session,
struct avdtp_stream *stream);
gboolean source_setup_stream(struct source *source, struct avdtp *session);
-int source_disconnect(struct audio_device *dev, gboolean shutdown);
+int source_disconnect(struct audio_device *dev, gboolean shutdown,
+ audio_device_cb cb, void *data);
--
1.7.11.7


2012-11-15 07:27:35

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v2 3/8] source: Add missing code in source_disconnect()

From: Mikel Astiz <[email protected]>

Use the implementation in sink_disconnect() as a template to implement
the missing code in source_disconnect(). Both functions should be
equivalent.
---
profiles/audio/source.c | 37 +++++++++++++++++++++++++++++++------
profiles/audio/source.h | 2 +-
2 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/profiles/audio/source.c b/profiles/audio/source.c
index 38cb822..9981d79 100644
--- a/profiles/audio/source.c
+++ b/profiles/audio/source.c
@@ -593,15 +593,40 @@ gboolean source_new_stream(struct audio_device *dev, struct avdtp *session,
return TRUE;
}

-gboolean source_disconnect(struct source *source)
+int source_disconnect(struct audio_device *dev, gboolean shutdown)
{
- if (!source->stream)
- return FALSE;
+ struct source *source = dev->source;

- if (avdtp_close(source->session, source->stream, FALSE) < 0)
- return FALSE;
+ if (!source->session)
+ return -ENOTCONN;

- return TRUE;
+ if (shutdown)
+ avdtp_set_device_disconnect(source->session, TRUE);
+
+ /* cancel pending connect */
+ if (source->connect) {
+ struct pending_request *pending = source->connect;
+
+ if (pending->msg)
+ error_failed(pending->msg, "Stream setup failed");
+
+ pending_request_free(source->dev, pending);
+ source->connect = NULL;
+
+ avdtp_unref(source->session);
+ source->session = NULL;
+
+ return 0;
+ }
+
+ /* disconnect already ongoing */
+ if (source->disconnect)
+ return -EBUSY;
+
+ if (!source->stream)
+ return -ENOTCONN;
+
+ return avdtp_close(source->session, source->stream, FALSE);
}

unsigned int source_add_state_cb(source_state_cb cb, void *user_data)
diff --git a/profiles/audio/source.h b/profiles/audio/source.h
index 49a8d64..3406754 100644
--- a/profiles/audio/source.h
+++ b/profiles/audio/source.h
@@ -47,4 +47,4 @@ source_state_t source_get_state(struct audio_device *dev);
gboolean source_new_stream(struct audio_device *dev, struct avdtp *session,
struct avdtp_stream *stream);
gboolean source_setup_stream(struct source *source, struct avdtp *session);
-gboolean source_disconnect(struct source *source);
+int source_disconnect(struct audio_device *dev, gboolean shutdown);
--
1.7.11.7


2012-11-15 07:27:33

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v2 1/8] audio: Trivial function renames

From: Mikel Astiz <[email protected]>

Rename functions to be consistent with the rest of the code.
---
profiles/audio/device.c | 4 ++--
profiles/audio/sink.c | 10 +++++-----
profiles/audio/sink.h | 2 +-
profiles/audio/source.c | 10 +++++-----
profiles/audio/source.h | 2 +-
5 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/profiles/audio/device.c b/profiles/audio/device.c
index df57d81..811ed75 100644
--- a/profiles/audio/device.c
+++ b/profiles/audio/device.c
@@ -203,7 +203,7 @@ static void disconnect_cb(struct btd_device *btd_dev, gboolean removal,
avrcp_disconnect(dev);

if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED)
- sink_shutdown(dev->sink);
+ sink_disconnect(dev->sink);
else
priv->disconnecting = FALSE;
}
@@ -390,7 +390,7 @@ static DBusMessage *dev_disconnect(DBusConnection *conn, DBusMessage *msg,
}

if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED)
- sink_shutdown(dev->sink);
+ sink_disconnect(dev->sink);
else {
dbus_message_unref(priv->dc_req);
priv->dc_req = NULL;
diff --git a/profiles/audio/sink.c b/profiles/audio/sink.c
index 2e63579..e769917 100644
--- a/profiles/audio/sink.c
+++ b/profiles/audio/sink.c
@@ -390,7 +390,7 @@ gboolean sink_setup_stream(struct sink *sink, struct avdtp *session)
return TRUE;
}

-static DBusMessage *sink_connect(DBusConnection *conn,
+static DBusMessage *connect_sink(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct audio_device *dev = data;
@@ -423,7 +423,7 @@ static DBusMessage *sink_connect(DBusConnection *conn,
return NULL;
}

-static DBusMessage *sink_disconnect(DBusConnection *conn,
+static DBusMessage *disconnect_sink(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct audio_device *device = data;
@@ -489,8 +489,8 @@ static DBusMessage *sink_get_properties(DBusConnection *conn,
}

static const GDBusMethodTable sink_methods[] = {
- { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, sink_connect) },
- { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, sink_disconnect) },
+ { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, connect_sink) },
+ { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, disconnect_sink) },
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
sink_get_properties) },
@@ -604,7 +604,7 @@ gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
return TRUE;
}

-gboolean sink_shutdown(struct sink *sink)
+gboolean sink_disconnect(struct sink *sink)
{
if (!sink->session)
return FALSE;
diff --git a/profiles/audio/sink.h b/profiles/audio/sink.h
index 4fea5ba..edac364 100644
--- a/profiles/audio/sink.h
+++ b/profiles/audio/sink.h
@@ -46,4 +46,4 @@ sink_state_t sink_get_state(struct audio_device *dev);
gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
struct avdtp_stream *stream);
gboolean sink_setup_stream(struct sink *sink, struct avdtp *session);
-gboolean sink_shutdown(struct sink *sink);
+gboolean sink_disconnect(struct sink *sink);
diff --git a/profiles/audio/source.c b/profiles/audio/source.c
index 1d0c74a..38cb822 100644
--- a/profiles/audio/source.c
+++ b/profiles/audio/source.c
@@ -379,7 +379,7 @@ gboolean source_setup_stream(struct source *source, struct avdtp *session)
return TRUE;
}

-static DBusMessage *source_connect(DBusConnection *conn,
+static DBusMessage *connect_source(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct audio_device *dev = data;
@@ -412,7 +412,7 @@ static DBusMessage *source_connect(DBusConnection *conn,
return NULL;
}

-static DBusMessage *source_disconnect(DBusConnection *conn,
+static DBusMessage *disconnect_source(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct audio_device *device = data;
@@ -478,8 +478,8 @@ static DBusMessage *source_get_properties(DBusConnection *conn,
}

static const GDBusMethodTable source_methods[] = {
- { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, source_connect) },
- { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, source_disconnect) },
+ { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, connect_source) },
+ { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, disconnect_source) },
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
source_get_properties) },
@@ -593,7 +593,7 @@ gboolean source_new_stream(struct audio_device *dev, struct avdtp *session,
return TRUE;
}

-gboolean source_shutdown(struct source *source)
+gboolean source_disconnect(struct source *source)
{
if (!source->stream)
return FALSE;
diff --git a/profiles/audio/source.h b/profiles/audio/source.h
index 695bded..49a8d64 100644
--- a/profiles/audio/source.h
+++ b/profiles/audio/source.h
@@ -47,4 +47,4 @@ source_state_t source_get_state(struct audio_device *dev);
gboolean source_new_stream(struct audio_device *dev, struct avdtp *session,
struct avdtp_stream *stream);
gboolean source_setup_stream(struct source *source, struct avdtp *session);
-gboolean source_shutdown(struct source *source);
+gboolean source_disconnect(struct source *source);
--
1.7.11.7


2012-11-15 07:27:34

by Mikel Astiz

[permalink] [raw]
Subject: [PATCH v2 2/8] sink: Generalize disconnection function

From: Mikel Astiz <[email protected]>

Extend the function for a more general usage other than full device
disconnection. Besides, return error code instead of a boolean.
---
profiles/audio/device.c | 4 ++--
profiles/audio/sink.c | 20 ++++++++++----------
profiles/audio/sink.h | 2 +-
3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/profiles/audio/device.c b/profiles/audio/device.c
index 811ed75..09a1ed7 100644
--- a/profiles/audio/device.c
+++ b/profiles/audio/device.c
@@ -203,7 +203,7 @@ static void disconnect_cb(struct btd_device *btd_dev, gboolean removal,
avrcp_disconnect(dev);

if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED)
- sink_disconnect(dev->sink);
+ sink_disconnect(dev, TRUE);
else
priv->disconnecting = FALSE;
}
@@ -390,7 +390,7 @@ static DBusMessage *dev_disconnect(DBusConnection *conn, DBusMessage *msg,
}

if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED)
- sink_disconnect(dev->sink);
+ sink_disconnect(dev, TRUE);
else {
dbus_message_unref(priv->dc_req);
priv->dc_req = NULL;
diff --git a/profiles/audio/sink.c b/profiles/audio/sink.c
index e769917..7a08960 100644
--- a/profiles/audio/sink.c
+++ b/profiles/audio/sink.c
@@ -604,12 +604,15 @@ gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
return TRUE;
}

-gboolean sink_disconnect(struct sink *sink)
+int sink_disconnect(struct audio_device *dev, gboolean shutdown)
{
+ struct sink *sink = dev->sink;
+
if (!sink->session)
- return FALSE;
+ return -ENOTCONN;

- avdtp_set_device_disconnect(sink->session, TRUE);
+ if (shutdown)
+ avdtp_set_device_disconnect(sink->session, TRUE);

/* cancel pending connect */
if (sink->connect) {
@@ -623,20 +626,17 @@ gboolean sink_disconnect(struct sink *sink)
avdtp_unref(sink->session);
sink->session = NULL;

- return TRUE;
+ return 0;
}

/* disconnect already ongoing */
if (sink->disconnect)
- return TRUE;
+ return -EBUSY;

if (!sink->stream)
- return FALSE;
-
- if (avdtp_close(sink->session, sink->stream, FALSE) < 0)
- return FALSE;
+ return -ENOTCONN;

- return TRUE;
+ return avdtp_close(sink->session, sink->stream, FALSE);
}

unsigned int sink_add_state_cb(sink_state_cb cb, void *user_data)
diff --git a/profiles/audio/sink.h b/profiles/audio/sink.h
index edac364..426d83f 100644
--- a/profiles/audio/sink.h
+++ b/profiles/audio/sink.h
@@ -46,4 +46,4 @@ sink_state_t sink_get_state(struct audio_device *dev);
gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
struct avdtp_stream *stream);
gboolean sink_setup_stream(struct sink *sink, struct avdtp *session);
-gboolean sink_disconnect(struct sink *sink);
+int sink_disconnect(struct audio_device *dev, gboolean shutdown);
--
1.7.11.7