3
* BlueZ - Bluetooth protocol stack for Linux
5
* Copyright (C) 2006-2007 Nokia Corporation
6
* Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34
#include "../src/adapter.h"
35
#include "../src/dbus-common.h"
42
#include "transport.h"
46
#ifndef DBUS_TYPE_UNIX_FD
47
#define DBUS_TYPE_UNIX_FD -1
50
#define MEDIA_INTERFACE "org.bluez.Media"
51
#define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint"
53
#define REQUEST_TIMEOUT (3 * 1000) /* 3 seconds */
55
struct media_adapter {
56
bdaddr_t src; /* Adapter address */
57
char *path; /* Adapter path */
58
DBusConnection *conn; /* Adapter connection */
59
GSList *endpoints; /* Endpoints list */
62
struct endpoint_request {
64
DBusPendingCall *call;
65
media_endpoint_cb_t cb;
69
struct media_endpoint {
71
char *sender; /* Endpoint DBus bus id */
72
char *path; /* Endpoint object path */
73
char *uuid; /* Endpoint property UUID */
74
uint8_t codec; /* Endpoint codec */
75
uint8_t *capabilities; /* Endpoint property capabilities */
76
size_t size; /* Endpoint capabilities size */
79
struct endpoint_request *request;
80
struct media_transport *transport;
81
struct media_adapter *adapter;
84
static GSList *adapters = NULL;
86
static void endpoint_request_free(struct endpoint_request *request)
89
dbus_pending_call_cancel(request->call);
91
dbus_message_unref(request->msg);
95
static void media_endpoint_remove(struct media_endpoint *endpoint)
97
struct media_adapter *adapter = endpoint->adapter;
99
info("Endpoint unregistered: sender=%s path=%s", endpoint->sender,
102
adapter->endpoints = g_slist_remove(adapter->endpoints, endpoint);
105
a2dp_remove_sep(endpoint->sep);
107
if (endpoint->hs_watch)
108
headset_remove_state_cb(endpoint->hs_watch);
110
if (endpoint->request)
111
endpoint_request_free(endpoint->request);
113
if (endpoint->transport)
114
media_transport_remove(endpoint->transport);
116
g_dbus_remove_watch(adapter->conn, endpoint->watch);
117
g_free(endpoint->capabilities);
118
g_free(endpoint->sender);
119
g_free(endpoint->path);
120
g_free(endpoint->uuid);
124
static void media_endpoint_exit(DBusConnection *connection, void *user_data)
126
struct media_endpoint *endpoint = user_data;
129
media_endpoint_remove(endpoint);
132
static void headset_setconf_cb(struct media_endpoint *endpoint, void *ret,
133
int size, void *user_data)
135
struct audio_device *dev = user_data;
140
headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
143
static void headset_state_changed(struct audio_device *dev,
144
headset_state_t old_state,
145
headset_state_t new_state,
148
struct media_endpoint *endpoint = user_data;
153
case HEADSET_STATE_DISCONNECTED:
154
if (old_state != HEADSET_STATE_CONNECTING)
155
media_endpoint_clear_configuration(endpoint);
156
case HEADSET_STATE_CONNECTING:
158
case HEADSET_STATE_CONNECTED:
159
if (old_state != HEADSET_STATE_PLAY_IN_PROGRESS &&
160
old_state != HEADSET_STATE_PLAYING)
161
media_endpoint_set_configuration(endpoint, dev, NULL,
162
0, headset_setconf_cb,
165
case HEADSET_STATE_PLAY_IN_PROGRESS:
167
case HEADSET_STATE_PLAYING:
172
static struct media_endpoint *media_endpoint_create(struct media_adapter *adapter,
176
gboolean delay_reporting,
178
uint8_t *capabilities,
181
struct media_endpoint *endpoint;
183
endpoint = g_new0(struct media_endpoint, 1);
184
endpoint->sender = g_strdup(sender);
185
endpoint->path = g_strdup(path);
186
endpoint->uuid = g_strdup(uuid);
187
endpoint->codec = codec;
188
endpoint->capabilities = g_new(uint8_t, size);
189
memcpy(endpoint->capabilities, capabilities, size);
190
endpoint->size = size;
191
endpoint->adapter = adapter;
193
if (strcasecmp(uuid, A2DP_SOURCE_UUID) == 0) {
194
endpoint->sep = a2dp_add_sep(&adapter->src,
195
AVDTP_SEP_TYPE_SOURCE, codec,
196
delay_reporting, endpoint);
197
if (endpoint->sep == NULL)
199
} else if (strcasecmp(uuid, A2DP_SINK_UUID) == 0) {
200
endpoint->sep = a2dp_add_sep(&adapter->src,
201
AVDTP_SEP_TYPE_SINK, codec,
202
delay_reporting, endpoint);
203
if (endpoint->sep == NULL)
205
} else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
206
g_strcmp0(uuid, HSP_AG_UUID) == 0)
207
endpoint->hs_watch = headset_add_state_cb(headset_state_changed,
212
endpoint->watch = g_dbus_add_disconnect_watch(adapter->conn, sender,
213
media_endpoint_exit, endpoint,
216
adapter->endpoints = g_slist_append(adapter->endpoints, endpoint);
217
info("Endpoint registered: sender=%s path=%s", sender, path);
226
static struct media_endpoint *media_adapter_find_endpoint(
227
struct media_adapter *adapter,
234
for (l = adapter->endpoints; l; l = l->next) {
235
struct media_endpoint *endpoint = l->data;
237
if (sender && g_strcmp0(endpoint->sender, sender) != 0)
240
if (path && g_strcmp0(endpoint->path, path) != 0)
243
if (uuid && g_strcmp0(endpoint->uuid, uuid) != 0)
252
const char *media_endpoint_get_sender(struct media_endpoint *endpoint)
254
return endpoint->sender;
257
static int parse_properties(DBusMessageIter *props, const char **uuid,
258
gboolean *delay_reporting, uint8_t *codec,
259
uint8_t **capabilities, int *size)
261
while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) {
263
DBusMessageIter value, entry;
266
dbus_message_iter_recurse(props, &entry);
267
dbus_message_iter_get_basic(&entry, &key);
269
dbus_message_iter_next(&entry);
270
dbus_message_iter_recurse(&entry, &value);
272
var = dbus_message_iter_get_arg_type(&value);
273
if (strcasecmp(key, "UUID") == 0) {
274
if (var != DBUS_TYPE_STRING)
276
dbus_message_iter_get_basic(&value, uuid);
277
} else if (strcasecmp(key, "Codec") == 0) {
278
if (var != DBUS_TYPE_BYTE)
280
dbus_message_iter_get_basic(&value, codec);
281
} else if (strcasecmp(key, "DelayReporting") == 0) {
282
if (var != DBUS_TYPE_BOOLEAN)
284
dbus_message_iter_get_basic(&value, delay_reporting);
285
} else if (strcasecmp(key, "Capabilities") == 0) {
286
DBusMessageIter array;
288
if (var != DBUS_TYPE_ARRAY)
291
dbus_message_iter_recurse(&value, &array);
292
dbus_message_iter_get_fixed_array(&array, capabilities,
296
dbus_message_iter_next(props);
302
static DBusMessage *register_endpoint(DBusConnection *conn, DBusMessage *msg,
305
struct media_adapter *adapter = data;
306
DBusMessageIter args, props;
307
const char *sender, *path, *uuid = NULL;
308
gboolean delay_reporting;
310
uint8_t *capabilities;
313
sender = dbus_message_get_sender(msg);
315
dbus_message_iter_init(msg, &args);
317
dbus_message_iter_get_basic(&args, &path);
318
dbus_message_iter_next(&args);
320
if (media_adapter_find_endpoint(adapter, sender, path, NULL) != NULL)
321
return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
322
"Endpoint already registered");
324
dbus_message_iter_recurse(&args, &props);
325
if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY)
326
return g_dbus_create_error(msg, ERROR_INTERFACE
327
".Failed", "Invalid argument");
329
if (parse_properties(&props, &uuid, &delay_reporting, &codec,
330
&capabilities, &size) || uuid == NULL)
331
return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
334
if (media_endpoint_create(adapter, sender, path, uuid, delay_reporting,
335
codec, capabilities, size) == FALSE)
336
return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
339
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
342
static DBusMessage *unregister_endpoint(DBusConnection *conn, DBusMessage *msg,
345
struct media_adapter *adapter = data;
346
struct media_endpoint *endpoint;
347
const char *sender, *path;
349
if (!dbus_message_get_args(msg, NULL,
350
DBUS_TYPE_OBJECT_PATH, &path,
354
sender = dbus_message_get_sender(msg);
356
endpoint = media_adapter_find_endpoint(adapter, sender, path, NULL);
357
if (endpoint == NULL)
358
return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
359
"Endpoint not registered");
361
media_endpoint_remove(endpoint);
363
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
366
static GDBusMethodTable media_methods[] = {
367
{ "RegisterEndpoint", "oa{sv}", "", register_endpoint },
368
{ "UnregisterEndpoint", "o", "", unregister_endpoint },
372
static void path_free(void *data)
374
struct media_adapter *adapter = data;
376
g_slist_foreach(adapter->endpoints, (GFunc) media_endpoint_release,
378
g_slist_free(adapter->endpoints);
380
dbus_connection_unref(adapter->conn);
382
adapters = g_slist_remove(adapters, adapter);
384
g_free(adapter->path);
388
int media_register(DBusConnection *conn, const char *path, const bdaddr_t *src)
390
struct media_adapter *adapter;
392
if (DBUS_TYPE_UNIX_FD < 0)
395
adapter = g_new0(struct media_adapter, 1);
396
adapter->conn = dbus_connection_ref(conn);
397
bacpy(&adapter->src, src);
398
adapter->path = g_strdup(path);
400
if (!g_dbus_register_interface(conn, path, MEDIA_INTERFACE,
401
media_methods, NULL, NULL,
402
adapter, path_free)) {
403
error("D-Bus failed to register %s path", path);
408
adapters = g_slist_append(adapters, adapter);
413
void media_unregister(const char *path)
417
for (l = adapters; l; l = l->next) {
418
struct media_adapter *adapter = l->data;
420
if (g_strcmp0(path, adapter->path) == 0) {
421
g_dbus_unregister_interface(adapter->conn, path,
428
size_t media_endpoint_get_capabilities(struct media_endpoint *endpoint,
429
uint8_t **capabilities)
431
*capabilities = endpoint->capabilities;
432
return endpoint->size;
435
static void endpoint_reply(DBusPendingCall *call, void *user_data)
437
struct media_endpoint *endpoint = user_data;
438
struct endpoint_request *request = endpoint->request;
445
/* steal_reply will always return non-NULL since the callback
446
* is only called after a reply has been received */
447
reply = dbus_pending_call_steal_reply(call);
449
dbus_error_init(&err);
450
if (dbus_set_error_from_message(&err, reply)) {
451
error("Endpoint replied with an error: %s",
454
/* Clear endpoint configuration in case of NO_REPLY error */
455
if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
457
request->cb(endpoint, NULL, size,
459
media_endpoint_clear_configuration(endpoint);
460
dbus_message_unref(reply);
461
dbus_error_free(&err);
465
dbus_error_free(&err);
469
dbus_error_init(&err);
470
if (dbus_message_is_method_call(request->msg, MEDIA_ENDPOINT_INTERFACE,
471
"SelectConfiguration")) {
472
DBusMessageIter args, array;
473
uint8_t *configuration;
475
dbus_message_iter_init(reply, &args);
477
dbus_message_iter_recurse(&args, &array);
479
dbus_message_iter_get_fixed_array(&array, &configuration, &size);
483
} else if (!dbus_message_get_args(reply, &err, DBUS_TYPE_INVALID)) {
484
error("Wrong reply signature: %s", err.message);
485
dbus_error_free(&err);
494
dbus_message_unref(reply);
497
request->cb(endpoint, ret, size, request->user_data);
499
endpoint_request_free(request);
500
endpoint->request = NULL;
503
static gboolean media_endpoint_async_call(DBusConnection *conn,
505
struct media_endpoint *endpoint,
506
media_endpoint_cb_t cb,
509
struct endpoint_request *request;
511
if (endpoint->request)
514
request = g_new0(struct endpoint_request, 1);
516
/* Timeout should be less than avdtp request timeout (4 seconds) */
517
if (dbus_connection_send_with_reply(conn, msg, &request->call,
518
REQUEST_TIMEOUT) == FALSE) {
519
error("D-Bus send failed");
524
dbus_pending_call_set_notify(request->call, endpoint_reply, endpoint, NULL);
528
request->user_data = user_data;
529
endpoint->request = request;
531
DBG("Calling %s: name = %s path = %s", dbus_message_get_member(msg),
532
dbus_message_get_destination(msg),
533
dbus_message_get_path(msg));
538
gboolean media_endpoint_set_configuration(struct media_endpoint *endpoint,
539
struct audio_device *device,
540
uint8_t *configuration, size_t size,
541
media_endpoint_cb_t cb,
544
DBusConnection *conn;
547
DBusMessageIter iter;
549
if (endpoint->transport != NULL || endpoint->request != NULL)
552
conn = endpoint->adapter->conn;
554
endpoint->transport = media_transport_create(conn, endpoint, device,
555
configuration, size);
556
if (endpoint->transport == NULL)
559
msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
560
MEDIA_ENDPOINT_INTERFACE,
563
error("Couldn't allocate D-Bus message");
567
dbus_message_iter_init_append(msg, &iter);
569
path = media_transport_get_path(endpoint->transport);
570
dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
572
transport_get_properties(endpoint->transport, &iter);
574
return media_endpoint_async_call(conn, msg, endpoint, cb, user_data);
577
gboolean media_endpoint_select_configuration(struct media_endpoint *endpoint,
578
uint8_t *capabilities,
580
media_endpoint_cb_t cb,
583
DBusConnection *conn;
586
if (endpoint->request != NULL)
589
conn = endpoint->adapter->conn;
591
msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
592
MEDIA_ENDPOINT_INTERFACE,
593
"SelectConfiguration");
595
error("Couldn't allocate D-Bus message");
599
dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
600
&capabilities, length,
603
return media_endpoint_async_call(conn, msg, endpoint, cb, user_data);
606
void media_endpoint_clear_configuration(struct media_endpoint *endpoint)
608
DBusConnection *conn;
612
if (endpoint->transport == NULL)
615
if (endpoint->request) {
616
endpoint_request_free(endpoint->request);
617
endpoint->request = NULL;
620
conn = endpoint->adapter->conn;
622
msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
623
MEDIA_ENDPOINT_INTERFACE,
624
"ClearConfiguration");
626
error("Couldn't allocate D-Bus message");
630
path = media_transport_get_path(endpoint->transport);
631
dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
633
g_dbus_send_message(conn, msg);
635
media_transport_remove(endpoint->transport);
636
endpoint->transport = NULL;
639
void media_endpoint_release(struct media_endpoint *endpoint)
643
DBG("sender=%s path=%s", endpoint->sender, endpoint->path);
646
if (endpoint->watch == 0)
649
msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
650
MEDIA_ENDPOINT_INTERFACE,
653
error("Couldn't allocate D-Bus message");
657
g_dbus_send_message(endpoint->adapter->conn, msg);
659
media_endpoint_remove(endpoint);
662
struct a2dp_sep *media_endpoint_get_sep(struct media_endpoint *endpoint)
664
return endpoint->sep;
667
const char *media_endpoint_get_uuid(struct media_endpoint *endpoint)
669
return endpoint->uuid;
672
uint8_t media_endpoint_get_codec(struct media_endpoint *endpoint)
674
return endpoint->codec;
677
struct media_transport *media_endpoint_get_transport(
678
struct media_endpoint *endpoint)
680
return endpoint->transport;