cras_bt_io.c revision 532e64eee91fc4acf5796e0a61c242a442a4cc04
1/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6#include <syslog.h> 7 8#include "cras_bt_io.h" 9#include "cras_bt_device.h" 10#include "cras_iodev.h" 11#include "cras_iodev_list.h" 12#include "utlist.h" 13 14/* Extends cras_ionode to hold bluetooth profile information 15 * so that iodevs of different profile(A2DP or HFP/HSP) can be 16 * associated with the same bt_io. 17 * Members: 18 * base - The base class cras_ionode. 19 * profile_dev - Pointer to the profile specific iodev. 20 * profile - The bluetooth profile profile_dev runs on. 21 */ 22struct bt_node { 23 struct cras_ionode base; 24 struct cras_iodev *profile_dev; 25 enum cras_bt_device_profile profile; 26}; 27 28/* The structure represents a virtual input or output device of a 29 * bluetooth audio device, speaker or headset for example. A node 30 * will be added to this virtual iodev for each profile supported 31 * by the bluetooth audio device. 32 * Member: 33 * base - The base class cras_iodev 34 * next_node_id - The index will give to the next node 35 */ 36struct bt_io { 37 struct cras_iodev base; 38 unsigned int next_node_id; 39 struct cras_bt_device *device; 40}; 41 42/* Returns the active profile specific iodev. */ 43static struct cras_iodev *active_profile_dev(const struct cras_iodev *iodev) 44{ 45 struct bt_node *active = (struct bt_node *)iodev->active_node; 46 47 return active->profile_dev; 48} 49 50/* Adds a profile specific iodev to btio. */ 51static struct cras_ionode *add_profile_dev(struct cras_iodev *bt_iodev, 52 struct cras_iodev *dev, 53 enum cras_bt_device_profile profile) 54{ 55 struct bt_node *n; 56 struct bt_io *btio = (struct bt_io *)bt_iodev; 57 58 n = (struct bt_node *)calloc(1, sizeof(*n)); 59 if (!n) 60 return NULL; 61 62 n->base.dev = bt_iodev; 63 n->base.idx = btio->next_node_id++; 64 n->base.type = CRAS_NODE_TYPE_BLUETOOTH; 65 n->base.volume = 100; 66 gettimeofday(&n->base.plugged_time, NULL); 67 68 strcpy(n->base.name, dev->info.name); 69 n->profile_dev = dev; 70 n->profile = profile; 71 72 cras_iodev_add_node(bt_iodev, &n->base); 73 return &n->base; 74} 75 76/* Forces bt device to switch to use the given profile. Note that if 77 * it has already been open for streaming, the new active profile will 78 * take effect after the related btio(s) are reopened. 79 */ 80static void bt_switch_to_profile(struct cras_bt_device *device, 81 enum cras_bt_device_profile profile) 82{ 83 switch (profile) { 84 case CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY: 85 case CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY: 86 cras_bt_device_set_active_profile(device, 87 CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY | 88 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY); 89 break; 90 case CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE: 91 cras_bt_device_set_active_profile(device, 92 CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE); 93 break; 94 default: 95 syslog(LOG_ERR, "Unexpect profile %u", profile); 96 break; 97 } 98} 99 100/* Checks if bt device is active for the given profile. 101 */ 102static int device_using_profile(struct cras_bt_device *device, 103 unsigned int profile) 104{ 105 return cras_bt_device_get_active_profile(device) & profile; 106} 107 108/* Checks if the condition is met to switch to a different profile 109 * when trying to set the format to btio before open it. Base on two 110 * rules: 111 * (1) Prefer to use A2DP for output since the audio quality is better. 112 * (2) Must use HFP/HSP for input since A2DP doesn't support audio input. 113 * 114 * If the profile switch happens, return non-zero error code, otherwise 115 * return zero. 116 */ 117static int update_supported_formats(struct cras_iodev *iodev) 118{ 119 struct bt_io *btio = (struct bt_io *)iodev; 120 struct cras_iodev *dev = active_profile_dev(iodev); 121 int rc, length, i; 122 123 /* Force to use HFP if opening input dev. */ 124 if (device_using_profile(btio->device, 125 CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE) && 126 iodev->direction == CRAS_STREAM_INPUT) { 127 bt_switch_to_profile(btio->device, 128 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY); 129 cras_bt_device_switch_profile_on_open(btio->device, iodev); 130 return -EAGAIN; 131 } 132 133 if (dev->format == NULL) { 134 dev->format = (struct cras_audio_format *) 135 malloc(sizeof(*dev->format)); 136 *dev->format = *iodev->format; 137 } 138 139 if (dev->update_supported_formats) { 140 rc = dev->update_supported_formats(dev); 141 if (rc) 142 return rc; 143 } 144 145 /* Fill in the supported rates and channel counts. */ 146 for (length = 0; dev->supported_rates[length]; length++); 147 free(iodev->supported_rates); 148 iodev->supported_rates = (size_t *)malloc( 149 (length + 1) * sizeof(*iodev->supported_rates)); 150 for (i = 0; i < length + 1; i++) 151 iodev->supported_rates[i] = dev->supported_rates[i]; 152 153 for (length = 0; dev->supported_channel_counts[length]; length++); 154 iodev->supported_channel_counts = (size_t *)malloc( 155 (length + 1) * sizeof(*iodev->supported_channel_counts)); 156 for (i = 0; i < length + 1; i++) 157 iodev->supported_channel_counts[i] = 158 dev->supported_channel_counts[i]; 159 160 for (length = 0; dev->supported_formats[length]; length++); 161 iodev->supported_formats = (snd_pcm_format_t *)malloc( 162 (length + 1) * sizeof(*iodev->supported_formats)); 163 for (i = 0; i < length + 1; i++) 164 iodev->supported_formats[i] = 165 dev->supported_formats[i]; 166 return 0; 167} 168 169static int open_dev(struct cras_iodev *iodev) 170{ 171 int rc; 172 struct cras_iodev *dev = active_profile_dev(iodev); 173 if (!dev) 174 return -EINVAL; 175 176 /* Fill back the format iodev is using. */ 177 *dev->format = *iodev->format; 178 179 rc = dev->open_dev(dev); 180 if (rc) 181 return rc; 182 183 iodev->buffer_size = dev->buffer_size; 184 iodev->min_buffer_level = dev->min_buffer_level; 185 return 0; 186} 187 188static int close_dev(struct cras_iodev *iodev) 189{ 190 struct bt_io *btio = (struct bt_io *)iodev; 191 int rc; 192 struct cras_iodev *dev = active_profile_dev(iodev); 193 194 /* Force back to A2DP if closing HFP. */ 195 if (device_using_profile(btio->device, 196 CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY | 197 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY) && 198 iodev->direction == CRAS_STREAM_INPUT && 199 cras_bt_device_supports_profile(btio->device, 200 CRAS_BT_DEVICE_PROFILE_A2DP_SINK)) { 201 cras_bt_device_set_active_profile(btio->device, 202 CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE); 203 cras_bt_device_switch_profile_on_close(btio->device, 204 iodev); 205 } 206 207 rc = dev->close_dev(dev); 208 if (rc < 0) 209 return rc; 210 cras_iodev_free_format(iodev); 211 return 0; 212} 213 214static int is_open(const struct cras_iodev *iodev) 215{ 216 struct cras_iodev *dev = active_profile_dev(iodev); 217 if (!dev) 218 return 0; 219 return dev->is_open(dev); 220} 221 222static int frames_queued(const struct cras_iodev *iodev) 223{ 224 struct cras_iodev *dev = active_profile_dev(iodev); 225 if (!dev) 226 return -EINVAL; 227 return dev->frames_queued(dev); 228} 229 230static int dev_running(const struct cras_iodev *iodev) 231{ 232 struct cras_iodev *dev = active_profile_dev(iodev); 233 if (!dev) 234 return -EINVAL; 235 return dev->dev_running(dev); 236} 237 238static int delay_frames(const struct cras_iodev *iodev) 239{ 240 struct cras_iodev *dev = active_profile_dev(iodev); 241 if (!dev) 242 return -EINVAL; 243 return dev->delay_frames(dev); 244} 245 246static int get_buffer(struct cras_iodev *iodev, 247 struct cras_audio_area **area, 248 unsigned *frames) 249{ 250 struct cras_iodev *dev = active_profile_dev(iodev); 251 if (!dev) 252 return -EINVAL; 253 return dev->get_buffer(dev, area, frames); 254} 255 256static int put_buffer(struct cras_iodev *iodev, unsigned nwritten) 257{ 258 struct cras_iodev *dev = active_profile_dev(iodev); 259 if (!dev) 260 return -EINVAL; 261 return dev->put_buffer(dev, nwritten); 262} 263 264/* If the first private iodev doesn't match the active profile stored on 265 * device, select to the correct private iodev. 266 */ 267static void update_active_node(struct cras_iodev *iodev) 268{ 269 struct bt_io *btio = (struct bt_io *)iodev; 270 struct cras_ionode *node; 271 struct bt_node *active = (struct bt_node *)iodev->active_node; 272 273 if (device_using_profile(btio->device, active->profile)) 274 return; 275 276 /* Switch to the correct dev using active_profile. */ 277 DL_FOREACH(iodev->nodes, node) { 278 struct bt_node *n = (struct bt_node *)node; 279 if (n == active) 280 continue; 281 282 if (device_using_profile(btio->device, n->profile)) { 283 active->profile = n->profile; 284 active->profile_dev = n->profile_dev; 285 } 286 } 287} 288 289struct cras_iodev *cras_bt_io_create(struct cras_bt_device *device, 290 struct cras_iodev *dev, 291 enum cras_bt_device_profile profile) 292{ 293 int err; 294 struct bt_io *btio; 295 struct cras_iodev *iodev; 296 struct cras_ionode *node; 297 struct bt_node *active; 298 299 if (!dev) 300 return NULL; 301 302 btio = (struct bt_io *)calloc(1, sizeof(*btio)); 303 if (!btio) 304 goto error; 305 btio->device = device; 306 307 bt_switch_to_profile(device, profile); 308 309 iodev = &btio->base; 310 iodev->direction = dev->direction; 311 strcpy(iodev->info.name, dev->info.name); 312 313 iodev->open_dev = open_dev; 314 iodev->is_open = is_open; /* Needed by thread_add_stream */ 315 iodev->frames_queued = frames_queued; 316 iodev->dev_running = dev_running; 317 iodev->delay_frames = delay_frames; 318 iodev->get_buffer = get_buffer; 319 iodev->put_buffer = put_buffer; 320 iodev->close_dev = close_dev; 321 iodev->update_supported_formats = update_supported_formats; 322 iodev->update_active_node = update_active_node; 323 iodev->software_volume_needed = 1; 324 325 /* Create the dummy node set to plugged so it's the only node exposed 326 * to UI, and point it to the first profile dev. */ 327 active = (struct bt_node *)calloc(1, sizeof(*active)); 328 if (!active) 329 return NULL; 330 active->base.dev = iodev; 331 active->base.idx = btio->next_node_id++; 332 active->base.type = CRAS_NODE_TYPE_BLUETOOTH; 333 active->base.volume = 100; 334 active->base.plugged = 1; 335 active->profile = profile; 336 active->profile_dev = dev; 337 gettimeofday(&active->base.plugged_time, NULL); 338 strcpy(active->base.name, dev->info.name); 339 cras_iodev_add_node(iodev, &active->base); 340 341 node = add_profile_dev(&btio->base, dev, profile); 342 if (node == NULL) 343 goto error; 344 345 if (iodev->direction == CRAS_STREAM_OUTPUT) 346 err = cras_iodev_list_add_output(iodev); 347 else 348 err = cras_iodev_list_add_input(iodev); 349 if (err) 350 goto error; 351 352 cras_iodev_set_active_node(iodev, &active->base); 353 return &btio->base; 354 355error: 356 if (btio) 357 free(btio); 358 return NULL; 359} 360 361void cras_bt_io_destroy(struct cras_iodev *bt_iodev) 362{ 363 int rc; 364 struct bt_io *btio = (struct bt_io *)bt_iodev; 365 struct cras_ionode *node; 366 struct bt_node *n; 367 368 if (bt_iodev->direction == CRAS_STREAM_OUTPUT) 369 rc = cras_iodev_list_rm_output(bt_iodev); 370 else 371 rc = cras_iodev_list_rm_input(bt_iodev); 372 if (rc == -EBUSY) 373 return; 374 375 DL_FOREACH(bt_iodev->nodes, node) { 376 n = (struct bt_node *)node; 377 cras_iodev_rm_node(bt_iodev, node); 378 free(n); 379 } 380 free(btio); 381} 382 383int cras_bt_io_has_dev(struct cras_iodev *bt_iodev, 384 struct cras_iodev *dev) 385{ 386 struct cras_ionode *node; 387 388 DL_FOREACH(bt_iodev->nodes, node) { 389 struct bt_node *n = (struct bt_node *)node; 390 if (n->profile_dev == dev) 391 return 1; 392 } 393 return 0; 394} 395 396int cras_bt_io_append(struct cras_iodev *bt_iodev, 397 struct cras_iodev *dev, 398 enum cras_bt_device_profile profile) 399{ 400 struct cras_ionode *node; 401 struct bt_io *btio = (struct bt_io *)bt_iodev; 402 403 if (cras_bt_io_has_dev(bt_iodev, dev)) 404 return -EEXIST; 405 406 node = add_profile_dev(bt_iodev, dev, profile); 407 if (!node) 408 return -ENOMEM; 409 410 if (profile == CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE && 411 cras_bt_device_can_switch_to_a2dp(btio->device)) { 412 bt_switch_to_profile(btio->device, 413 CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE); 414 cras_bt_device_switch_profile_on_open(btio->device, bt_iodev); 415 syslog(LOG_ERR, "Switch to A2DP on append"); 416 } 417 return 0; 418} 419 420unsigned int cras_bt_io_try_remove(struct cras_iodev *bt_iodev, 421 struct cras_iodev *dev) 422{ 423 struct cras_ionode *node; 424 struct bt_node *active, *btnode; 425 unsigned int try_profile = 0; 426 427 active = (struct bt_node *)bt_iodev->active_node; 428 429 if (active->profile_dev == dev) { 430 DL_FOREACH(bt_iodev->nodes, node) { 431 btnode = (struct bt_node *)node; 432 /* Skip the active node and the node we're trying 433 * to remove. */ 434 if (btnode == active || btnode->profile_dev == dev) 435 continue; 436 try_profile = btnode->profile; 437 break; 438 } 439 } else { 440 try_profile = active->profile; 441 } 442 return try_profile; 443} 444 445int cras_bt_io_remove(struct cras_iodev *bt_iodev, 446 struct cras_iodev *dev) 447{ 448 struct cras_ionode *node; 449 struct bt_node *btnode; 450 451 DL_SEARCH_SCALAR_WITH_CAST(bt_iodev->nodes, node, btnode, 452 profile_dev, dev); 453 if (node) { 454 DL_DELETE(bt_iodev->nodes, node); 455 free(node); 456 } 457 return 0; 458} 459