1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "sound_trigger_hw_flounder" 18 /*#define LOG_NDEBUG 0*/ 19 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <malloc.h> 23 #include <poll.h> 24 #include <pthread.h> 25 #include <sys/ioctl.h> 26 #include <sys/prctl.h> 27 #include <cutils/log.h> 28 #include <cutils/uevent.h> 29 30 #include <hardware/hardware.h> 31 #include <system/sound_trigger.h> 32 #include <hardware/sound_trigger.h> 33 #include <tinyalsa/asoundlib.h> 34 35 #define FLOUNDER_MIXER_VAD 0 36 #define FLOUNDER_CTRL_DSP "VAD Mode" 37 #define UEVENT_MSG_LEN 1024 38 39 #define FLOUNDER_VAD_DEV "/dev/snd/hwC0D0" 40 41 #define FLOUNDER_STREAMING_DELAY_USEC 1000 42 #define FLOUNDER_STREAMING_READ_RETRY_ATTEMPTS 30 43 #define FLOUNDER_STREAMING_BUFFER_SIZE (16 * 1024) 44 45 static const struct sound_trigger_properties hw_properties = { 46 "The Android Open Source Project", // implementor 47 "Volantis OK Google ", // description 48 1, // version 49 { 0xe780f240, 0xf034, 0x11e3, 0xb79a, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid 50 1, // max_sound_models 51 1, // max_key_phrases 52 1, // max_users 53 RECOGNITION_MODE_VOICE_TRIGGER, // recognition_modes 54 true, // capture_transition 55 0, // max_capture_ms 56 false, // concurrent_capture 57 false, // trigger_in_event 58 0 // power_consumption_mw 59 }; 60 61 struct flounder_sound_trigger_device { 62 struct sound_trigger_hw_device device; 63 sound_model_handle_t model_handle; 64 recognition_callback_t recognition_callback; 65 void *recognition_cookie; 66 sound_model_callback_t sound_model_callback; 67 void *sound_model_cookie; 68 pthread_t callback_thread; 69 pthread_mutex_t lock; 70 int send_sock; 71 int term_sock; 72 int vad_fd; 73 struct mixer *mixer; 74 struct mixer_ctl *ctl_dsp; 75 struct sound_trigger_recognition_config *config; 76 int is_streaming; 77 int opened; 78 char *streaming_buf; 79 size_t streaming_buf_read; 80 size_t streaming_buf_len; 81 }; 82 83 struct rt_codec_cmd { 84 size_t number; 85 int *buf; 86 }; 87 88 enum { 89 RT_READ_CODEC_DSP_IOCTL = _IOR('R', 0x04, struct rt_codec_cmd), 90 RT_WRITE_CODEC_DSP_IOCTL = _IOW('R', 0x04, struct rt_codec_cmd), 91 }; 92 93 // Since there's only ever one sound_trigger_device, keep it as a global so that other people can 94 // dlopen this lib to get at the streaming audio. 95 static struct flounder_sound_trigger_device g_stdev = { .lock = PTHREAD_MUTEX_INITIALIZER }; 96 97 static void stdev_dsp_set_power(struct flounder_sound_trigger_device *stdev, 98 int val) 99 { 100 stdev->is_streaming = 0; 101 stdev->streaming_buf_read = 0; 102 stdev->streaming_buf_len = 0; 103 mixer_ctl_set_value(stdev->ctl_dsp, 0, val); 104 } 105 106 static int stdev_init_mixer(struct flounder_sound_trigger_device *stdev) 107 { 108 int ret = -1; 109 110 stdev->vad_fd = open(FLOUNDER_VAD_DEV, O_RDWR); 111 if (stdev->vad_fd < 0) { 112 ALOGE("Error opening vad device"); 113 return ret; 114 } 115 116 stdev->mixer = mixer_open(FLOUNDER_MIXER_VAD); 117 if (!stdev->mixer) 118 goto err; 119 120 stdev->ctl_dsp = mixer_get_ctl_by_name(stdev->mixer, FLOUNDER_CTRL_DSP); 121 if (!stdev->ctl_dsp) 122 goto err; 123 124 stdev_dsp_set_power(stdev, 0); // Disable DSP at the beginning 125 126 return 0; 127 128 err: 129 close(stdev->vad_fd); 130 if (stdev->mixer) 131 mixer_close(stdev->mixer); 132 return ret; 133 } 134 135 static void stdev_close_term_sock(struct flounder_sound_trigger_device *stdev) 136 { 137 if (stdev->send_sock >=0) { 138 close(stdev->send_sock); 139 stdev->send_sock = -1; 140 } 141 if (stdev->term_sock >=0) { 142 close(stdev->term_sock); 143 stdev->term_sock = -1; 144 } 145 } 146 147 static void stdev_close_mixer(struct flounder_sound_trigger_device *stdev) 148 { 149 if (stdev) { 150 stdev_dsp_set_power(stdev, 0); 151 mixer_close(stdev->mixer); 152 stdev_close_term_sock(stdev); 153 close(stdev->vad_fd); 154 } 155 } 156 157 static int vad_load_sound_model(struct flounder_sound_trigger_device *stdev, 158 char *buf, size_t len) 159 { 160 struct rt_codec_cmd cmd; 161 int ret = 0; 162 163 if (!buf || (len == 0)) 164 return ret; 165 166 cmd.number = len / sizeof(int); 167 cmd.buf = (int *)buf; 168 169 ret = ioctl(stdev->vad_fd, RT_WRITE_CODEC_DSP_IOCTL, &cmd); 170 if (ret) 171 ALOGE("Error VAD write ioctl: %d", ret); 172 return ret; 173 } 174 175 static char *sound_trigger_event_alloc(struct flounder_sound_trigger_device * 176 stdev) 177 { 178 char *data; 179 struct sound_trigger_phrase_recognition_event *event; 180 181 data = (char *)calloc(1, 182 sizeof(struct sound_trigger_phrase_recognition_event)); 183 if (!data) 184 return NULL; 185 186 event = (struct sound_trigger_phrase_recognition_event *)data; 187 event->common.status = RECOGNITION_STATUS_SUCCESS; 188 event->common.type = SOUND_MODEL_TYPE_KEYPHRASE; 189 event->common.model = stdev->model_handle; 190 191 if (stdev->config) { 192 unsigned int i; 193 194 event->num_phrases = stdev->config->num_phrases; 195 if (event->num_phrases > SOUND_TRIGGER_MAX_PHRASES) 196 event->num_phrases = SOUND_TRIGGER_MAX_PHRASES; 197 for (i=0; i < event->num_phrases; i++) 198 memcpy(&event->phrase_extras[i], &stdev->config->phrases[i], 199 sizeof(struct sound_trigger_phrase_recognition_extra)); 200 } 201 202 event->num_phrases = 1; 203 event->phrase_extras[0].confidence_level = 100; 204 event->phrase_extras[0].num_levels = 1; 205 event->phrase_extras[0].levels[0].level = 100; 206 event->phrase_extras[0].levels[0].user_id = 0; 207 // Signify that all the data is comming through streaming, not through the 208 // buffer. 209 event->common.capture_available = true; 210 211 event->common.audio_config = AUDIO_CONFIG_INITIALIZER; 212 event->common.audio_config.sample_rate = 16000; 213 event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO; 214 event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT; 215 216 return data; 217 } 218 219 // The stdev should be locked when you call this function. 220 static int fetch_streaming_buffer(struct flounder_sound_trigger_device * stdev) 221 { 222 struct rt_codec_cmd cmd; 223 int ret = 0; 224 int i; 225 226 cmd.number = FLOUNDER_STREAMING_BUFFER_SIZE / sizeof(int); 227 cmd.buf = (int*) stdev->streaming_buf; 228 229 ALOGV("%s: Fetching bytes", __func__); 230 for (i = 0; i < FLOUNDER_STREAMING_READ_RETRY_ATTEMPTS; i++) { 231 ret = ioctl(stdev->vad_fd, RT_READ_CODEC_DSP_IOCTL, &cmd); 232 if (ret == 0) { 233 usleep(FLOUNDER_STREAMING_DELAY_USEC); 234 } else if (ret < 0) { 235 ALOGV("%s: IOCTL failed with code %d", __func__, ret); 236 return ret; 237 } else { 238 // The IOCTL returns the number of int16 samples that were read, so we need to multipy 239 // it by 2 . 240 ALOGV("%s: IOCTL captured %d samples", __func__, ret); 241 stdev->streaming_buf_read = 0; 242 stdev->streaming_buf_len = ret << 1; 243 return 0; 244 } 245 } 246 ALOGV("%s: Timeout waiting for data from dsp", __func__); 247 return 0; 248 } 249 250 static void *callback_thread_loop(void *context) 251 { 252 char msg[UEVENT_MSG_LEN]; 253 struct flounder_sound_trigger_device *stdev = 254 (struct flounder_sound_trigger_device *)context; 255 struct pollfd fds[2]; 256 int exit_sockets[2]; 257 int err = 0; 258 int i, n; 259 260 ALOGI("%s", __func__); 261 prctl(PR_SET_NAME, (unsigned long)"sound trigger callback", 0, 0, 0); 262 263 pthread_mutex_lock(&stdev->lock); 264 if (stdev->recognition_callback == NULL) 265 goto exit; 266 267 if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) 268 goto exit; 269 270 stdev_close_term_sock(stdev); 271 stdev->send_sock = exit_sockets[0]; 272 stdev->term_sock = exit_sockets[1]; 273 274 memset(fds, 0, 2 * sizeof(struct pollfd)); 275 fds[0].events = POLLIN; 276 fds[0].fd = uevent_open_socket(64*1024, true); 277 if (fds[0].fd == -1) { 278 ALOGE("Error opening socket for hotplug uevent"); 279 goto exit; 280 } 281 fds[1].events = POLLIN; 282 fds[1].fd = stdev->term_sock; 283 284 stdev_dsp_set_power(stdev, 1); 285 286 pthread_mutex_unlock(&stdev->lock); 287 288 while (1) { 289 err = poll(fds, 2, -1); 290 pthread_mutex_lock(&stdev->lock); 291 if ((err < 0) || (stdev->recognition_callback == NULL)) { 292 ALOGE_IF(err < 0, "Error in hotplug CPU poll: %d", errno); 293 break; 294 } 295 296 if (fds[0].revents & POLLIN) { 297 n = uevent_kernel_multicast_recv(fds[0].fd, msg, UEVENT_MSG_LEN); 298 if (n <= 0) { 299 pthread_mutex_unlock(&stdev->lock); 300 continue; 301 } 302 for (i=0; i < n;) { 303 if (strstr(msg + i, "HOTWORD")) { 304 struct sound_trigger_phrase_recognition_event *event; 305 306 event = (struct sound_trigger_phrase_recognition_event *) 307 sound_trigger_event_alloc(stdev); 308 if (event) { 309 recognition_callback_t callback = stdev->recognition_callback; 310 void *cookie = stdev->recognition_cookie; 311 312 stdev->is_streaming = 1; 313 ALOGI("%s send callback model %d", __func__, 314 stdev->model_handle); 315 pthread_mutex_unlock(&stdev->lock); 316 if (callback != NULL) { 317 callback(&event->common, cookie); 318 } 319 pthread_mutex_lock(&stdev->lock); 320 free(event); 321 // Start reading data from the DSP while the upper levels do their thing. 322 if (stdev->config && stdev->config->capture_requested) { 323 fetch_streaming_buffer(stdev); 324 } 325 } 326 goto found; 327 } 328 i += strlen(msg + i) + 1; 329 } 330 } else if (fds[1].revents & POLLIN) { 331 read(fds[1].fd, &n, sizeof(n)); /* clear the socket */ 332 ALOGI("%s: Termination message", __func__); 333 break; 334 } else { 335 ALOGI("%s: Message to ignore", __func__); 336 } 337 pthread_mutex_unlock(&stdev->lock); 338 } 339 340 found: 341 close(fds[0].fd); 342 343 exit: 344 stdev->recognition_callback = NULL; 345 stdev_close_term_sock(stdev); 346 347 if (stdev->config && !stdev->config->capture_requested) 348 stdev_dsp_set_power(stdev, 0); 349 350 pthread_mutex_unlock(&stdev->lock); 351 352 return (void *)(long)err; 353 } 354 355 static int stdev_get_properties(const struct sound_trigger_hw_device *dev, 356 struct sound_trigger_properties *properties) 357 { 358 struct flounder_sound_trigger_device *stdev = 359 (struct flounder_sound_trigger_device *)dev; 360 361 ALOGI("%s", __func__); 362 if (properties == NULL) 363 return -EINVAL; 364 memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties)); 365 return 0; 366 } 367 368 static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev, 369 struct sound_trigger_sound_model *sound_model, 370 sound_model_callback_t callback, 371 void *cookie, 372 sound_model_handle_t *handle) 373 { 374 struct flounder_sound_trigger_device *stdev = 375 (struct flounder_sound_trigger_device *)dev; 376 int ret = 0; 377 378 ALOGI("%s", __func__); 379 pthread_mutex_lock(&stdev->lock); 380 if (handle == NULL || sound_model == NULL) { 381 ret = -EINVAL; 382 goto exit; 383 } 384 385 if (stdev->model_handle == 1) { 386 ret = -ENOSYS; 387 goto exit; 388 } 389 390 ret = vad_load_sound_model(stdev, 391 (char *)sound_model + sound_model->data_offset, 392 sound_model->data_size); 393 if (ret) 394 goto exit; 395 396 stdev->model_handle = 1; 397 stdev->sound_model_callback = callback; 398 stdev->sound_model_cookie = cookie; 399 *handle = stdev->model_handle; 400 401 exit: 402 pthread_mutex_unlock(&stdev->lock); 403 return ret; 404 } 405 406 static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev, 407 sound_model_handle_t handle) 408 { 409 struct flounder_sound_trigger_device *stdev = 410 (struct flounder_sound_trigger_device *)dev; 411 int status = 0; 412 413 ALOGI("%s handle %d", __func__, handle); 414 pthread_mutex_lock(&stdev->lock); 415 if (handle != 1) { 416 status = -EINVAL; 417 goto exit; 418 } 419 if (stdev->model_handle == 0) { 420 status = -ENOSYS; 421 goto exit; 422 } 423 stdev->model_handle = 0; 424 free(stdev->config); 425 stdev->config = NULL; 426 if (stdev->recognition_callback != NULL) { 427 stdev->recognition_callback = NULL; 428 if (stdev->send_sock >=0) 429 write(stdev->send_sock, "T", 1); 430 pthread_mutex_unlock(&stdev->lock); 431 432 pthread_join(stdev->callback_thread, (void **)NULL); 433 434 pthread_mutex_lock(&stdev->lock); 435 } 436 437 exit: 438 stdev_dsp_set_power(stdev, 0); 439 440 pthread_mutex_unlock(&stdev->lock); 441 return status; 442 } 443 444 static int stdev_start_recognition(const struct sound_trigger_hw_device *dev, 445 sound_model_handle_t sound_model_handle, 446 const struct sound_trigger_recognition_config *config, 447 recognition_callback_t callback, 448 void *cookie) 449 { 450 struct flounder_sound_trigger_device *stdev = 451 (struct flounder_sound_trigger_device *)dev; 452 int status = 0; 453 454 ALOGI("%s sound model %d", __func__, sound_model_handle); 455 pthread_mutex_lock(&stdev->lock); 456 if (stdev->model_handle != sound_model_handle) { 457 status = -ENOSYS; 458 goto exit; 459 } 460 if (stdev->recognition_callback != NULL) { 461 status = -ENOSYS; 462 goto exit; 463 } 464 465 free(stdev->config); 466 stdev->config = NULL; 467 if (config) { 468 stdev->config = malloc(sizeof(*config)); 469 if (!stdev->config) { 470 status = -ENOMEM; 471 goto exit; 472 } 473 memcpy(stdev->config, config, sizeof(*config)); 474 } 475 476 stdev_dsp_set_power(stdev, 0); 477 478 stdev->recognition_callback = callback; 479 stdev->recognition_cookie = cookie; 480 pthread_create(&stdev->callback_thread, (const pthread_attr_t *) NULL, 481 callback_thread_loop, stdev); 482 exit: 483 pthread_mutex_unlock(&stdev->lock); 484 return status; 485 } 486 487 static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev, 488 sound_model_handle_t sound_model_handle) 489 { 490 struct flounder_sound_trigger_device *stdev = 491 (struct flounder_sound_trigger_device *)dev; 492 int status = 0; 493 494 ALOGI("%s sound model %d", __func__, sound_model_handle); 495 pthread_mutex_lock(&stdev->lock); 496 if (stdev->model_handle != sound_model_handle) { 497 status = -ENOSYS; 498 goto exit; 499 } 500 if (stdev->recognition_callback == NULL) { 501 status = -ENOSYS; 502 goto exit; 503 } 504 free(stdev->config); 505 stdev->config = NULL; 506 stdev->recognition_callback = NULL; 507 if (stdev->send_sock >=0) 508 write(stdev->send_sock, "T", 1); 509 pthread_mutex_unlock(&stdev->lock); 510 511 pthread_join(stdev->callback_thread, (void **)NULL); 512 513 pthread_mutex_lock(&stdev->lock); 514 515 exit: 516 stdev_dsp_set_power(stdev, 0); 517 518 pthread_mutex_unlock(&stdev->lock); 519 return status; 520 } 521 522 __attribute__ ((visibility ("default"))) 523 int sound_trigger_open_for_streaming() 524 { 525 struct flounder_sound_trigger_device *stdev = &g_stdev; 526 int ret = 0; 527 528 pthread_mutex_lock(&stdev->lock); 529 530 if (!stdev->opened) { 531 ALOGE("%s: stdev has not been opened", __func__); 532 ret = -EFAULT; 533 goto exit; 534 } 535 if (!stdev->is_streaming) { 536 ALOGE("%s: DSP is not currently streaming", __func__); 537 ret = -EBUSY; 538 goto exit; 539 } 540 // TODO: Probably want to get something from whoever called us to bind to it/assert that it's a 541 // valid connection. Perhaps returning a more 542 // meaningful handle would be a good idea as well. 543 ret = 1; 544 exit: 545 pthread_mutex_unlock(&stdev->lock); 546 return ret; 547 } 548 549 __attribute__ ((visibility ("default"))) 550 size_t sound_trigger_read_samples(int audio_handle, void *buffer, size_t buffer_len) 551 { 552 struct flounder_sound_trigger_device *stdev = &g_stdev; 553 int i; 554 size_t ret = 0; 555 556 if (audio_handle <= 0) { 557 ALOGE("%s: invalid audio handle", __func__); 558 return -EINVAL; 559 } 560 561 pthread_mutex_lock(&stdev->lock); 562 563 if (!stdev->opened) { 564 ALOGE("%s: stdev has not been opened", __func__); 565 ret = -EFAULT; 566 goto exit; 567 } 568 if (!stdev->is_streaming) { 569 ALOGE("%s: DSP is not currently streaming", __func__); 570 ret = -EINVAL; 571 goto exit; 572 } 573 574 if (stdev->streaming_buf_read == stdev->streaming_buf_len) { 575 ret = fetch_streaming_buffer(stdev); 576 } 577 578 if (!ret) { 579 ret = stdev->streaming_buf_len - stdev->streaming_buf_read; 580 if (ret > buffer_len) 581 ret = buffer_len; 582 memcpy(buffer, stdev->streaming_buf + stdev->streaming_buf_read, ret); 583 stdev->streaming_buf_read += ret; 584 ALOGV("%s: Sent %zu bytes to buffer", __func__, ret); 585 } 586 587 exit: 588 pthread_mutex_unlock(&stdev->lock); 589 return ret; 590 } 591 592 __attribute__ ((visibility ("default"))) 593 int sound_trigger_close_for_streaming(int audio_handle __unused) 594 { 595 // TODO: Power down the DSP? I think we shouldn't in case we want to open this mic for streaming 596 // for the voice search? 597 return 0; 598 } 599 600 static int stdev_close(hw_device_t *device) 601 { 602 struct flounder_sound_trigger_device *stdev = 603 (struct flounder_sound_trigger_device *)device; 604 int ret = 0; 605 606 pthread_mutex_lock(&stdev->lock); 607 if (!stdev->opened) { 608 ALOGE("%s: device already closed", __func__); 609 ret = -EFAULT; 610 goto exit; 611 } 612 free(stdev->streaming_buf); 613 stdev_close_mixer(stdev); 614 stdev->model_handle = 0; 615 stdev->send_sock = 0; 616 stdev->term_sock = 0; 617 stdev->opened = false; 618 619 exit: 620 pthread_mutex_unlock(&stdev->lock); 621 return ret; 622 } 623 624 static int stdev_open(const hw_module_t *module, const char *name, 625 hw_device_t **device) 626 { 627 struct flounder_sound_trigger_device *stdev; 628 int ret; 629 630 if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0) 631 return -EINVAL; 632 633 stdev = &g_stdev; 634 pthread_mutex_lock(&stdev->lock); 635 636 if (stdev->opened) { 637 ALOGE("%s: Only one sountrigger can be opened at a time", __func__); 638 ret = -EBUSY; 639 goto exit; 640 } 641 642 stdev->streaming_buf = malloc(FLOUNDER_STREAMING_BUFFER_SIZE); 643 if (!stdev->streaming_buf) { 644 ret = -ENOMEM; 645 goto exit; 646 } 647 648 ret = stdev_init_mixer(stdev); 649 if (ret) { 650 ALOGE("Error mixer init"); 651 free(stdev->streaming_buf); 652 goto exit; 653 } 654 655 stdev->device.common.tag = HARDWARE_DEVICE_TAG; 656 stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0; 657 stdev->device.common.module = (struct hw_module_t *)module; 658 stdev->device.common.close = stdev_close; 659 stdev->device.get_properties = stdev_get_properties; 660 stdev->device.load_sound_model = stdev_load_sound_model; 661 stdev->device.unload_sound_model = stdev_unload_sound_model; 662 stdev->device.start_recognition = stdev_start_recognition; 663 stdev->device.stop_recognition = stdev_stop_recognition; 664 stdev->send_sock = stdev->term_sock = -1; 665 stdev->streaming_buf_read = 0; 666 stdev->streaming_buf_len = 0; 667 stdev->opened = true; 668 669 *device = &stdev->device.common; /* same address as stdev */ 670 exit: 671 pthread_mutex_unlock(&stdev->lock); 672 return ret; 673 } 674 675 static struct hw_module_methods_t hal_module_methods = { 676 .open = stdev_open, 677 }; 678 679 struct sound_trigger_module HAL_MODULE_INFO_SYM = { 680 .common = { 681 .tag = HARDWARE_MODULE_TAG, 682 .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0, 683 .hal_api_version = HARDWARE_HAL_API_VERSION, 684 .id = SOUND_TRIGGER_HARDWARE_MODULE_ID, 685 .name = "Default sound trigger HAL", 686 .author = "The Android Open Source Project", 687 .methods = &hal_module_methods, 688 }, 689 }; 690