device.c revision 0094809955895c974fbe95f2d3ed13f420a6a6ed
1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2006-2007 Nokia Corporation 6 * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org> 7 * 8 * 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. 13 * 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. 18 * 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 22 * 23 */ 24 25#ifdef HAVE_CONFIG_H 26#include <config.h> 27#endif 28 29#include <stdio.h> 30#include <errno.h> 31#include <unistd.h> 32#include <sys/stat.h> 33#include <netinet/in.h> 34 35#include <bluetooth/bluetooth.h> 36#include <bluetooth/hci.h> 37#include <bluetooth/hci_lib.h> 38#include <bluetooth/sdp.h> 39#include <bluetooth/sdp_lib.h> 40 41#include <glib.h> 42#include <dbus/dbus.h> 43#include <gdbus.h> 44 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 "control.h" 53#include "headset.h" 54#include "sink.h" 55 56static DBusHandlerResult device_get_address(DBusConnection *conn, 57 DBusMessage *msg, void *data) 58{ 59 struct device *device = data; 60 DBusMessage *reply; 61 char address[18], *ptr = address; 62 63 reply = dbus_message_new_method_return(msg); 64 if (!reply) 65 return DBUS_HANDLER_RESULT_NEED_MEMORY; 66 67 ba2str(&device->dst, address); 68 69 dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr, 70 DBUS_TYPE_INVALID); 71 72 return send_message_and_unref(conn, reply); 73} 74 75static char *get_dev_name(DBusConnection *conn, const bdaddr_t *src, 76 const bdaddr_t *bda) 77{ 78 char address[18], filename[PATH_MAX + 1]; 79 80 ba2str(src, address); 81 82 /* check if it is in the cache */ 83 create_name(filename, PATH_MAX, STORAGEDIR, address, "names"); 84 85 ba2str(bda, address); 86 return textfile_caseget(filename, address); 87} 88 89static DBusHandlerResult device_get_name(DBusConnection *conn, 90 DBusMessage *msg, void *data) 91{ 92 struct device *dev = data; 93 DBusMessage *reply; 94 const char *name = dev->name ? dev->name : ""; 95 96 reply = dbus_message_new_method_return(msg); 97 if (!reply) 98 return DBUS_HANDLER_RESULT_NEED_MEMORY; 99 100 dbus_message_append_args(reply, DBUS_TYPE_STRING, &name, 101 DBUS_TYPE_INVALID); 102 103 return send_message_and_unref(conn, reply); 104} 105 106static DBusHandlerResult device_get_adapter(DBusConnection *conn, 107 DBusMessage *msg, void *data) 108{ 109 struct device *device = data; 110 DBusMessage *reply; 111 char address[18], *ptr = address; 112 113 reply = dbus_message_new_method_return(msg); 114 if (!reply) 115 return DBUS_HANDLER_RESULT_NEED_MEMORY; 116 117 ba2str(&device->src, address); 118 119 dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr, 120 DBUS_TYPE_INVALID); 121 122 return send_message_and_unref(conn, reply); 123} 124 125 126static DBusHandlerResult device_get_connected(DBusConnection *conn, 127 DBusMessage *msg, void *data) 128{ 129 DBusMessageIter iter, array_iter; 130 struct device *device = data; 131 DBusMessage *reply; 132 const char *iface; 133 134 reply = dbus_message_new_method_return(msg); 135 if (!reply) 136 return DBUS_HANDLER_RESULT_NEED_MEMORY; 137 138 dbus_message_iter_init_append(reply, &iter); 139 140 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 141 DBUS_TYPE_STRING_AS_STRING, 142 &array_iter); 143 144 if (device->headset && 145 headset_get_state(device) >= HEADSET_STATE_CONNECTED) { 146 iface = AUDIO_HEADSET_INTERFACE; 147 dbus_message_iter_append_basic(&array_iter, 148 DBUS_TYPE_STRING, &iface); 149 } 150 151 dbus_message_iter_close_container(&iter, &array_iter); 152 153 return send_message_and_unref(conn, reply); 154} 155 156static DBusMethodVTable device_methods[] = { 157 { "GetAddress", device_get_address, "", "s" }, 158 { "GetName", device_get_name, "", "s" }, 159 { "GetAdapter", device_get_adapter, "", "s" }, 160 { "GetConnectedInterfaces", device_get_connected, "", "as" }, 161 { NULL, NULL, NULL, NULL } 162}; 163 164static void device_free(struct device *dev) 165{ 166 if (dev->headset) 167 headset_free(dev); 168 169 if (dev->sink) 170 sink_free(dev); 171 172 if (dev->control) 173 control_free(dev); 174 175 if (dev->conn) 176 dbus_connection_unref(dev->conn); 177 178 g_free(dev->adapter_path); 179 g_free(dev->path); 180 g_free(dev->name); 181 182 g_free(dev); 183} 184 185static void device_unregister(DBusConnection *conn, void *data) 186{ 187 struct device *device = data; 188 189 info("Unregistered device path:%s", device->path); 190 191 device_free(device); 192} 193 194struct device *device_register(DBusConnection *conn, 195 const char *path, const bdaddr_t *bda) 196{ 197 struct device *dev; 198 bdaddr_t src; 199 int dev_id; 200 201 if (!conn || !path) 202 return NULL; 203 204 bacpy(&src, BDADDR_ANY); 205 dev_id = hci_get_route(&src); 206 if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0)) 207 return NULL; 208 209 dev = g_new0(struct device, 1); 210 211 /* FIXME just to maintain compatibility */ 212 dev->adapter_path = g_strdup_printf("/org/bluez/hci%d", dev_id); 213 if (!dev->adapter_path) { 214 device_free(dev); 215 return NULL; 216 } 217 218 if (!dbus_connection_create_object_path(conn, path, dev, 219 device_unregister)) { 220 error("D-Bus failed to register %s path", path); 221 device_free(dev); 222 return NULL; 223 } 224 225 if (!dbus_connection_register_interface(conn, path, 226 AUDIO_DEVICE_INTERFACE, device_methods, NULL, NULL)) { 227 error("Failed to register %s interface to %s", 228 AUDIO_DEVICE_INTERFACE, path); 229 dbus_connection_destroy_object_path(conn, path); 230 return NULL; 231 } 232 233 dev->name = get_dev_name(conn, &src, bda); 234 dev->path = g_strdup(path); 235 bacpy(&dev->dst, bda); 236 bacpy(&dev->src, &src); 237 bacpy(&dev->store, &src); 238 dev->conn = dbus_connection_ref(conn); 239 240 return dev; 241} 242 243int device_store(struct device *dev, gboolean is_default) 244{ 245 char value[64]; 246 char filename[PATH_MAX + 1]; 247 char src_addr[18], dst_addr[18]; 248 int offset = 0; 249 250 if (!dev->path) 251 return -EINVAL; 252 253 ba2str(&dev->dst, dst_addr); 254 ba2str(&dev->store, src_addr); 255 256 create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio"); 257 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 258 259 if (is_default) 260 textfile_put(filename, "default", dst_addr); 261 if (dev->headset) { 262 snprintf(value, 64, "headset "); 263 offset += strlen("headset "); 264 } 265 if (dev->gateway) { 266 snprintf(value + offset, 64 - offset, "gateway "); 267 offset += strlen("gateway "); 268 } 269 if (dev->sink) { 270 snprintf(value + offset, 64 - offset, "sink "); 271 offset += strlen("sink "); 272 } 273 if (dev->source) { 274 snprintf(value + offset, 64 - offset, "source "); 275 offset += strlen("source "); 276 } 277 if (dev->control) { 278 snprintf(value + offset, 64 - offset, "control "); 279 offset += strlen("control "); 280 } 281 if (dev->target) 282 snprintf(value + offset, 64 - offset, "target"); 283 284 return textfile_put(filename, dst_addr, value); 285} 286 287int device_remove_stored(struct device *dev) 288{ 289 char filename[PATH_MAX + 1]; 290 char src_addr[18], dst_addr[18]; 291 292 ba2str(&dev->dst, dst_addr); 293 ba2str(&dev->store, src_addr); 294 295 create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio"); 296 297 return textfile_del(filename, dst_addr); 298} 299 300void device_finish_sdp_transaction(struct device *dev) 301{ 302 char address[18], *addr_ptr = address; 303 DBusMessage *msg; 304 305 ba2str(&dev->dst, address); 306 307 msg = dbus_message_new_method_call("org.bluez", dev->adapter_path, 308 "org.bluez.Adapter", 309 "FinishRemoteServiceTransaction"); 310 if (!msg) { 311 error("Unable to allocate new method call"); 312 return; 313 } 314 315 dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, 316 DBUS_TYPE_INVALID); 317 318 send_message_and_unref(dev->conn, msg); 319} 320 321#if 0 322static avdtp_state_t ipc_to_avdtp_state(uint8_t ipc_state) 323{ 324 switch (ipc_state) { 325 case STATE_DISCONNECTED: 326 return AVDTP_STATE_IDLE; 327 case STATE_CONNECTING: 328 return AVDTP_STATE_CONFIGURED; 329 case STATE_CONNECTED: 330 return AVDTP_STATE_OPEN; 331 case STATE_STREAM_STARTING: 332 case STATE_STREAMING: 333 return AVDTP_STATE_STREAMING; 334 default: 335 error("Unknown ipc state"); 336 return AVDTP_STATE_IDLE; 337 } 338} 339 340static headset_state_t ipc_to_hs_state(uint8_t ipc_state) 341{ 342 switch (ipc_state) { 343 case STATE_DISCONNECTED: 344 return HEADSET_STATE_DISCONNECTED; 345 case STATE_CONNECTING: 346 return HEADSET_STATE_CONNECT_IN_PROGRESS; 347 case STATE_CONNECTED: 348 return HEADSET_STATE_CONNECTED; 349 case STATE_STREAM_STARTING: 350 return HEADSET_STATE_PLAY_IN_PROGRESS; 351 case STATE_STREAMING: 352 return HEADSET_STATE_PLAYING; 353 default: 354 error("Unknown ipc state"); 355 return HEADSET_STATE_DISCONNECTED; 356 } 357} 358 359static uint8_t avdtp_to_ipc_state(avdtp_state_t state) 360{ 361 switch (state) { 362 case AVDTP_STATE_IDLE: 363 return STATE_DISCONNECTED; 364 case AVDTP_STATE_CONFIGURED: 365 return STATE_CONNECTING; 366 case AVDTP_STATE_OPEN: 367 return STATE_CONNECTED; 368 case AVDTP_STATE_STREAMING: 369 return STATE_STREAMING; 370 default: 371 error("Unknown avdt state"); 372 return AVDTP_STATE_IDLE; 373 } 374} 375 376static uint8_t hs_to_ipc_state(headset_state_t state) 377{ 378 switch (state) { 379 case HEADSET_STATE_DISCONNECTED: 380 return STATE_DISCONNECTED; 381 case HEADSET_STATE_CONNECT_IN_PROGRESS: 382 return STATE_CONNECTING; 383 case HEADSET_STATE_CONNECTED: 384 return STATE_CONNECTED; 385 case HEADSET_STATE_PLAY_IN_PROGRESS: 386 return STATE_STREAMING; 387 default: 388 error("Unknown headset state"); 389 return AVDTP_STATE_IDLE; 390 } 391} 392 393uint8_t device_get_state(struct device *dev) 394{ 395 avdtp_state_t sink_state; 396 headset_state_t hs_state; 397 398 if (dev->sink && sink_is_active(dev)) { 399 sink_state = sink_get_state(dev); 400 return avdtp_to_ipc_state(sink_state); 401 } 402 else if (dev->headset && headset_is_active(dev)) { 403 hs_state = headset_get_state(dev); 404 return hs_to_ipc_state(hs_state); 405 } 406 else if (dev->control && control_is_active(dev)) 407 return STATE_CONNECTED; 408 409 return STATE_DISCONNECTED; 410} 411#endif 412 413gboolean device_is_connected(struct device *dev, const char *interface) 414{ 415 if (!interface) { 416 if ((dev->sink || dev->source) && 417 avdtp_is_connected(&dev->src, &dev->dst)) 418 return TRUE; 419 420 if (dev->headset && headset_is_active(dev)) 421 return TRUE; 422 } 423 else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink && 424 avdtp_is_connected(&dev->src, &dev->dst)) 425 return TRUE; 426 else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source && 427 avdtp_is_connected(&dev->src, &dev->dst)) 428 return TRUE; 429 else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset && 430 headset_is_active(dev)) 431 return TRUE; 432 else if (!strcmp(interface, AUDIO_CONTROL_INTERFACE) && dev->headset && 433 control_is_active(dev)) 434 return TRUE; 435 436 return FALSE; 437} 438