device.c revision dad4c62b54ab078c1d5525e80be9c6391ea1731a
1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2007 Marcel Holtmann <marcel@holtmann.org> 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24#ifdef HAVE_CONFIG_H 25#include <config.h> 26#endif 27 28#include <stdio.h> 29#include <errno.h> 30#include <unistd.h> 31#include <sys/stat.h> 32#include <netinet/in.h> 33 34#include <glib.h> 35#include <dbus/dbus.h> 36 37#include <bluetooth/bluetooth.h> 38#include <bluetooth/hci.h> 39#include <bluetooth/hci_lib.h> 40#include <bluetooth/sdp.h> 41#include <bluetooth/sdp_lib.h> 42 43#include "dbus.h" 44#include "dbus-helper.h" 45#include "logging.h" 46#include "textfile.h" 47 48#include "error.h" 49#include "ipc.h" 50#include "device.h" 51#include "avdtp.h" 52#include "headset.h" 53#include "sink.h" 54 55static DBusHandlerResult device_get_address(DBusConnection *conn, 56 DBusMessage *msg, void *data) 57{ 58 struct device *device = data; 59 DBusMessage *reply; 60 char address[18], *ptr = address; 61 62 reply = dbus_message_new_method_return(msg); 63 if (!reply) 64 return DBUS_HANDLER_RESULT_NEED_MEMORY; 65 66 ba2str(&device->dst, address); 67 68 dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr, 69 DBUS_TYPE_INVALID); 70 71 return send_message_and_unref(conn, reply); 72} 73 74static DBusHandlerResult device_get_name(DBusConnection *conn, 75 DBusMessage *msg, void *data) 76{ 77 struct device *device = data; 78 DBusMessage *reply, *reply2, *msg2; 79 DBusError derr; 80 const char *name; 81 char address[18], *addr_ptr = address; 82 83 msg2 = dbus_message_new_method_call("org.bluez", device->adapter_path, 84 "org.bluez.Adapter", "GetRemoteName"); 85 if (!msg2) 86 return DBUS_HANDLER_RESULT_NEED_MEMORY; 87 88 ba2str(&device->dst, address); 89 dbus_message_append_args(msg2, DBUS_TYPE_STRING, &addr_ptr, 90 DBUS_TYPE_INVALID); 91 92 dbus_error_init(&derr); 93 reply2 = dbus_connection_send_with_reply_and_block(conn, msg2, -1, 94 &derr); 95 96 dbus_message_unref(msg2); 97 98 if (dbus_error_is_set(&derr)) { 99 error("%s GetRemoteName(): %s", device->adapter_path, 100 derr.message); 101 dbus_error_free(&derr); 102 return err_failed(conn, msg, "Unable to get remote name"); 103 } 104 105 106 reply = dbus_message_new_method_return(msg); 107 if (!reply) 108 return DBUS_HANDLER_RESULT_NEED_MEMORY; 109 110 dbus_message_get_args(reply2, NULL, 111 DBUS_TYPE_STRING, &name, 112 DBUS_TYPE_INVALID); 113 114 dbus_message_append_args(reply, DBUS_TYPE_STRING, &name, 115 DBUS_TYPE_INVALID); 116 117 dbus_message_unref(reply2); 118 119 return send_message_and_unref(conn, reply); 120} 121 122static DBusHandlerResult device_get_connected(DBusConnection *conn, 123 DBusMessage *msg, void *data) 124{ 125 DBusMessageIter iter, array_iter; 126 struct device *device = data; 127 DBusMessage *reply; 128 const char *iface; 129 130 reply = dbus_message_new_method_return(msg); 131 if (!reply) 132 return DBUS_HANDLER_RESULT_NEED_MEMORY; 133 134 dbus_message_iter_init_append(reply, &iter); 135 136 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 137 DBUS_TYPE_STRING_AS_STRING, 138 &array_iter); 139 140 if (device->headset && 141 headset_get_state(device) >= HEADSET_STATE_CONNECTED) { 142 iface = AUDIO_HEADSET_INTERFACE; 143 dbus_message_iter_append_basic(&array_iter, 144 DBUS_TYPE_STRING, &iface); 145 } 146 147 dbus_message_iter_close_container(&iter, &array_iter); 148 149 return send_message_and_unref(conn, reply); 150} 151 152static DBusMethodVTable device_methods[] = { 153 { "GetAddress", device_get_address, "", "s" }, 154 { "GetName", device_get_name, "", "s" }, 155 { "GetConnectedInterfaces", device_get_connected, "", "as" }, 156 { NULL, NULL, NULL, NULL } 157}; 158 159static void device_free(struct device *dev) 160{ 161 if (dev->headset) 162 headset_free(dev); 163 164 if (dev->sink) 165 sink_free(dev); 166 167 if (dev->conn) 168 dbus_connection_unref(dev->conn); 169 170 if (dev->adapter_path) 171 g_free(dev->adapter_path); 172 173 if (dev->path) 174 g_free(dev->path); 175 176 g_free(dev); 177} 178 179static void device_unregister(DBusConnection *conn, void *data) 180{ 181 struct device *device = data; 182 183 info("Unregistered device path:%s", device->path); 184 185 device_free(device); 186} 187 188char *find_adapter(DBusConnection *conn, bdaddr_t *src) 189{ 190 DBusMessage *msg, *reply; 191 DBusError derr; 192 char address[18], *addr_ptr = address; 193 char *path, *ret; 194 195 msg = dbus_message_new_method_call("org.bluez", "/org/bluez", 196 "org.bluez.Manager", 197 "FindAdapter"); 198 if (!msg) { 199 error("Unable to allocate new method call"); 200 return NULL; 201 } 202 203 ba2str(src, address); 204 205 dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, 206 DBUS_TYPE_INVALID); 207 208 dbus_error_init(&derr); 209 reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, 210 &derr); 211 212 dbus_message_unref(msg); 213 214 if (dbus_error_is_set(&derr) || 215 dbus_set_error_from_message(&derr, reply)) { 216 error("FindAdapter(%s) failed: %s", address, derr.message); 217 dbus_error_free(&derr); 218 return NULL; 219 } 220 221 dbus_error_init(&derr); 222 dbus_message_get_args(reply, &derr, 223 DBUS_TYPE_STRING, &path, 224 DBUS_TYPE_INVALID); 225 226 if (dbus_error_is_set(&derr)) { 227 error("Unable to get message args"); 228 dbus_message_unref(reply); 229 dbus_error_free(&derr); 230 return FALSE; 231 } 232 233 ret = g_strdup(path); 234 235 dbus_message_unref(reply); 236 237 debug("Got path %s for adapter with address %s", ret, address); 238 239 return ret; 240} 241 242struct device *device_register(DBusConnection *conn, 243 const char *path, bdaddr_t *bda) 244{ 245 struct device *dev; 246 bdaddr_t src; 247 int dev_id; 248 249 if (!conn || !path) 250 return NULL; 251 252 bacpy(&src, BDADDR_ANY); 253 dev_id = hci_get_route(&src); 254 if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0)) 255 return NULL; 256 257 dev = g_new0(struct device, 1); 258 259 dev->adapter_path = find_adapter(conn, &src); 260 if (!dev->adapter_path) { 261 device_free(dev); 262 return NULL; 263 } 264 265 if (!dbus_connection_create_object_path(conn, path, dev, 266 device_unregister)) { 267 error("D-Bus failed to register %s path", path); 268 device_free(dev); 269 return NULL; 270 } 271 272 if (!dbus_connection_register_interface(conn, path, 273 AUDIO_DEVICE_INTERFACE, device_methods, NULL, NULL)) { 274 error("Failed to register %s interface to %s", 275 AUDIO_DEVICE_INTERFACE, path); 276 dbus_connection_destroy_object_path(conn, path); 277 return NULL; 278 } 279 280 dev->path = g_strdup(path); 281 bacpy(&dev->dst, bda); 282 bacpy(&dev->src, &src); 283 dev->conn = dbus_connection_ref(conn); 284 285 return dev; 286} 287 288int device_store(struct device *dev, gboolean is_default) 289{ 290 char value[64]; 291 char filename[PATH_MAX + 1]; 292 char src_addr[18], dst_addr[18]; 293 int offset = 0; 294 295 if (!dev->path) 296 return -EINVAL; 297 298 ba2str(&dev->dst, dst_addr); 299 ba2str(&dev->src, src_addr); 300 301 create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio"); 302 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 303 304 if (is_default) 305 textfile_put(filename, "default", dst_addr); 306 if (dev->headset) { 307 snprintf(value, 64, "headset "); 308 offset += strlen("headset "); 309 } 310 if (dev->gateway) { 311 snprintf(value + offset, 64 - offset, "gateway "); 312 offset += strlen("gateway "); 313 } 314 if (dev->sink) { 315 snprintf(value + offset, 64 - offset, "sink "); 316 offset += strlen("sink "); 317 } 318 if (dev->source) { 319 snprintf(value + offset, 64 - offset, "source "); 320 offset += strlen("source "); 321 } 322 if (dev->control) { 323 snprintf(value + offset, 64 - offset, "control "); 324 offset += strlen("control "); 325 } 326 if (dev->target) 327 snprintf(value + offset, 64 - offset, "target"); 328 329 return textfile_put(filename, dst_addr, value); 330} 331 332int device_remove_stored(struct device *dev) 333{ 334 char filename[PATH_MAX + 1]; 335 char src_addr[18], dst_addr[18]; 336 337 ba2str(&dev->dst, dst_addr); 338 ba2str(&dev->src, src_addr); 339 340 create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio"); 341 342 return textfile_del(filename, dst_addr); 343} 344 345void device_finish_sdp_transaction(struct device *dev) 346{ 347 char address[18], *addr_ptr = address; 348 DBusMessage *msg, *reply; 349 DBusError derr; 350 351 ba2str(&dev->dst, address); 352 353 msg = dbus_message_new_method_call("org.bluez", dev->adapter_path, 354 "org.bluez.Adapter", 355 "FinishRemoteServiceTransaction"); 356 if (!msg) { 357 error("Unable to allocate new method call"); 358 return; 359 } 360 361 dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, 362 DBUS_TYPE_INVALID); 363 364 dbus_error_init(&derr); 365 reply = dbus_connection_send_with_reply_and_block(dev->conn, 366 msg, -1, &derr); 367 368 dbus_message_unref(msg); 369 370 if (dbus_error_is_set(&derr) || 371 dbus_set_error_from_message(&derr, reply)) { 372 error("FinishRemoteServiceTransaction(%s) failed: %s", 373 address, derr.message); 374 dbus_error_free(&derr); 375 return; 376 } 377 378 dbus_message_unref(reply); 379} 380 381#if 0 382static avdtp_state_t ipc_to_avdtp_state(uint8_t ipc_state) 383{ 384 switch (ipc_state) { 385 case STATE_DISCONNECTED: 386 return AVDTP_STATE_IDLE; 387 case STATE_CONNECTING: 388 return AVDTP_STATE_CONFIGURED; 389 case STATE_CONNECTED: 390 return AVDTP_STATE_OPEN; 391 case STATE_STREAM_STARTING: 392 case STATE_STREAMING: 393 return AVDTP_STATE_STREAMING; 394 default: 395 error("Unknown ipc state"); 396 return AVDTP_STATE_IDLE; 397 } 398} 399 400static headset_state_t ipc_to_hs_state(uint8_t ipc_state) 401{ 402 switch (ipc_state) { 403 case STATE_DISCONNECTED: 404 return HEADSET_STATE_DISCONNECTED; 405 case STATE_CONNECTING: 406 return HEADSET_STATE_CONNECT_IN_PROGRESS; 407 case STATE_CONNECTED: 408 return HEADSET_STATE_CONNECTED; 409 case STATE_STREAM_STARTING: 410 return HEADSET_STATE_PLAY_IN_PROGRESS; 411 case STATE_STREAMING: 412 return HEADSET_STATE_PLAYING; 413 default: 414 error("Unknown ipc state"); 415 return HEADSET_STATE_DISCONNECTED; 416 } 417} 418#endif 419 420static uint8_t avdtp_to_ipc_state(avdtp_state_t state) 421{ 422 switch (state) { 423 case AVDTP_STATE_IDLE: 424 return STATE_DISCONNECTED; 425 case AVDTP_STATE_CONFIGURED: 426 return STATE_CONNECTING; 427 case AVDTP_STATE_OPEN: 428 return STATE_CONNECTED; 429 case AVDTP_STATE_STREAMING: 430 return STATE_STREAMING; 431 default: 432 error("Unknown avdt state"); 433 return AVDTP_STATE_IDLE; 434 } 435} 436 437static uint8_t hs_to_ipc_state(headset_state_t state) 438{ 439 switch (state) { 440 case HEADSET_STATE_DISCONNECTED: 441 return STATE_DISCONNECTED; 442 case HEADSET_STATE_CONNECT_IN_PROGRESS: 443 return STATE_CONNECTING; 444 case HEADSET_STATE_CONNECTED: 445 return STATE_CONNECTED; 446 case HEADSET_STATE_PLAY_IN_PROGRESS: 447 return STATE_STREAMING; 448 default: 449 error("Unknown headset state"); 450 return AVDTP_STATE_IDLE; 451 } 452} 453 454uint8_t device_get_state(struct device *dev) 455{ 456 avdtp_state_t sink_state; 457 headset_state_t hs_state; 458 459 if (dev->sink && sink_is_active(dev)) { 460 sink_state = sink_get_state(dev); 461 return avdtp_to_ipc_state(sink_state); 462 } 463 else if (dev->headset && headset_is_active(dev)) { 464 hs_state = headset_get_state(dev); 465 return hs_to_ipc_state(hs_state); 466 } 467 468 return STATE_DISCONNECTED; 469} 470 471gboolean device_is_connected(struct device *dev, const char *interface) 472{ 473 if (!interface) { 474 if ((dev->sink || dev->source) && 475 avdtp_is_connected(&dev->src, &dev->dst)) 476 return TRUE; 477 478 if (dev->headset && headset_is_active(dev)) 479 return TRUE; 480 } 481 else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink && 482 avdtp_is_connected(&dev->src, &dev->dst)) 483 return TRUE; 484 else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source && 485 avdtp_is_connected(&dev->src, &dev->dst)) 486 return TRUE; 487 else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset && 488 headset_is_active(dev)) 489 return TRUE; 490 491 return FALSE; 492} 493