1 /* 2 * Copyright (C) 2011 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 18 /* This HAL simulates triggers from the DSP. 19 * To send a trigger from the command line you can type: 20 * 21 * adb forward tcp:14035 tcp:14035 22 * 23 * telnet localhost 14035 24 * 25 * Commands include: 26 * ls : Lists all models that have been loaded. 27 * trig <uuid> : Sends a recognition event for the model at the given uuid 28 * update <uuid> : Sends a model update event for the model at the given uuid. 29 * close : Closes the network connection. 30 * 31 * To enable this file, you can make with command line parameter 32 * SOUND_TRIGGER_USE_STUB_MODULE=1 33 */ 34 35 #define LOG_TAG "sound_trigger_hw_default" 36 #define LOG_NDEBUG 1 37 #define PARSE_BUF_LEN 1024 // Length of the parsing buffer.S 38 39 #define EVENT_RECOGNITION 1 40 #define EVENT_SOUND_MODEL 2 41 42 // The following commands work with the network port: 43 #define COMMAND_LS "ls" 44 #define COMMAND_RECOGNITION_TRIGGER "trig" // Argument: model index. 45 #define COMMAND_RECOGNITION_ABORT "abort" // Argument: model index. 46 #define COMMAND_RECOGNITION_FAILURE "fail" // Argument: model index. 47 #define COMMAND_UPDATE "update" // Argument: model index. 48 #define COMMAND_CLEAR "clear" // Removes all models from the list. 49 #define COMMAND_CLOSE "close" // Close just closes the network port, keeps thread running. 50 #define COMMAND_END "end" // Closes connection and stops the thread. 51 52 #define ERROR_BAD_COMMAND "Bad command" 53 54 #include <errno.h> 55 #include <stdarg.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <unistd.h> 60 #include <arpa/inet.h> 61 #include <sys/types.h> 62 #include <netinet/in.h> 63 #include <sys/socket.h> 64 65 #include <errno.h> 66 #include <pthread.h> 67 #include <sys/prctl.h> 68 #include <cutils/log.h> 69 70 #include <hardware/hardware.h> 71 #include <system/sound_trigger.h> 72 #include <hardware/sound_trigger.h> 73 74 static const struct sound_trigger_properties hw_properties = { 75 "The Android Open Source Project", // implementor 76 "Sound Trigger stub HAL", // description 77 1, // version 78 { 0xed7a7d60, 0xc65e, 0x11e3, 0x9be4, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid 79 4, // max_sound_models 80 1, // max_key_phrases 81 1, // max_users 82 RECOGNITION_MODE_VOICE_TRIGGER, // recognition_modes 83 false, // capture_transition 84 0, // max_buffer_ms 85 true, // concurrent_capture 86 false, // trigger_in_event 87 0 // power_consumption_mw 88 }; 89 90 struct recognition_context { 91 // Sound Model information, added in method load_sound_model 92 sound_model_handle_t model_handle; 93 sound_trigger_uuid_t model_uuid; 94 sound_trigger_sound_model_type_t model_type; 95 sound_model_callback_t model_callback; 96 void *model_cookie; 97 98 // Sound Model information, added in start_recognition 99 struct sound_trigger_recognition_config *config; 100 recognition_callback_t recognition_callback; 101 void *recognition_cookie; 102 103 bool model_started; 104 105 // Next recognition_context in the linked list 106 struct recognition_context *next; 107 }; 108 109 char tmp_write_buffer[PARSE_BUF_LEN]; 110 111 struct stub_sound_trigger_device { 112 struct sound_trigger_hw_device device; 113 pthread_mutex_t lock; 114 115 // This thread opens a port that can be used to monitor and inject events 116 // into the stub HAL. 117 pthread_t control_thread; 118 119 // Recognition contexts are stored as a linked list 120 struct recognition_context *root_model_context; 121 122 int next_sound_model_id; 123 }; 124 125 static bool check_uuid_equality(sound_trigger_uuid_t uuid1, sound_trigger_uuid_t uuid2) { 126 if (uuid1.timeLow != uuid2.timeLow || 127 uuid1.timeMid != uuid2.timeMid || 128 uuid1.timeHiAndVersion != uuid2.timeHiAndVersion || 129 uuid1.clockSeq != uuid2.clockSeq) { 130 return false; 131 } 132 for (int i = 0; i < 6; i++) { 133 if(uuid1.node[i] != uuid2.node[i]) { 134 return false; 135 } 136 } 137 return true; 138 } 139 140 bool str_to_uuid(char* uuid_str, sound_trigger_uuid_t* uuid) { 141 if (uuid_str == NULL) { 142 ALOGI("Invalid str_to_uuid input."); 143 return false; 144 } 145 146 int tmp[10]; 147 if (sscanf(uuid_str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", 148 tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) { 149 ALOGI("Invalid UUID, got: %s", uuid_str); 150 return false; 151 } 152 uuid->timeLow = (unsigned int)tmp[0]; 153 uuid->timeMid = (unsigned short)tmp[1]; 154 uuid->timeHiAndVersion = (unsigned short)tmp[2]; 155 uuid->clockSeq = (unsigned short)tmp[3]; 156 uuid->node[0] = (unsigned char)tmp[4]; 157 uuid->node[1] = (unsigned char)tmp[5]; 158 uuid->node[2] = (unsigned char)tmp[6]; 159 uuid->node[3] = (unsigned char)tmp[7]; 160 uuid->node[4] = (unsigned char)tmp[8]; 161 uuid->node[5] = (unsigned char)tmp[9]; 162 return true; 163 } 164 165 void write_bad_command_error(int conn_socket, char* command) { 166 int num = snprintf(tmp_write_buffer, PARSE_BUF_LEN, "Bad command received: %s", command); 167 tmp_write_buffer[PARSE_BUF_LEN - 1] = '\0'; // Just to be sure. 168 tmp_write_buffer[PARSE_BUF_LEN - 2] = '\n'; 169 write(conn_socket, tmp_write_buffer, num); 170 } 171 172 void write_string(int conn_socket, char* str) { 173 int num = snprintf(tmp_write_buffer, PARSE_BUF_LEN, "%s", str); 174 tmp_write_buffer[PARSE_BUF_LEN - 1] = '\0'; 175 tmp_write_buffer[PARSE_BUF_LEN - 2] = '\n'; 176 write(conn_socket, tmp_write_buffer, num); 177 } 178 179 void write_vastr(int conn_socket, char* format, ...) { 180 va_list argptr; 181 va_start(argptr, format); 182 int num = vsnprintf(tmp_write_buffer, PARSE_BUF_LEN, format, argptr); 183 va_end(argptr); 184 tmp_write_buffer[PARSE_BUF_LEN - 1] = '\0'; 185 tmp_write_buffer[PARSE_BUF_LEN - 2] = '\n'; 186 write(conn_socket, tmp_write_buffer, num); 187 } 188 189 static void print_uuid(sound_trigger_uuid_t uuid) { 190 ALOGI("%s %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", __func__, uuid.timeLow, uuid.timeMid, 191 uuid.timeHiAndVersion, uuid.clockSeq, uuid.node[0], uuid.node[1], uuid.node[2], 192 uuid.node[3], uuid.node[4], uuid.node[5]); 193 } 194 195 static void write_uuid(int conn_socket, sound_trigger_uuid_t uuid) { 196 write_vastr(conn_socket, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n", uuid.timeLow, uuid.timeMid, 197 uuid.timeHiAndVersion, uuid.clockSeq, uuid.node[0], uuid.node[1], uuid.node[2], 198 uuid.node[3], uuid.node[4], uuid.node[5]); 199 } 200 201 // Returns model at the given index, null otherwise (error, doesn't exist, etc). 202 // Note that here index starts from zero. 203 struct recognition_context* fetch_model_with_handle( 204 struct stub_sound_trigger_device* stdev, sound_model_handle_t* model_handle) { 205 ALOGI("%s", __func__); 206 struct recognition_context *model_context = NULL; 207 struct recognition_context *last_model_context = stdev->root_model_context; 208 while(last_model_context) { 209 if (last_model_context->model_handle == *model_handle) { 210 model_context = last_model_context; 211 break; 212 } 213 last_model_context = last_model_context->next; 214 } 215 return model_context; 216 } 217 218 // Returns the first model that matches the sound model UUID. 219 static sound_model_handle_t* get_model_handle_with_uuid(struct stub_sound_trigger_device* stdev, 220 sound_trigger_uuid_t uuid) { 221 sound_model_handle_t* model_handle_str = NULL; 222 struct recognition_context *last_model_context = stdev->root_model_context; 223 while(last_model_context) { 224 if (check_uuid_equality(last_model_context->model_uuid, uuid)) { 225 model_handle_str = &last_model_context->model_handle; 226 break; 227 } 228 last_model_context = last_model_context->next; 229 } 230 return model_handle_str; 231 } 232 233 /* Will reuse ids when overflow occurs */ 234 static sound_model_handle_t generate_sound_model_handle(const struct sound_trigger_hw_device *dev) { 235 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev; 236 int new_id = stdev->next_sound_model_id; 237 ++stdev->next_sound_model_id; 238 if (stdev->next_sound_model_id == 0) { 239 stdev->next_sound_model_id = 1; 240 } 241 return (sound_model_handle_t) new_id; 242 } 243 244 bool parse_socket_data(int conn_socket, struct stub_sound_trigger_device* stdev); 245 static void unload_all_sound_models(struct stub_sound_trigger_device *stdev); 246 247 static char *sound_trigger_keyphrase_event_alloc(sound_model_handle_t handle, 248 struct sound_trigger_recognition_config *config, 249 int recognition_status) { 250 char *data; 251 struct sound_trigger_phrase_recognition_event *event; 252 data = (char *)calloc(1, sizeof(struct sound_trigger_phrase_recognition_event)); 253 if (!data) 254 return NULL; 255 event = (struct sound_trigger_phrase_recognition_event *)data; 256 event->common.status = recognition_status; 257 event->common.type = SOUND_MODEL_TYPE_KEYPHRASE; 258 event->common.model = handle; 259 260 if (config) { 261 unsigned int i; 262 263 event->num_phrases = config->num_phrases; 264 if (event->num_phrases > SOUND_TRIGGER_MAX_PHRASES) 265 event->num_phrases = SOUND_TRIGGER_MAX_PHRASES; 266 for (i=0; i < event->num_phrases; i++) 267 memcpy(&event->phrase_extras[i], 268 &config->phrases[i], 269 sizeof(struct sound_trigger_phrase_recognition_extra)); 270 } 271 272 event->num_phrases = 1; 273 event->phrase_extras[0].confidence_level = 100; 274 event->phrase_extras[0].num_levels = 1; 275 event->phrase_extras[0].levels[0].level = 100; 276 event->phrase_extras[0].levels[0].user_id = 0; 277 // Signify that all the data is comming through streaming, not through the buffer. 278 event->common.capture_available = true; 279 event->common.audio_config = AUDIO_CONFIG_INITIALIZER; 280 event->common.audio_config.sample_rate = 16000; 281 event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO; 282 event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT; 283 return data; 284 } 285 286 static char *sound_trigger_generic_event_alloc(sound_model_handle_t handle, 287 struct sound_trigger_recognition_config *config, 288 int recognition_status) { 289 char *data; 290 struct sound_trigger_generic_recognition_event *event; 291 data = (char *)calloc(1, sizeof(struct sound_trigger_generic_recognition_event)); 292 if (!data) 293 return NULL; 294 event = (struct sound_trigger_generic_recognition_event *)data; 295 event->common.status = recognition_status; 296 event->common.type = SOUND_MODEL_TYPE_GENERIC; 297 event->common.model = handle; 298 299 // Signify that all the data is comming through streaming, not through the buffer. 300 event->common.capture_available = true; 301 event->common.audio_config = AUDIO_CONFIG_INITIALIZER; 302 event->common.audio_config.sample_rate = 16000; 303 event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO; 304 event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT; 305 return data; 306 } 307 308 void send_event_with_handle(sound_model_handle_t* model_handle_str, 309 struct stub_sound_trigger_device* stdev, int event_type, 310 int status) { 311 ALOGI("%s", __func__); 312 struct recognition_context *model_context = fetch_model_with_handle(stdev, model_handle_str); 313 if (model_context) { 314 if (event_type == EVENT_RECOGNITION) { 315 if (model_context->recognition_callback == NULL) { 316 ALOGI("%s No matching callback", __func__); 317 return; 318 } 319 320 if (model_context->model_type == SOUND_MODEL_TYPE_KEYPHRASE) { 321 struct sound_trigger_phrase_recognition_event *event; 322 event = (struct sound_trigger_phrase_recognition_event *) 323 sound_trigger_keyphrase_event_alloc(model_context->model_handle, 324 model_context->config, status); 325 if (event) { 326 model_context->recognition_callback(event, model_context->recognition_cookie); 327 free(event); 328 } 329 } else if (model_context->model_type == SOUND_MODEL_TYPE_GENERIC) { 330 struct sound_trigger_generic_recognition_event *event; 331 event = (struct sound_trigger_generic_recognition_event *) 332 sound_trigger_generic_event_alloc(model_context->model_handle, 333 model_context->config, status); 334 if (event) { 335 model_context->recognition_callback(event, model_context->recognition_cookie); 336 free(event); 337 } 338 } else { 339 ALOGI("Unknown Sound Model Type, No Event to Send"); 340 } 341 } else if (event_type == EVENT_SOUND_MODEL) { 342 char *data; 343 data = (char *)calloc(1, sizeof(struct sound_trigger_model_event)); 344 if (!data) { 345 ALOGW("%s Could not allocate event", __func__); 346 return; 347 } 348 349 struct sound_trigger_model_event *event; 350 event = (struct sound_trigger_model_event *)data; 351 event->status = SOUND_MODEL_STATUS_UPDATED; 352 event->model = model_context->model_handle; 353 if (event) { 354 model_context->model_callback(&event, model_context->model_cookie); 355 free(event); 356 } 357 } 358 } else { 359 ALOGI("No model for this handle"); 360 } 361 } 362 363 static void send_event(int conn_socket, struct stub_sound_trigger_device* stdev, int event_type, 364 int status) { 365 char* model_uuid_str = strtok(NULL, " \r\n"); 366 sound_trigger_uuid_t model_uuid; 367 if (str_to_uuid(model_uuid_str, &model_uuid)) { 368 sound_model_handle_t* model_handle_str = get_model_handle_with_uuid(stdev, model_uuid); 369 if (model_handle_str == NULL) { 370 ALOGI("%s Bad sound model handle.", __func__); 371 write_string(conn_socket, "Bad sound model handle.\n"); 372 return; 373 } 374 send_event_with_handle(model_handle_str, stdev, event_type, status); 375 } else { 376 ALOGI("%s Not a valid UUID", __func__); 377 write_string(conn_socket, "Not a valid UUID.\n"); 378 } 379 } 380 381 static bool recognition_callback_exists(struct stub_sound_trigger_device *stdev) { 382 bool callback_found = false; 383 if (stdev->root_model_context) { 384 struct recognition_context *current_model_context = stdev->root_model_context; 385 while(current_model_context) { 386 if (current_model_context->recognition_callback != NULL) { 387 callback_found = true; 388 break; 389 } 390 current_model_context = current_model_context->next; 391 } 392 } 393 return callback_found; 394 } 395 396 static struct recognition_context * get_model_context(struct stub_sound_trigger_device *stdev, 397 sound_model_handle_t handle) { 398 struct recognition_context *model_context = NULL; 399 if (stdev->root_model_context) { 400 struct recognition_context *current_model_context = stdev->root_model_context; 401 while(current_model_context) { 402 if (current_model_context->model_handle == handle) { 403 model_context = current_model_context; 404 break; 405 } 406 current_model_context = current_model_context->next; 407 } 408 } 409 return model_context; 410 } 411 412 static void *control_thread_loop(void *context) { 413 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)context; 414 struct sockaddr_in incoming_info; 415 struct sockaddr_in self_info; 416 int self_socket; 417 socklen_t sock_size = sizeof(struct sockaddr_in); 418 memset(&self_info, 0, sizeof(self_info)); 419 self_info.sin_family = AF_INET; 420 self_info.sin_addr.s_addr = htonl(INADDR_ANY); 421 self_info.sin_port = htons(14035); 422 423 bool exit = false; 424 while(!exit) { 425 int received_count; 426 int requested_count = 2; 427 char buffer[requested_count]; 428 ALOGE("Opening socket"); 429 self_socket = socket(AF_INET, SOCK_STREAM, 0); 430 if (self_socket < 0) { 431 ALOGE("Error on socket creation: %s", strerror(errno)); 432 exit = true; 433 } else { 434 ALOGI("Socket created"); 435 } 436 437 int reuse = 1; 438 if (setsockopt(self_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) { 439 ALOGE("setsockopt(SO_REUSEADDR) failed"); 440 } 441 442 int bind_result = bind(self_socket, (struct sockaddr *)&self_info, sizeof(struct sockaddr)); 443 if (bind_result < 0) { 444 ALOGE("Error on bind"); 445 exit = true; 446 } 447 448 int listen_result = listen(self_socket, 1); 449 if (listen_result < 0) { 450 ALOGE("Error on Listen"); 451 exit = true; 452 } 453 454 while(!exit) { 455 int con_socket = accept(self_socket, (struct sockaddr *)&incoming_info, &sock_size); 456 if (!con_socket) { 457 ALOGE("Lost socket, cannot send trigger"); 458 break; 459 } 460 ALOGI("Connection from %s", inet_ntoa(incoming_info.sin_addr)); 461 if (!parse_socket_data(con_socket, stdev)) { 462 ALOGI("Done processing commands over network. Stopping thread."); 463 exit = true; 464 } 465 close(con_socket); 466 } 467 ALOGE("Closing socket"); 468 close(self_socket); 469 } 470 471 return NULL; 472 } 473 474 void list_models(int conn_socket, char* buffer, 475 struct stub_sound_trigger_device* stdev) { 476 ALOGI("%s", __func__); 477 struct recognition_context *last_model_context = stdev->root_model_context; 478 unsigned int model_index = 0; 479 write_string(conn_socket, "-----------------------\n"); 480 if (!last_model_context) { 481 ALOGI("ZERO Models exist."); 482 write_string(conn_socket, "Zero models exist.\n"); 483 } 484 while (last_model_context) { 485 write_vastr(conn_socket, "Model Index: %d\n", model_index); 486 ALOGI("Model Index: %d", model_index); 487 write_vastr(conn_socket, "Model handle: %d\n", last_model_context->model_handle); 488 ALOGI("Model handle: %d", last_model_context->model_handle); 489 write_uuid(conn_socket, last_model_context->model_uuid); 490 print_uuid(last_model_context->model_uuid); 491 sound_trigger_sound_model_type_t model_type = last_model_context->model_type; 492 493 if (model_type == SOUND_MODEL_TYPE_KEYPHRASE) { 494 write_string(conn_socket, "Keyphrase sound Model.\n"); 495 ALOGI("Keyphrase sound Model."); 496 } else if (model_type == SOUND_MODEL_TYPE_GENERIC) { 497 write_string(conn_socket, "Generic sound Model.\n"); 498 ALOGI("Generic sound Model."); 499 } else { 500 write_vastr(conn_socket, "Unknown sound model type: %d\n", model_type); 501 ALOGI("Unknown sound model type: %d", model_type); 502 } 503 if (last_model_context->model_started) { 504 write_string(conn_socket, "Model started.\n"); 505 ALOGI("Model started.\n"); 506 } else { 507 write_string(conn_socket, "Model stopped.\n"); 508 ALOGI("Model stopped.\n"); 509 } 510 write_string(conn_socket, "-----------------------\n\n"); 511 ALOGI("----\n\n"); 512 last_model_context = last_model_context->next; 513 model_index++; 514 } 515 } 516 517 // Gets the next word from buffer, replaces '\n' or ' ' with '\0'. 518 char* get_command(char* buffer) { 519 char* command = strtok(buffer, " "); 520 char* newline = strchr(command, '\n'); 521 if (newline != NULL) { 522 *newline = '\0'; 523 } 524 return command; 525 } 526 527 // Parses data coming in from the local socket, executes commands. Returns when 528 // done. Return code indicates whether the server should continue listening or 529 // abort (true if continue listening). 530 bool parse_socket_data(int conn_socket, struct stub_sound_trigger_device* stdev) { 531 ALOGI("Calling parse_socket_data"); 532 bool input_done = false; 533 char buffer[PARSE_BUF_LEN]; 534 FILE* input_fp = fdopen(conn_socket, "r"); 535 bool continue_listening = true; 536 537 // Note: Since we acquire a lock inside this loop, do not use break or other 538 // exit methods without releasing this lock. 539 write_string(conn_socket, "\n>>> "); 540 while(!input_done) { 541 if (fgets(buffer, PARSE_BUF_LEN, input_fp) != NULL) { 542 pthread_mutex_lock(&stdev->lock); 543 char* command = strtok(buffer, " \r\n"); 544 if (command == NULL) { 545 write_bad_command_error(conn_socket, command); 546 } else if (strncmp(command, COMMAND_LS, 2) == 0) { 547 list_models(conn_socket, buffer, stdev); 548 } else if (strcmp(command, COMMAND_RECOGNITION_TRIGGER) == 0) { 549 send_event(conn_socket, stdev, EVENT_RECOGNITION, RECOGNITION_STATUS_SUCCESS); 550 } else if (strcmp(command, COMMAND_RECOGNITION_ABORT) == 0) { 551 send_event(conn_socket, stdev, EVENT_RECOGNITION, RECOGNITION_STATUS_ABORT); 552 } else if (strcmp(command, COMMAND_RECOGNITION_FAILURE) == 0) { 553 send_event(conn_socket, stdev, EVENT_RECOGNITION, RECOGNITION_STATUS_FAILURE); 554 } else if (strcmp(command, COMMAND_UPDATE) == 0) { 555 send_event(conn_socket, stdev, EVENT_SOUND_MODEL, SOUND_MODEL_STATUS_UPDATED); 556 } else if (strncmp(command, COMMAND_CLEAR, 5) == 0) { 557 unload_all_sound_models(stdev); 558 } else if (strncmp(command, COMMAND_CLOSE, 5) == 0) { 559 ALOGI("Closing this connection."); 560 write_string(conn_socket, "Closing this connection."); 561 input_done = true; 562 } else if (strncmp(command, COMMAND_END, 3) == 0) { 563 ALOGI("End command received."); 564 write_string(conn_socket, "End command received. Stopping connection."); 565 continue_listening = false; 566 input_done = true; 567 } else { 568 write_vastr(conn_socket, "\nBad command %s.\n\n", command); 569 } 570 pthread_mutex_unlock(&stdev->lock); 571 } else { 572 ALOGI("parse_socket_data done (got null)"); 573 input_done = true; // break. 574 } 575 write_string(conn_socket, "\n>>> "); 576 } 577 return continue_listening; 578 } 579 580 static void send_loop_kill_signal() { 581 ALOGI("Sending loop thread kill signal"); 582 int self_socket = socket(AF_INET, SOCK_STREAM, 0); 583 struct sockaddr_in remote_info; 584 memset(&remote_info, 0, sizeof(remote_info)); 585 remote_info.sin_family = AF_INET; 586 remote_info.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 587 remote_info.sin_port = htons(14035); 588 if (connect(self_socket, (struct sockaddr *)&remote_info, sizeof(struct sockaddr)) == 0) { 589 send(self_socket, COMMAND_END, 3, 0); 590 } else { 591 ALOGI("Could not connect"); 592 } 593 close(self_socket); 594 ALOGI("Sent loop thread kill signal"); 595 } 596 597 static int stdev_get_properties(const struct sound_trigger_hw_device *dev, 598 struct sound_trigger_properties *properties) { 599 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev; 600 601 ALOGI("%s", __func__); 602 if (properties == NULL) 603 return -EINVAL; 604 memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties)); 605 return 0; 606 } 607 608 static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev, 609 struct sound_trigger_sound_model *sound_model, 610 sound_model_callback_t callback, 611 void *cookie, 612 sound_model_handle_t *handle) { 613 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev; 614 ALOGI("%s stdev %p", __func__, stdev); 615 int status = 0; 616 pthread_mutex_lock(&stdev->lock); 617 618 if (handle == NULL || sound_model == NULL) { 619 pthread_mutex_unlock(&stdev->lock); 620 return -EINVAL; 621 } 622 if (sound_model->data_size == 0 || 623 sound_model->data_offset < sizeof(struct sound_trigger_sound_model)) { 624 pthread_mutex_unlock(&stdev->lock); 625 return -EINVAL; 626 } 627 628 struct recognition_context *model_context; 629 model_context = malloc(sizeof(struct recognition_context)); 630 if(!model_context) { 631 ALOGW("Could not allocate recognition_context"); 632 pthread_mutex_unlock(&stdev->lock); 633 return -ENOSYS; 634 } 635 636 // Add the new model context to the recognition_context linked list 637 if (stdev->root_model_context) { 638 // Find the tail 639 struct recognition_context *current_model_context = stdev->root_model_context; 640 unsigned int model_count = 0; 641 while(current_model_context->next) { 642 current_model_context = current_model_context->next; 643 model_count++; 644 if (model_count >= hw_properties.max_sound_models) { 645 ALOGW("Can't load model: reached max sound model limit"); 646 free(model_context); 647 pthread_mutex_unlock(&stdev->lock); 648 return -ENOSYS; 649 } 650 } 651 current_model_context->next = model_context; 652 } else { 653 stdev->root_model_context = model_context; 654 } 655 656 model_context->model_handle = generate_sound_model_handle(dev); 657 *handle = model_context->model_handle; 658 model_context->model_type = sound_model->type; 659 660 char *data = (char *)sound_model + sound_model->data_offset; 661 ALOGI("%s data size %d data %d - %d", __func__, 662 sound_model->data_size, data[0], data[sound_model->data_size - 1]); 663 model_context->model_uuid = sound_model->uuid; 664 model_context->model_callback = callback; 665 model_context->model_cookie = cookie; 666 model_context->config = NULL; 667 model_context->recognition_callback = NULL; 668 model_context->recognition_cookie = NULL; 669 model_context->next = NULL; 670 model_context->model_started = false; 671 ALOGI("Sound model loaded: Handle %d ", *handle); 672 673 pthread_mutex_unlock(&stdev->lock); 674 return status; 675 } 676 677 static void unload_all_sound_models(struct stub_sound_trigger_device *stdev) { 678 ALOGI("%s", __func__); 679 struct recognition_context *model_context = stdev->root_model_context; 680 stdev->root_model_context = NULL; 681 pthread_mutex_lock(&stdev->lock); 682 while (model_context) { 683 ALOGI("Deleting model with handle: %d", model_context->model_handle); 684 struct recognition_context *temp = model_context; 685 model_context = model_context->next; 686 free(temp->config); 687 free(temp); 688 } 689 pthread_mutex_unlock(&stdev->lock); 690 } 691 692 static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev, 693 sound_model_handle_t handle) { 694 // If recognizing, stop_recognition must be called for a sound model before unload_sound_model 695 ALOGI("%s", __func__); 696 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev; 697 int status = 0; 698 ALOGI("unload_sound_model:%d", handle); 699 pthread_mutex_lock(&stdev->lock); 700 701 struct recognition_context *model_context = NULL; 702 struct recognition_context *previous_model_context = NULL; 703 if (stdev->root_model_context) { 704 struct recognition_context *current_model_context = stdev->root_model_context; 705 while(current_model_context) { 706 if (current_model_context->model_handle == handle) { 707 model_context = current_model_context; 708 break; 709 } 710 previous_model_context = current_model_context; 711 current_model_context = current_model_context->next; 712 } 713 } 714 if (!model_context) { 715 ALOGW("Can't find sound model handle %d in registered list", handle); 716 pthread_mutex_unlock(&stdev->lock); 717 return -ENOSYS; 718 } 719 if (previous_model_context) { 720 previous_model_context->next = model_context->next; 721 } else { 722 stdev->root_model_context = model_context->next; 723 } 724 free(model_context->config); 725 free(model_context); 726 pthread_mutex_unlock(&stdev->lock); 727 return status; 728 } 729 730 static int stdev_start_recognition(const struct sound_trigger_hw_device *dev, 731 sound_model_handle_t handle, 732 const struct sound_trigger_recognition_config *config, 733 recognition_callback_t callback, 734 void *cookie) { 735 ALOGI("%s", __func__); 736 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev; 737 pthread_mutex_lock(&stdev->lock); 738 739 /* If other models running with callbacks, don't start trigger thread */ 740 bool other_callbacks_found = recognition_callback_exists(stdev); 741 742 struct recognition_context *model_context = get_model_context(stdev, handle); 743 if (!model_context) { 744 ALOGW("Can't find sound model handle %d in registered list", handle); 745 pthread_mutex_unlock(&stdev->lock); 746 return -ENOSYS; 747 } 748 749 free(model_context->config); 750 model_context->config = NULL; 751 if (config) { 752 model_context->config = malloc(sizeof(*config)); 753 if (!model_context->config) { 754 pthread_mutex_unlock(&stdev->lock); 755 return -ENOMEM; 756 } 757 memcpy(model_context->config, config, sizeof(*config)); 758 } 759 model_context->recognition_callback = callback; 760 model_context->recognition_cookie = cookie; 761 model_context->model_started = true; 762 763 pthread_mutex_unlock(&stdev->lock); 764 ALOGI("%s done for handle %d", __func__, handle); 765 return 0; 766 } 767 768 static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev, 769 sound_model_handle_t handle) { 770 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev; 771 ALOGI("%s", __func__); 772 pthread_mutex_lock(&stdev->lock); 773 774 struct recognition_context *model_context = get_model_context(stdev, handle); 775 if (!model_context) { 776 ALOGW("Can't find sound model handle %d in registered list", handle); 777 pthread_mutex_unlock(&stdev->lock); 778 return -ENOSYS; 779 } 780 781 free(model_context->config); 782 model_context->config = NULL; 783 model_context->recognition_callback = NULL; 784 model_context->recognition_cookie = NULL; 785 model_context->model_started = false; 786 787 pthread_mutex_unlock(&stdev->lock); 788 ALOGI("%s done for handle %d", __func__, handle); 789 790 return 0; 791 } 792 793 static int stdev_stop_all_recognitions(const struct sound_trigger_hw_device *dev) { 794 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev; 795 ALOGI("%s", __func__); 796 pthread_mutex_lock(&stdev->lock); 797 798 struct recognition_context *model_context = stdev->root_model_context; 799 while (model_context) { 800 free(model_context->config); 801 model_context->config = NULL; 802 model_context->recognition_callback = NULL; 803 model_context->recognition_cookie = NULL; 804 model_context->model_started = false; 805 ALOGI("%s stopped handle %d", __func__, model_context->model_handle); 806 807 model_context = model_context->next; 808 } 809 810 pthread_mutex_unlock(&stdev->lock); 811 812 return 0; 813 } 814 815 __attribute__ ((visibility ("default"))) 816 int sound_trigger_open_for_streaming() { 817 int ret = 0; 818 return ret; 819 } 820 821 __attribute__ ((visibility ("default"))) 822 size_t sound_trigger_read_samples(int audio_handle, void *buffer, size_t buffer_len) { 823 size_t ret = 0; 824 return ret; 825 } 826 827 __attribute__ ((visibility ("default"))) 828 int sound_trigger_close_for_streaming(int audio_handle __unused) { 829 return 0; 830 } 831 832 static int stdev_close(hw_device_t *device) { 833 // TODO: Implement the ability to stop the control thread. Since this is a 834 // test hal, we have skipped implementing this for now. A possible method 835 // would register a signal handler for the control thread so that any 836 // blocking socket calls can be interrupted. We would send that signal here 837 // to interrupt and quit the thread. 838 free(device); 839 return 0; 840 } 841 842 static int stdev_open(const hw_module_t* module, const char* name, 843 hw_device_t** device) { 844 struct stub_sound_trigger_device *stdev; 845 int ret; 846 847 if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0) 848 return -EINVAL; 849 850 stdev = calloc(1, sizeof(struct stub_sound_trigger_device)); 851 if (!stdev) 852 return -ENOMEM; 853 854 stdev->next_sound_model_id = 1; 855 stdev->root_model_context = NULL; 856 857 stdev->device.common.tag = HARDWARE_DEVICE_TAG; 858 stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_1; 859 stdev->device.common.module = (struct hw_module_t *) module; 860 stdev->device.common.close = stdev_close; 861 stdev->device.get_properties = stdev_get_properties; 862 stdev->device.load_sound_model = stdev_load_sound_model; 863 stdev->device.unload_sound_model = stdev_unload_sound_model; 864 stdev->device.start_recognition = stdev_start_recognition; 865 stdev->device.stop_recognition = stdev_stop_recognition; 866 stdev->device.stop_all_recognitions = stdev_stop_all_recognitions; 867 868 pthread_mutex_init(&stdev->lock, (const pthread_mutexattr_t *) NULL); 869 870 *device = &stdev->device.common; 871 872 pthread_create(&stdev->control_thread, (const pthread_attr_t *) NULL, 873 control_thread_loop, stdev); 874 ALOGI("Starting control thread for the stub hal."); 875 876 return 0; 877 } 878 879 static struct hw_module_methods_t hal_module_methods = { 880 .open = stdev_open, 881 }; 882 883 struct sound_trigger_module HAL_MODULE_INFO_SYM = { 884 .common = { 885 .tag = HARDWARE_MODULE_TAG, 886 .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0, 887 .hal_api_version = HARDWARE_HAL_API_VERSION, 888 .id = SOUND_TRIGGER_HARDWARE_MODULE_ID, 889 .name = "Default sound trigger HAL", 890 .author = "The Android Open Source Project", 891 .methods = &hal_module_methods, 892 }, 893 }; 894 895