diff options
Diffstat (limited to 'audio/sink.c')
-rw-r--r-- | audio/sink.c | 325 |
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; |