sink: Expose internal connection API

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.
This commit is contained in:
Mikel Astiz 2012-11-15 08:27:37 +01:00 committed by Luiz Augusto von Dentz
parent 6b2faaa185
commit 6086d9c742
3 changed files with 84 additions and 80 deletions

View File

@ -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;

View File

@ -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,12 @@ 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 pending_request *pending;
int err;
if (!sink->session)
return -ENOTCONN;
@ -618,9 +613,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 +629,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)

View File

@ -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);