aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikel Astiz <mikel.astiz@bmw-carit.de>2012-05-04 15:14:37 +0200
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2012-05-07 07:05:39 -0700
commit06da2b022802e8dbd47f6180e5d852beba5c0e5d (patch)
treedf131c2d662354b3b3834a00198d23917813cff0
parentee14d62aba5dccd6d9108f7e4f944188c43fb1a3 (diff)
downloadbluez-06da2b022802e8dbd47f6180e5d852beba5c0e5d.tar.gz
bluez-06da2b022802e8dbd47f6180e5d852beba5c0e5d.tar.xz
bluez-06da2b022802e8dbd47f6180e5d852beba5c0e5d.zip
media: Support multiple transports per endpoint
Several transports may exist for each endpoint, for example if several HFGW are connected. This should be exposed to the endpoint as one transport each.
-rw-r--r--audio/media.c98
1 files changed, 65 insertions, 33 deletions
diff --git a/audio/media.c b/audio/media.c
index c0fd0c32..fd5a3696 100644
--- a/audio/media.c
+++ b/audio/media.c
@@ -86,8 +86,8 @@ struct media_endpoint {
guint ag_watch;
guint watch;
struct endpoint_request *request;
- struct media_transport *transport;
struct media_adapter *adapter;
+ GSList *transports;
};
struct media_player {
@@ -153,8 +153,8 @@ static void media_endpoint_destroy(struct media_endpoint *endpoint)
if (endpoint->request)
media_endpoint_cancel(endpoint);
- if (endpoint->transport)
- media_transport_destroy(endpoint->transport);
+ g_slist_free_full(endpoint->transports,
+ (GDestroyNotify) media_transport_destroy);
g_dbus_remove_watch(adapter->conn, endpoint->watch);
g_free(endpoint->capabilities);
@@ -200,18 +200,12 @@ static void headset_setconf_cb(struct media_endpoint *endpoint, void *ret,
headset_shutdown(dev);
}
-static void clear_configuration(struct media_endpoint *endpoint)
+static void clear_configuration(struct media_endpoint *endpoint,
+ struct media_transport *transport)
{
DBusConnection *conn;
DBusMessage *msg;
const char *path;
- struct media_transport *transport = endpoint->transport;
-
- if (endpoint->transport == NULL)
- return;
-
- if (endpoint->request)
- media_endpoint_cancel(endpoint);
conn = endpoint->adapter->conn;
@@ -223,15 +217,24 @@ static void clear_configuration(struct media_endpoint *endpoint)
goto done;
}
- path = media_transport_get_path(endpoint->transport);
+ path = media_transport_get_path(transport);
dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
g_dbus_send_message(conn, msg);
done:
- endpoint->transport = NULL;
+ endpoint->transports = g_slist_remove(endpoint->transports, transport);
media_transport_destroy(transport);
}
+static void clear_endpoint(struct media_endpoint *endpoint)
+{
+ if (endpoint->request)
+ media_endpoint_cancel(endpoint);
+
+ while (endpoint->transports != NULL)
+ clear_configuration(endpoint, endpoint->transports->data);
+}
+
static void endpoint_reply(DBusPendingCall *call, void *user_data)
{
struct media_endpoint *endpoint = user_data;
@@ -256,7 +259,7 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data)
if (request->cb)
request->cb(endpoint, NULL, size,
request->user_data);
- clear_configuration(endpoint);
+ clear_endpoint(endpoint);
dbus_message_unref(reply);
dbus_error_free(&err);
return;
@@ -369,6 +372,31 @@ static gboolean select_configuration(struct media_endpoint *endpoint,
destroy);
}
+static gint transport_device_cmp(gconstpointer data, gconstpointer user_data)
+{
+ struct media_transport *transport = (struct media_transport *) data;
+ const struct audio_device *device = user_data;
+
+ if (device == media_transport_get_dev(transport))
+ return 0;
+
+ return -1;
+}
+
+static struct media_transport *find_device_transport(
+ struct media_endpoint *endpoint,
+ struct audio_device *device)
+{
+ GSList *match;
+
+ match = g_slist_find_custom(endpoint->transports, device,
+ transport_device_cmp);
+ if (match == NULL)
+ return NULL;
+
+ return match->data;
+}
+
static gboolean set_configuration(struct media_endpoint *endpoint,
struct audio_device *device,
uint8_t *configuration, size_t size,
@@ -380,15 +408,18 @@ static gboolean set_configuration(struct media_endpoint *endpoint,
DBusMessage *msg;
const char *path;
DBusMessageIter iter;
+ struct media_transport *transport;
+
+ transport = find_device_transport(endpoint, device);
- if (endpoint->transport != NULL || endpoint->request != NULL)
+ if (transport != NULL || endpoint->request != NULL)
return FALSE;
conn = endpoint->adapter->conn;
- endpoint->transport = media_transport_create(conn, endpoint, device,
+ transport = media_transport_create(conn, endpoint, device,
configuration, size);
- if (endpoint->transport == NULL)
+ if (transport == NULL)
return FALSE;
msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
@@ -396,15 +427,18 @@ static gboolean set_configuration(struct media_endpoint *endpoint,
"SetConfiguration");
if (msg == NULL) {
error("Couldn't allocate D-Bus message");
+ media_transport_destroy(transport);
return FALSE;
}
+ endpoint->transports = g_slist_append(endpoint->transports, transport);
+
dbus_message_iter_init_append(msg, &iter);
- path = media_transport_get_path(endpoint->transport);
+ path = media_transport_get_path(transport);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
- transport_get_properties(endpoint->transport, &iter);
+ transport_get_properties(transport, &iter);
return media_endpoint_async_call(conn, msg, endpoint, cb, user_data,
destroy);
@@ -440,16 +474,17 @@ static void headset_state_changed(struct audio_device *dev,
void *user_data)
{
struct media_endpoint *endpoint = user_data;
+ struct media_transport *transport;
DBG("");
switch (new_state) {
case HEADSET_STATE_DISCONNECTED:
- if (endpoint->transport &&
- media_transport_get_dev(endpoint->transport) == dev) {
+ transport = find_device_transport(endpoint, dev);
+ if (transport != NULL) {
DBG("Clear endpoint %p", endpoint);
- clear_configuration(endpoint);
+ clear_configuration(endpoint, transport);
}
break;
case HEADSET_STATE_CONNECTING:
@@ -551,17 +586,17 @@ static void clear_config(struct a2dp_sep *sep, void *user_data)
{
struct media_endpoint *endpoint = user_data;
- clear_configuration(endpoint);
+ clear_endpoint(endpoint);
}
static void set_delay(struct a2dp_sep *sep, uint16_t delay, void *user_data)
{
struct media_endpoint *endpoint = user_data;
- if (endpoint->transport == NULL)
+ if (endpoint->transports == NULL)
return;
- media_transport_update_delay(endpoint->transport, delay);
+ media_transport_update_delay(endpoint->transports->data, delay);
}
static struct a2dp_endpoint a2dp_endpoint = {
@@ -577,10 +612,7 @@ static void a2dp_destroy_endpoint(void *user_data)
{
struct media_endpoint *endpoint = user_data;
- if (endpoint->transport) {
- media_transport_destroy(endpoint->transport);
- endpoint->transport = NULL;
- }
+ clear_endpoint(endpoint);
endpoint->sep = NULL;
release_endpoint(endpoint);
@@ -603,16 +635,16 @@ static void gateway_state_changed(struct audio_device *dev,
void *user_data)
{
struct media_endpoint *endpoint = user_data;
+ struct media_transport *transport;
DBG("");
switch (new_state) {
case GATEWAY_STATE_DISCONNECTED:
- if (endpoint->transport &&
- media_transport_get_dev(endpoint->transport) == dev) {
-
+ transport = find_device_transport(endpoint, dev);
+ if (transport != NULL) {
DBG("Clear endpoint %p", endpoint);
- clear_configuration(endpoint);
+ clear_configuration(endpoint, transport);
}
break;
case GATEWAY_STATE_CONNECTING: