static unsigned int avctp_id = 0;
+struct pending_request {
+ audio_device_cb cb;
+ void *data;
+ unsigned int id;
+};
+
struct control {
struct avctp *session;
gboolean target;
- DBusMessage *connect;
+ struct pending_request *connect;
};
+static void pending_request_free(struct audio_device *dev,
+ struct pending_request *pending,
+ int err)
+{
+ if (pending->cb)
+ pending->cb(dev, err, pending->data);
+
+ g_free(pending);
+}
+
static void state_changed(struct audio_device *dev, avctp_state_t old_state,
avctp_state_t new_state, void *user_data)
{
control->session = NULL;
if (control->connect) {
- DBusMessage *reply = btd_error_failed(control->connect,
- "Unable to connect");
-
- g_dbus_send_message(btd_get_dbus_connection(), reply);
- dbus_message_unref(control->connect);
+ pending_request_free(dev, control->connect, -EIO);
control->connect = NULL;
}
break;
case AVCTP_STATE_CONNECTED:
if (control->connect) {
- g_dbus_send_reply(conn, control->connect,
- DBUS_TYPE_INVALID);
- dbus_message_unref(control->connect);
+ pending_request_free(dev, control->connect, 0);
control->connect = NULL;
}
return reply;
}
-static DBusMessage *control_connect(DBusConnection *conn, DBusMessage *msg,
- void *data)
+int control_connect(struct audio_device *dev, audio_device_cb cb, void *data)
{
- struct audio_device *device = data;
- struct control *control = device->control;
+ struct control *control = dev->control;
+ struct pending_request *pending;
if (control->session)
- return btd_error_already_connected(msg);
+ return -EALREADY;
if (!control->target)
- return btd_error_not_supported(msg);
+ return -ENOTSUP;
if (control->connect)
- return btd_error_in_progress(msg);
+ return -EINPROGRESS;
- control->session = avctp_connect(&device->src, &device->dst);
+ control->session = avctp_connect(&dev->src, &dev->dst);
if (!control->session)
- return btd_error_failed(msg, "Unable to connect");
+ return -EIO;
- control->connect = dbus_message_ref(msg);
+ pending = g_new0(struct pending_request, 1);
+ pending->cb = cb;
+ pending->data = data;
+ control->connect = pending;
- return NULL;
+ return 0;
}
-static DBusMessage *control_disconnect(DBusConnection *conn, DBusMessage *msg,
+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_control(DBusConnection *conn, DBusMessage *msg,
void *data)
{
struct audio_device *device = data;
- struct control *control = device->control;
+ int err;
+
+ err = control_connect(device, generic_cb, msg);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ dbus_message_ref(msg);
+
+ return NULL;
+}
+
+int control_disconnect(struct audio_device *dev, audio_device_cb cb,
+ void *data)
+{
+ struct control *control = dev->control;
if (!control->session)
- return btd_error_not_connected(msg);
+ return -ENOTCONN;
+
+ /* cancel pending connect */
+ if (control->connect) {
+ pending_request_free(dev, control->connect, -ECANCELED);
+ control->connect = NULL;
+ }
avctp_disconnect(control->session);
+ if (cb)
+ cb(dev, 0, data);
+
+ return 0;
+
+}
+
+static DBusMessage *disconnect_control(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct audio_device *device = data;
+ int err;
+
+ err = control_disconnect(device, NULL, NULL);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
return dbus_message_new_method_return(msg);
}
{ GDBUS_DEPRECATED_METHOD("IsConnected",
NULL, GDBUS_ARGS({ "connected", "b" }),
control_is_connected) },
- { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, control_connect) },
- { GDBUS_METHOD("Disconnect", NULL, NULL, control_disconnect) },
+ { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, connect_control) },
+ { GDBUS_METHOD("Disconnect", NULL, NULL, disconnect_control) },
{ GDBUS_METHOD("Play", NULL, NULL, control_play) },
{ GDBUS_METHOD("Pause", NULL, NULL, control_pause) },
{ GDBUS_METHOD("Stop", NULL, NULL, control_stop) },
avctp_disconnect(control->session);
if (control->connect)
- dbus_message_unref(control->connect);
+ pending_request_free(dev, control->connect, -ECANCELED);
g_free(control);
dev->control = NULL;