diff --git a/audio/transport.c b/audio/transport.c
index 9961684..9a8fc22 100644
--- a/audio/transport.c
+++ b/audio/transport.c
#define MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport"
-struct acquire_request {
+struct media_request {
DBusMessage *msg;
guint id;
struct media_owner *owner;
struct media_owner {
struct media_transport *transport;
- struct acquire_request *request;
+ struct media_request *pending;
char *name;
char *accesstype;
guint watch;
gboolean in_use;
guint (*resume) (struct media_transport *transport,
struct media_owner *owner);
- void (*suspend) (struct media_transport *transport);
+ guint (*suspend) (struct media_transport *transport,
+ struct media_owner *owner);
void (*cancel) (struct media_transport *transport,
guint id);
void (*get_properties) (
g_free(path);
}
-static void acquire_request_free(struct acquire_request *req)
+static struct media_request *media_request_new(struct media_owner *owner,
+ DBusMessage *msg)
+{
+ struct media_request *req;
+
+ req = g_new0(struct media_request, 1);
+ req->msg = dbus_message_ref(msg);
+ req->owner = owner;
+ owner->pending = req;
+
+ return req;
+}
+
+static void media_request_free(struct media_request *req)
{
struct media_owner *owner = req->owner;
struct media_transport *transport = owner->transport;
if (req->msg)
dbus_message_unref(req->msg);
- owner->request = NULL;
+ owner->pending = NULL;
g_free(req);
}
+static void media_request_reply(struct media_request *req, int err)
+{
+ struct media_owner *owner = req->owner;
+ struct media_transport *transport = owner->transport;
+ DBusMessage *reply;
+
+ if (!err)
+ reply = g_dbus_create_reply(req->msg, DBUS_TYPE_INVALID);
+ else
+ reply = g_dbus_create_error(owner->pending->msg,
+ ERROR_INTERFACE ".Failed",
+ "%s", strerror(err));
+
+ g_dbus_send_message(transport->conn, reply);
+}
+
static gboolean media_transport_release(struct media_transport *transport,
const char *accesstype)
{
if (owner->watch)
g_dbus_remove_watch(transport->conn, owner->watch);
- if (owner->request) {
- DBusMessage *reply = g_dbus_create_error(owner->request->msg,
- ERROR_INTERFACE ".Failed",
- "%s", strerror(EIO));
-
- g_dbus_send_message(transport->conn, reply);
-
- acquire_request_free(owner->request);
- }
+ if (owner->pending)
+ media_request_free(owner->pending);
transport->owners = g_slist_remove(transport->owners, owner);
- /* Suspend if the is no longer any owner */
- if (transport->owners == NULL)
- transport->suspend(transport);
+ /* Suspend if there is no longer any owner */
+ if (transport->owners == NULL && transport->in_use)
+ transport->suspend(transport, NULL);
DBG("Owner removed: sender=%s accesstype=%s", owner->name,
owner->accesstype);
struct avdtp_error *err, void *user_data)
{
struct media_owner *owner = user_data;
- struct acquire_request *req = owner->request;
+ struct media_request *req = owner->pending;
struct media_transport *transport = owner->transport;
struct a2dp_sep *sep = media_endpoint_get_sep(transport->endpoint);
struct avdtp_stream *stream;
if (ret == FALSE)
goto fail;
+ media_request_free(req);
+
return;
fail:
owner);
}
-static void suspend_a2dp(struct media_transport *transport)
+static void a2dp_suspend_complete(struct avdtp *session,
+ struct avdtp_error *err, void *user_data)
{
- struct media_endpoint *endpoint = transport->endpoint;
- struct a2dp_sep *sep = media_endpoint_get_sep(endpoint);
+ struct media_owner *owner = user_data;
+ struct media_transport *transport = owner->transport;
+ struct a2dp_sep *sep = media_endpoint_get_sep(transport->endpoint);
+
+ /* Release always succeeds */
+ if (owner->pending) {
+ owner->pending->id = 0;
+ media_request_reply(owner->pending, 0);
+ }
a2dp_sep_unlock(sep, transport->session);
transport->in_use = FALSE;
+ media_owner_remove(owner);
+}
+
+static guint suspend_a2dp(struct media_transport *transport,
+ struct media_owner *owner)
+{
+ struct media_endpoint *endpoint = transport->endpoint;
+ struct a2dp_sep *sep = media_endpoint_get_sep(endpoint);
+
+ if (!owner) {
+ a2dp_sep_unlock(sep, transport->session);
+ transport->in_use = FALSE;
+ return 0;
+ }
+
+ return a2dp_suspend(transport->session, sep, a2dp_suspend_complete,
+ owner);
}
static void cancel_a2dp(struct media_transport *transport, guint id)
static void headset_resume_complete(struct audio_device *dev, void *user_data)
{
struct media_owner *owner = user_data;
- struct acquire_request *req = owner->request;
+ struct media_request *req = owner->pending;
struct media_transport *transport = owner->transport;
int fd;
uint16_t imtu, omtu;
if (ret == FALSE)
goto fail;
+ media_request_free(req);
+
return;
fail:
owner);
}
-static void suspend_headset(struct media_transport *transport)
+static void headset_suspend_complete(struct audio_device *dev, void *user_data)
{
- struct audio_device *device = transport->device;
+ struct media_owner *owner = user_data;
+ struct media_transport *transport = owner->transport;
+
+ /* Release always succeeds */
+ if (owner->pending) {
+ owner->pending->id = 0;
+ media_request_reply(owner->pending, 0);
+ }
- headset_unlock(device, HEADSET_LOCK_READ | HEADSET_LOCK_WRITE);
+ headset_unlock(dev, HEADSET_LOCK_READ | HEADSET_LOCK_WRITE);
transport->in_use = FALSE;
+ media_owner_remove(owner);
+}
+
+static guint suspend_headset(struct media_transport *transport,
+ struct media_owner *owner)
+{
+ struct audio_device *device = transport->device;
+
+ if (!owner) {
+ headset_unlock(device, HEADSET_LOCK_READ | HEADSET_LOCK_WRITE);
+ transport->in_use = FALSE;
+ return 0;
+ }
+
+ return headset_suspend_stream(device, headset_suspend_complete, owner);
}
static void cancel_headset(struct media_transport *transport, guint id)
struct media_owner *owner = user_data;
owner->watch = 0;
- if (owner->request != NULL)
- acquire_request_free(owner->request);
+
+ if (owner->pending != NULL)
+ media_request_free(owner->pending);
media_owner_remove(owner);
}
{
struct media_transport *transport = data;
struct media_owner *owner;
- struct acquire_request *req;
+ struct media_request *req;
const char *accesstype, *sender;
if (!dbus_message_get_args(msg, NULL,
return btd_error_not_authorized(msg);
owner = media_owner_create(transport, msg, accesstype);
- req = g_new0(struct acquire_request, 1);
- req->msg = dbus_message_ref(msg);
- req->owner = owner;
+ req = media_request_new(owner, msg);
req->id = transport->resume(transport, owner);
- owner->request = req;
if (req->id == 0)
media_owner_remove(owner);
struct media_transport *transport = data;
struct media_owner *owner;
const char *accesstype, *sender;
+ struct media_request *req;
if (!dbus_message_get_args(msg, NULL,
DBUS_TYPE_STRING, &accesstype,
if (owner == NULL)
return btd_error_not_authorized(msg);
- if (g_strcmp0(owner->accesstype, accesstype) == 0)
- media_owner_remove(owner);
- else if (g_strstr_len(owner->accesstype, -1, accesstype) != NULL) {
+ if (g_strcmp0(owner->accesstype, accesstype) == 0) {
+ /* Not the last owner, no need to suspend */
+ if (g_slist_length(transport->owners) != 1) {
+ media_owner_remove(owner);
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ }
+
+ if (owner->pending) {
+ const char *member;
+
+ member = dbus_message_get_member(owner->pending->msg);
+ /* Cancel Acquire request if that exist */
+ if (g_str_equal(member, "Acquire"))
+ media_request_free(owner->pending);
+ else
+ return btd_error_in_progress(msg);
+ }
+
+ req = media_request_new(owner, msg);
+ req->id = transport->suspend(transport, owner);
+ if (req->id == 0)
+ media_owner_remove(owner);
+
+ return NULL;
+ } else if (g_strstr_len(owner->accesstype, -1, accesstype) != NULL) {
media_transport_release(transport, accesstype);
g_strdelimit(owner->accesstype, accesstype, ' ');
} else
{ "GetProperties", "", "a{sv}", get_properties },
{ "Acquire", "s", "h", acquire,
G_DBUS_METHOD_FLAG_ASYNC},
- { "Release", "s", "", release },
+ { "Release", "s", "", release,
+ G_DBUS_METHOD_FLAG_ASYNC},
{ "SetProperty", "sv", "", set_property },
{ },
};