1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2010 Marcel Holtmann <marcel (at) holtmann.org> 6 * 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library 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 GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; 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 <sys/socket.h> 29 #include <sys/un.h> 30 31 #include <alsa/asoundlib.h> 32 #include <alsa/control_external.h> 33 34 #include <bluetooth/bluetooth.h> 35 36 #include "ipc.h" 37 38 #ifdef ENABLE_DEBUG 39 #define DBG(fmt, arg...) printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg) 40 #else 41 #define DBG(fmt, arg...) 42 #endif 43 44 #define BLUETOOTH_MINVOL 0 45 #define BLUETOOTH_MAXVOL 15 46 47 struct bluetooth_data { 48 snd_ctl_ext_t ext; 49 int sock; 50 }; 51 52 enum { 53 BLUETOOTH_PLAYBACK, 54 BLUETOOTH_CAPTURE, 55 }; 56 57 static const char *vol_devices[2] = { 58 [BLUETOOTH_PLAYBACK] = "Playback volume", 59 [BLUETOOTH_CAPTURE] = "Capture volume", 60 }; 61 62 static void bluetooth_exit(struct bluetooth_data *data) 63 { 64 if (data == NULL) 65 return; 66 67 if (data->sock >= 0) 68 bt_audio_service_close(data->sock); 69 70 free(data); 71 } 72 73 static void bluetooth_close(snd_ctl_ext_t *ext) 74 { 75 struct bluetooth_data *data = ext->private_data; 76 77 DBG("ext %p", ext); 78 79 bluetooth_exit(data); 80 } 81 82 static int bluetooth_elem_count(snd_ctl_ext_t *ext) 83 { 84 DBG("ext %p", ext); 85 86 return 2; 87 } 88 89 static int bluetooth_elem_list(snd_ctl_ext_t *ext, 90 unsigned int offset, snd_ctl_elem_id_t *id) 91 { 92 DBG("ext %p offset %d id %p", ext, offset, id); 93 94 snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); 95 96 if (offset > 1) 97 return -EINVAL; 98 99 snd_ctl_elem_id_set_name(id, vol_devices[offset]); 100 101 return 0; 102 } 103 104 static snd_ctl_ext_key_t bluetooth_find_elem(snd_ctl_ext_t *ext, 105 const snd_ctl_elem_id_t *id) 106 { 107 const char *name = snd_ctl_elem_id_get_name(id); 108 int i; 109 110 DBG("ext %p id %p name '%s'", ext, id, name); 111 112 for (i = 0; i < 2; i++) 113 if (strcmp(name, vol_devices[i]) == 0) 114 return i; 115 116 return SND_CTL_EXT_KEY_NOT_FOUND; 117 } 118 119 static int bluetooth_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, 120 int *type, unsigned int *acc, unsigned int *count) 121 { 122 DBG("ext %p key %ld", ext, key); 123 124 *type = SND_CTL_ELEM_TYPE_INTEGER; 125 *acc = SND_CTL_EXT_ACCESS_READWRITE; 126 *count = 1; 127 128 return 0; 129 } 130 131 static int bluetooth_get_integer_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, 132 long *imin, long *imax, long *istep) 133 { 134 DBG("ext %p key %ld", ext, key); 135 136 *istep = 1; 137 *imin = BLUETOOTH_MINVOL; 138 *imax = BLUETOOTH_MAXVOL; 139 140 return 0; 141 } 142 143 static int bluetooth_send_ctl(struct bluetooth_data *data, 144 uint8_t mode, uint8_t key, struct bt_control_rsp *rsp) 145 { 146 int ret; 147 struct bt_control_req *req = (void *) rsp; 148 bt_audio_error_t *err = (void *) rsp; 149 const char *type, *name; 150 151 memset(req, 0, BT_SUGGESTED_BUFFER_SIZE); 152 req->h.type = BT_REQUEST; 153 req->h.name = BT_CONTROL; 154 req->h.length = sizeof(*req); 155 156 req->mode = mode; 157 req->key = key; 158 159 ret = send(data->sock, req, BT_SUGGESTED_BUFFER_SIZE, MSG_NOSIGNAL); 160 if (ret <= 0) { 161 SYSERR("Unable to request new volume value to server"); 162 return -errno; 163 } 164 165 ret = recv(data->sock, rsp, BT_SUGGESTED_BUFFER_SIZE, 0); 166 if (ret <= 0) { 167 SNDERR("Unable to receive new volume value from server"); 168 return -errno; 169 } 170 171 if (rsp->h.type == BT_ERROR) { 172 SNDERR("BT_CONTROL failed : %s (%d)", 173 strerror(err->posix_errno), 174 err->posix_errno); 175 return -err->posix_errno; 176 } 177 178 type = bt_audio_strtype(rsp->h.type); 179 if (!type) { 180 SNDERR("Bogus message type %d " 181 "received from audio service", 182 rsp->h.type); 183 return -EINVAL; 184 } 185 186 name = bt_audio_strname(rsp->h.name); 187 if (!name) { 188 SNDERR("Bogus message name %d " 189 "received from audio service", 190 rsp->h.name); 191 return -EINVAL; 192 } 193 194 if (rsp->h.name != BT_CONTROL) { 195 SNDERR("Unexpected message %s received", type); 196 return -EINVAL; 197 } 198 199 return 0; 200 } 201 202 static int bluetooth_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, 203 long *value) 204 { 205 struct bluetooth_data *data = ext->private_data; 206 int ret; 207 char buf[BT_SUGGESTED_BUFFER_SIZE]; 208 struct bt_control_rsp *rsp = (void *) buf; 209 210 DBG("ext %p key %ld", ext, key); 211 212 memset(buf, 0, sizeof(buf)); 213 *value = 0; 214 215 ret = bluetooth_send_ctl(data, key, 0, rsp); 216 if (ret < 0) 217 goto done; 218 219 *value = rsp->key; 220 done: 221 return ret; 222 } 223 224 static int bluetooth_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, 225 long *value) 226 { 227 struct bluetooth_data *data = ext->private_data; 228 char buf[BT_SUGGESTED_BUFFER_SIZE]; 229 struct bt_control_rsp *rsp = (void *) buf; 230 long current; 231 int ret, keyvalue; 232 233 DBG("ext %p key %ld", ext, key); 234 235 ret = bluetooth_read_integer(ext, key, ¤t); 236 if (ret < 0) 237 return ret; 238 239 if (*value == current) 240 return 0; 241 242 while (*value != current) { 243 keyvalue = (*value > current) ? BT_CONTROL_KEY_VOL_UP : 244 BT_CONTROL_KEY_VOL_DOWN; 245 246 ret = bluetooth_send_ctl(data, key, keyvalue, rsp); 247 if (ret < 0) 248 break; 249 250 current = keyvalue; 251 } 252 253 return ret; 254 } 255 256 static int bluetooth_read_event(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id, 257 unsigned int *event_mask) 258 { 259 struct bluetooth_data *data = ext->private_data; 260 char buf[BT_SUGGESTED_BUFFER_SIZE]; 261 struct bt_control_ind *ind = (void *) buf; 262 int ret; 263 const char *type, *name; 264 265 DBG("ext %p id %p", ext, id); 266 267 memset(buf, 0, sizeof(buf)); 268 269 ret = recv(data->sock, ind, BT_SUGGESTED_BUFFER_SIZE, MSG_DONTWAIT); 270 if (ret < 0) { 271 SNDERR("Failed while receiving data: %s (%d)", 272 strerror(errno), errno); 273 return -errno; 274 } 275 276 type = bt_audio_strtype(ind->h.type); 277 if (!type) { 278 SNDERR("Bogus message type %d " 279 "received from audio service", 280 ind->h.type); 281 return -EAGAIN; 282 } 283 284 name = bt_audio_strname(ind->h.name); 285 if (!name) { 286 SNDERR("Bogus message name %d " 287 "received from audio service", 288 ind->h.name); 289 return -EAGAIN; 290 } 291 292 if (ind->h.name != BT_CONTROL) { 293 SNDERR("Unexpected message %s received", name); 294 return -EAGAIN; 295 } 296 297 snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); 298 snd_ctl_elem_id_set_name(id, ind->mode == BLUETOOTH_PLAYBACK ? 299 vol_devices[BLUETOOTH_PLAYBACK] : 300 vol_devices[BLUETOOTH_CAPTURE]); 301 *event_mask = SND_CTL_EVENT_MASK_VALUE; 302 303 return 1; 304 } 305 306 static snd_ctl_ext_callback_t bluetooth_callback = { 307 .close = bluetooth_close, 308 .elem_count = bluetooth_elem_count, 309 .elem_list = bluetooth_elem_list, 310 .find_elem = bluetooth_find_elem, 311 .get_attribute = bluetooth_get_attribute, 312 .get_integer_info = bluetooth_get_integer_info, 313 .read_integer = bluetooth_read_integer, 314 .write_integer = bluetooth_write_integer, 315 .read_event = bluetooth_read_event, 316 }; 317 318 static int bluetooth_init(struct bluetooth_data *data) 319 { 320 int sk; 321 322 if (!data) 323 return -EINVAL; 324 325 memset(data, 0, sizeof(struct bluetooth_data)); 326 327 data->sock = -1; 328 329 sk = bt_audio_service_open(); 330 if (sk < 0) 331 return -errno; 332 333 data->sock = sk; 334 335 return 0; 336 } 337 338 SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth); 339 340 SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth) 341 { 342 struct bluetooth_data *data; 343 int err; 344 345 DBG("Bluetooth Control plugin"); 346 347 data = malloc(sizeof(struct bluetooth_data)); 348 if (!data) { 349 err = -ENOMEM; 350 goto error; 351 } 352 353 err = bluetooth_init(data); 354 if (err < 0) 355 goto error; 356 357 data->ext.version = SND_CTL_EXT_VERSION; 358 data->ext.card_idx = -1; 359 360 strncpy(data->ext.id, "bluetooth", sizeof(data->ext.id) - 1); 361 strncpy(data->ext.driver, "Bluetooth-Audio", sizeof(data->ext.driver) - 1); 362 strncpy(data->ext.name, "Bluetooth Audio", sizeof(data->ext.name) - 1); 363 strncpy(data->ext.longname, "Bluetooth Audio", sizeof(data->ext.longname) - 1); 364 strncpy(data->ext.mixername, "Bluetooth Audio", sizeof(data->ext.mixername) - 1); 365 366 data->ext.callback = &bluetooth_callback; 367 data->ext.poll_fd = data->sock; 368 data->ext.private_data = data; 369 370 err = snd_ctl_ext_create(&data->ext, name, mode); 371 if (err < 0) 372 goto error; 373 374 *handlep = data->ext.handle; 375 376 return 0; 377 378 error: 379 bluetooth_exit(data); 380 381 return err; 382 } 383 384 SND_CTL_PLUGIN_SYMBOL(bluetooth); 385