summaryrefslogtreecommitdiffstats
path: root/audio/sink.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2007-08-16 15:42:10 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2007-08-16 15:42:10 +0000
commitcdd9e2e17ad674e5fc1a5ed19643880ef61d28c7 (patch)
tree5292da714c803e54ad8e199f3a06d6db9d9d42f2 /audio/sink.c
parent3863eba35ca65bb4ea17d3763ae27afafdf0f4c2 (diff)
Rework interfacing with the avdtp state machine
Diffstat (limited to 'audio/sink.c')
-rw-r--r--audio/sink.c325
1 files changed, 74 insertions, 251 deletions
diff --git a/audio/sink.c b/audio/sink.c
index fe8b6393..0f69bbf6 100644
--- a/audio/sink.c
+++ b/audio/sink.c
@@ -46,29 +46,29 @@
#include "sink.h"
struct pending_request {
+ DBusConnection *conn;
DBusMessage *msg;
- struct ipc_packet *pkt;
- int pkt_len;
- int sock;
+ int id;
};
struct sink {
struct avdtp *session;
struct avdtp_stream *stream;
uint8_t state;
- struct pending_request *c;
+ struct pending_request *connect;
+ struct pending_request *disconnect;
DBusConnection *conn;
gboolean initiator;
gboolean suspending;
};
-static void pending_connect_free(struct pending_request *c)
+static void pending_request_free(struct pending_request *pending)
{
- if (c->pkt)
- g_free(c->pkt);
- if (c->msg)
- dbus_message_unref(c->msg);
- g_free(c);
+ if (pending->conn)
+ dbus_connection_unref(pending->conn);
+ if (pending->msg)
+ dbus_message_unref(pending->msg);
+ g_free(pending);
}
void stream_state_changed(struct avdtp_stream *stream, avdtp_state_t old_state,
@@ -77,12 +77,9 @@ void stream_state_changed(struct avdtp_stream *stream, avdtp_state_t old_state,
{
struct device *dev = user_data;
struct sink *sink = dev->sink;
- struct pending_request *c = NULL;
- DBusMessage *reply;
- int cmd_err;
if (err)
- goto failed;
+ return;
switch (new_state) {
case AVDTP_STATE_IDLE:
@@ -90,152 +87,64 @@ void stream_state_changed(struct avdtp_stream *stream, avdtp_state_t old_state,
AUDIO_SINK_INTERFACE,
"Disconnected",
DBUS_TYPE_INVALID);
+ if (sink->disconnect) {
+ DBusMessage *reply;
+ struct pending_request *p;
+
+ p = sink->disconnect;
+ sink->disconnect = NULL;
+
+ reply = dbus_message_new_method_return(p->msg);
+ send_message_and_unref(p->conn, reply);
+ pending_request_free(p);
+ }
+
if (sink->session) {
avdtp_unref(sink->session);
sink->session = NULL;
}
sink->stream = NULL;
- c = sink->c;
- break;
- case AVDTP_STATE_CONFIGURED:
- if (!sink->initiator)
- break;
-
- cmd_err = avdtp_open(sink->session, stream);
- if (cmd_err < 0) {
- error("Error on avdtp_open %s (%d)", strerror(-cmd_err),
- cmd_err);
- goto failed;
- }
-
- if (sink->c && sink->c->pkt)
- a2dp_start_stream_when_opened(sink->session, stream);
break;
case AVDTP_STATE_OPEN:
- sink->suspending = FALSE;
-
if (old_state == AVDTP_STATE_CONFIGURED)
dbus_connection_emit_signal(dev->conn, dev->path,
AUDIO_SINK_INTERFACE,
"Connected",
DBUS_TYPE_INVALID);
-
- if (!sink->initiator)
- break;
-
- if (!(sink->c && sink->c->pkt))
- c = sink->c;
-
break;
+ case AVDTP_STATE_CONFIGURED:
case AVDTP_STATE_STREAMING:
- c = sink->c;
- break;
case AVDTP_STATE_CLOSING:
- break;
case AVDTP_STATE_ABORTING:
+ default:
break;
}
sink->state = new_state;
-
- if (c) {
- sink->c = NULL;
-
- if (c->msg) {
- reply = dbus_message_new_method_return(c->msg);
- send_message_and_unref(dev->conn, reply);
- }
- if (c->pkt) {
- struct ipc_data_cfg *rsp;
- int ret, fd;
-
- ret = sink_get_config(dev, c->sock, c->pkt,
- c->pkt_len, &rsp, &fd);
- if (ret == 0) {
- unix_send_cfg(c->sock, rsp, fd);
- g_free(rsp);
- }
- else
- unix_send_cfg(c->sock, NULL, -1);
- }
-
- pending_connect_free(c);
- }
-
- return;
-
-failed:
- if (sink->c) {
- if (sink->c->msg && err)
- err_failed(dev->conn, sink->c->msg,
- avdtp_strerror(err));
-
- pending_connect_free(sink->c);
- sink->c = NULL;
- }
-
- if (new_state == AVDTP_STATE_IDLE) {
- avdtp_unref(sink->session);
- sink->session = NULL;
- sink->stream = NULL;
- }
}
-static void discovery_complete(struct avdtp *session, GSList *seps, int err,
- void *user_data)
+static void stream_setup_complete(struct avdtp *session, struct device *dev,
+ struct avdtp_stream *stream,
+ void *user_data)
{
- struct device *dev = user_data;
struct sink *sink = dev->sink;
- struct avdtp_local_sep *lsep;
- struct avdtp_remote_sep *rsep;
- GSList *caps = NULL;
- const char *err_str = NULL;
-
- if (err < 0) {
- error("Discovery failed");
- err_str = strerror(-err);
- goto failed;
- }
-
- debug("Discovery complete");
-
- if (avdtp_get_seps(session, AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
- A2DP_CODEC_SBC, &lsep, &rsep) < 0) {
- err_str = "No matching ACP and INT SEPs found";
- goto failed;
- }
+ struct pending_request *pending;
- if (!a2dp_select_capabilities(rsep, &caps)) {
- err_str = "Unable to select remote SEP capabilities";
- goto failed;
- }
+ pending = sink->connect;
+ sink->connect = NULL;
- err = avdtp_set_configuration(session, rsep, lsep, caps,
- &sink->stream);
- if (err < 0) {
- error("avdtp_set_configuration: %s", strerror(-err));
- err_str = "Unable to set configuration";
- goto failed;
+ if (stream) {
+ DBusMessage *reply;
+ reply = dbus_message_new_method_return(pending->msg);
+ send_message_and_unref(pending->conn, reply);
}
-
- sink->initiator = TRUE;
-
- avdtp_stream_set_cb(session, sink->stream, stream_state_changed, dev);
-
- return;
-
-failed:
- error("%s", err_str);
- if (sink->c) {
- if (sink->c->msg)
- err_failed(dev->conn, sink->c->msg, err_str);
- pending_connect_free(sink->c);
- sink->c = NULL;
- }
- if (sink->session) {
+ else {
+ err_failed(pending->conn, pending->msg, "Stream setup failed");
avdtp_unref(sink->session);
sink->session = NULL;
}
+
+ pending_request_free(pending);
}
static DBusHandlerResult sink_connect(DBusConnection *conn,
@@ -243,31 +152,36 @@ static DBusHandlerResult sink_connect(DBusConnection *conn,
{
struct device *dev = data;
struct sink *sink = dev->sink;
- struct pending_request *c;
- int err;
+ struct pending_request *pending;
+ int id;
if (!sink->session)
sink->session = avdtp_get(&dev->src, &dev->dst);
- if (sink->c)
+ if (sink->connect || sink->disconnect)
return err_connect_failed(conn, msg, "Connect in progress");
if (sink->state >= AVDTP_STATE_OPEN)
return err_already_connected(conn, msg);
- c = g_new0(struct pending_request, 1);
- c->msg = dbus_message_ref(msg);
- sink->c = c;
+ pending = g_new0(struct pending_request, 1);
+ pending->conn = dbus_connection_ref(conn);
+ pending->msg = dbus_message_ref(msg);
+ sink->connect = pending;
- err = avdtp_discover(sink->session, discovery_complete, data);
- if (err < 0) {
- pending_connect_free(c);
- sink->c = NULL;
+ id = a2dp_source_request_stream(sink->session, dev, FALSE,
+ stream_setup_complete, pending);
+ if (id < 0) {
+ pending_request_free(pending);
+ sink->connect = NULL;
avdtp_unref(sink->session);
sink->session = NULL;
- return err_connect_failed(conn, msg, strerror(err));
+ return err_connect_failed(conn, msg,
+ "Failed to request a stream");
}
+ pending->id = id;
+
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -276,27 +190,32 @@ static DBusHandlerResult sink_disconnect(DBusConnection *conn,
{
struct device *device = data;
struct sink *sink = device->sink;
- struct pending_request *c;
+ struct pending_request *pending;
int err;
if (!sink->session)
return err_not_connected(conn, msg);
- if (sink->c)
+ if (sink->connect || sink->disconnect)
return err_failed(conn, msg, strerror(EBUSY));
if (sink->state < AVDTP_STATE_OPEN) {
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
avdtp_unref(sink->session);
sink->session = NULL;
- } else {
- err = avdtp_close(sink->session, sink->stream);
- if (err < 0)
- return err_failed(conn, msg, strerror(-err));
+ return send_message_and_unref(conn, reply);
}
- c = g_new0(struct pending_request, 1);
- c->msg = dbus_message_ref(msg);
- sink->c = c;
+ err = avdtp_close(sink->session, sink->stream);
+ if (err < 0)
+ return err_failed(conn, 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 DBUS_HANDLER_RESULT_HANDLED;
}
@@ -355,66 +274,16 @@ void sink_free(struct device *dev)
if (sink->session)
avdtp_unref(sink->session);
- if (sink->c)
- pending_connect_free(sink->c);
+ if (sink->connect)
+ pending_request_free(sink->connect);
+
+ if (sink->disconnect)
+ pending_request_free(sink->disconnect);
g_free(sink);
dev->sink = NULL;
}
-int sink_get_config(struct device *dev, int sock, struct ipc_packet *req,
- int pkt_len, struct ipc_data_cfg **rsp, int *fd)
-{
- struct sink *sink = dev->sink;
- int err;
- struct pending_request *c = NULL;
-
- if (!sink->suspending && sink->state == AVDTP_STATE_STREAMING)
- goto proceed;
-
- if (sink->c) {
- error("sink_get_config: another request already in progress");
- return -EBUSY;
- }
-
- if (!sink->session)
- sink->session = avdtp_get(&dev->src, &dev->dst);
-
- c = g_new0(struct pending_request, 1);
- c->sock = sock;
- c->pkt = g_malloc(pkt_len);
- memcpy(c->pkt, req, pkt_len);
-
- if (sink->state == AVDTP_STATE_IDLE)
- err = avdtp_discover(sink->session, discovery_complete, dev);
- else if (sink->state < AVDTP_STATE_STREAMING)
- err = avdtp_start(sink->session, sink->stream);
- else if (sink->suspending)
- err = 0;
- else
- err = -EINVAL;
-
- if (err < 0)
- goto failed;
-
- sink->c = c;
-
- return 1;
-
-proceed:
- if (!a2dp_get_config(sink->stream, rsp, fd)) {
- err = -EINVAL;
- goto failed;
- }
-
- return 0;
-
-failed:
- if (c)
- pending_connect_free(c);
- return -err;
-}
-
gboolean sink_is_active(struct device *dev)
{
struct sink *sink = dev->sink;
@@ -425,52 +294,6 @@ gboolean sink_is_active(struct device *dev)
return FALSE;
}
-void sink_set_state(struct device *dev, avdtp_state_t state)
-{
- struct sink *sink = dev->sink;
- int err = 0;
-
- if (sink->state == state)
- return;
-
- if (!sink->session || !sink->stream)
- goto failed;
-
- switch (sink->state) {
- case AVDTP_STATE_OPEN:
- if (state == AVDTP_STATE_STREAMING) {
- err = avdtp_start(sink->session, sink->stream);
- if (err == 0)
- return;
- }
- else if (state == AVDTP_STATE_IDLE) {
- err = avdtp_close(sink->session, sink->stream);
- if (err == 0)
- return;
- }
- break;
- case AVDTP_STATE_STREAMING:
- if (state == AVDTP_STATE_OPEN) {
- err = avdtp_suspend(sink->session, sink->stream);
- if (err == 0) {
- sink->suspending = TRUE;
- return;
- }
- }
- else if (state == AVDTP_STATE_IDLE) {
- err = avdtp_close(sink->session, sink->stream);
- if (err == 0)
- return;
- }
- break;
- default:
- goto failed;
- }
-
-failed:
- error("%s: Error changing states", dev->path);
-}
-
avdtp_state_t sink_get_state(struct device *dev)
{
struct sink *sink = dev->sink;