blob: c7739cccaa750977bf09d2469952be9cdbea94df [file] [log] [blame]
Eric Laurentcbca9052014-04-18 17:54:10 -07001/*
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
Ryan Bavetta4615aad2016-01-27 16:12:04 -080017
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
Ryan Bavetta4615aad2016-01-27 16:12:04 -080022 *
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -080023 * telnet localhost 14035
Ryan Bavetta4615aad2016-01-27 16:12:04 -080024 *
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -080025 * Commands include:
26 * ls : Lists all models that have been loaded.
27 * trig <index> : Sends a recognition event for the model at the given index.
28 * update <index> : Sends a model update event for the model at the given index.
29 * close : Closes the network connection.
Ryan Bavettac2bdc552016-02-15 15:51:46 -080030 *
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -080031 * To enable this file, you can make with command line parameter
32 * SOUND_TRIGGER_USE_STUB_MODULE=1
Ryan Bavetta4615aad2016-01-27 16:12:04 -080033 */
34
Eric Laurentcbca9052014-04-18 17:54:10 -070035#define LOG_TAG "sound_trigger_hw_default"
Ryan Bavettacc6541c2016-02-09 21:20:51 -080036#define LOG_NDEBUG 1
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -080037#define PARSE_BUF_LEN 1024 // Length of the parsing buffer.S
38
39// The following commands work with the network port:
40#define COMMAND_LS "ls"
Ryan Bavetta9beb06c2016-02-29 18:37:29 -080041#define COMMAND_RECOGNITION_TRIGGER "trig" // Argument: model index.
42#define COMMAND_RECOGNITION_ABORT "abort" // Argument: model index.
43#define COMMAND_RECOGNITION_FAILURE "fail" // Argument: model index.
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -080044#define COMMAND_UPDATE "update" // Argument: model index.
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -080045#define COMMAND_CLOSE "close" // Close just closes the network port, keeps thread running.
46#define COMMAND_END "end" // Closes connection and stops the thread.
47
48#define ERROR_BAD_COMMAND "Bad command"
Eric Laurentcbca9052014-04-18 17:54:10 -070049
50#include <errno.h>
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -080051#include <stdarg.h>
Ryan Bavetta4615aad2016-01-27 16:12:04 -080052#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <unistd.h>
56#include <arpa/inet.h>
57#include <sys/types.h>
58#include <netinet/in.h>
59#include <sys/socket.h>
60
61#include <errno.h>
Eric Laurentcbca9052014-04-18 17:54:10 -070062#include <pthread.h>
63#include <sys/prctl.h>
64#include <cutils/log.h>
65
66#include <hardware/hardware.h>
67#include <system/sound_trigger.h>
68#include <hardware/sound_trigger.h>
69
70static const struct sound_trigger_properties hw_properties = {
71 "The Android Open Source Project", // implementor
72 "Sound Trigger stub HAL", // description
73 1, // version
74 { 0xed7a7d60, 0xc65e, 0x11e3, 0x9be4, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -080075 4, // max_sound_models
Eric Laurentcbca9052014-04-18 17:54:10 -070076 1, // max_key_phrases
77 1, // max_users
78 RECOGNITION_MODE_VOICE_TRIGGER, // recognition_modes
79 false, // capture_transition
80 0, // max_buffer_ms
Ryan Bavetta9beb06c2016-02-29 18:37:29 -080081 true, // concurrent_capture
Eric Laurent83cd8302014-07-30 08:58:39 -070082 false, // trigger_in_event
Eric Laurentcbca9052014-04-18 17:54:10 -070083 0 // power_consumption_mw
84};
85
Ryan Bavetta4615aad2016-01-27 16:12:04 -080086struct recognition_context {
Ryan Bavettacc6541c2016-02-09 21:20:51 -080087 // Sound Model information, added in method load_sound_model
88 sound_model_handle_t model_handle;
89 sound_trigger_sound_model_type_t model_type;
90 sound_model_callback_t model_callback;
91 void *model_cookie;
Ryan Bavetta4615aad2016-01-27 16:12:04 -080092
Ryan Bavettacc6541c2016-02-09 21:20:51 -080093 // Sound Model information, added in start_recognition
Ryan Bavetta4615aad2016-01-27 16:12:04 -080094 struct sound_trigger_recognition_config *config;
95 recognition_callback_t recognition_callback;
96 void *recognition_cookie;
Ryan Bavettacc6541c2016-02-09 21:20:51 -080097
98 // Next recognition_context in the linked list
99 struct recognition_context *next;
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800100};
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800101
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800102char tmp_write_buffer[PARSE_BUF_LEN];
103
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800104struct stub_sound_trigger_device {
105 struct sound_trigger_hw_device device;
Eric Laurentcbca9052014-04-18 17:54:10 -0700106 pthread_mutex_t lock;
Arunesh Mishrad0535ae2016-02-20 20:52:25 -0800107
108 // This thread opens a port that can be used to monitor and inject events
109 // into the stub HAL.
110 pthread_t control_thread;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800111
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800112 // Recognition contexts are stored as a linked list
113 struct recognition_context *root_model_context;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800114
115 int next_sound_model_id;
Eric Laurentcbca9052014-04-18 17:54:10 -0700116};
117
Ryan Bavetta9beb06c2016-02-29 18:37:29 -0800118// Returns model at the given index, null otherwise (error, doesn't exist, etc).
119// Note that here index starts from zero.
120struct recognition_context* fetch_model_at_index(
121 struct stub_sound_trigger_device* stdev, int index) {
122 ALOGI("%s", __func__);
123 struct recognition_context *model_context = NULL;
124 struct recognition_context *last_model_context = stdev->root_model_context;
125 unsigned int model_index = 0;
126 while(last_model_context) {
127 if (model_index == index) {
128 model_context = last_model_context;
129 break;
130 }
131 last_model_context = last_model_context->next;
132 model_index++;
133 }
134 return model_context;
135}
136
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800137/* Will reuse ids when overflow occurs */
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800138static sound_model_handle_t generate_sound_model_handle(const struct sound_trigger_hw_device *dev) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800139 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
140 int new_id = stdev->next_sound_model_id;
141 ++stdev->next_sound_model_id;
142 if (stdev->next_sound_model_id == 0) {
143 stdev->next_sound_model_id = 1;
144 }
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800145 return (sound_model_handle_t) new_id;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800146}
Eric Laurentcbca9052014-04-18 17:54:10 -0700147
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -0800148bool parse_socket_data(int conn_socket, struct stub_sound_trigger_device* stdev);
149
Ryan Bavetta9beb06c2016-02-29 18:37:29 -0800150static char *sound_trigger_keyphrase_event_alloc(sound_model_handle_t handle,
151 struct sound_trigger_recognition_config *config,
152 int recognition_status) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800153 char *data;
Ryan Bavetta9beb06c2016-02-29 18:37:29 -0800154 struct sound_trigger_phrase_recognition_event *event;
155 data = (char *)calloc(1, sizeof(struct sound_trigger_phrase_recognition_event));
156 if (!data)
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800157 return NULL;
Ryan Bavetta9beb06c2016-02-29 18:37:29 -0800158 event = (struct sound_trigger_phrase_recognition_event *)data;
159 event->common.status = recognition_status;
160 event->common.type = SOUND_MODEL_TYPE_KEYPHRASE;
161 event->common.model = handle;
162
163 if (config) {
164 unsigned int i;
165
166 event->num_phrases = config->num_phrases;
167 if (event->num_phrases > SOUND_TRIGGER_MAX_PHRASES)
168 event->num_phrases = SOUND_TRIGGER_MAX_PHRASES;
169 for (i=0; i < event->num_phrases; i++)
170 memcpy(&event->phrase_extras[i],
171 &config->phrases[i],
172 sizeof(struct sound_trigger_phrase_recognition_extra));
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800173 }
Ryan Bavetta9beb06c2016-02-29 18:37:29 -0800174
175 event->num_phrases = 1;
176 event->phrase_extras[0].confidence_level = 100;
177 event->phrase_extras[0].num_levels = 1;
178 event->phrase_extras[0].levels[0].level = 100;
179 event->phrase_extras[0].levels[0].user_id = 0;
180 // Signify that all the data is comming through streaming, not through the buffer.
181 event->common.capture_available = true;
182 event->common.audio_config = AUDIO_CONFIG_INITIALIZER;
183 event->common.audio_config.sample_rate = 16000;
184 event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO;
185 event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800186 return data;
187}
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800188
Ryan Bavetta9beb06c2016-02-29 18:37:29 -0800189static char *sound_trigger_generic_event_alloc(sound_model_handle_t handle,
190 struct sound_trigger_recognition_config *config,
191 int recognition_status) {
192 char *data;
193 struct sound_trigger_generic_recognition_event *event;
194 data = (char *)calloc(1, sizeof(struct sound_trigger_generic_recognition_event));
195 if (!data)
196 return NULL;
197 event = (struct sound_trigger_generic_recognition_event *)data;
198 event->common.status = recognition_status;
199 event->common.type = SOUND_MODEL_TYPE_GENERIC;
200 event->common.model = handle;
201
202 // Signify that all the data is comming through streaming, not through the buffer.
203 event->common.capture_available = true;
204 event->common.audio_config = AUDIO_CONFIG_INITIALIZER;
205 event->common.audio_config.sample_rate = 16000;
206 event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO;
207 event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
208 return data;
209}
210
211void write_bad_command_error(int conn_socket, char* command) {
212 int num = snprintf(tmp_write_buffer, PARSE_BUF_LEN, "Bad command received: %s", command);
213 tmp_write_buffer[PARSE_BUF_LEN - 1] = '\0'; // Just to be sure.
214 tmp_write_buffer[PARSE_BUF_LEN - 2] = '\n';
215 write(conn_socket, tmp_write_buffer, num);
216}
217
218void write_string(int conn_socket, char* str) {
219 int num = snprintf(tmp_write_buffer, PARSE_BUF_LEN, "%s", str);
220 tmp_write_buffer[PARSE_BUF_LEN - 1] = '\0';
221 tmp_write_buffer[PARSE_BUF_LEN - 2] = '\n';
222 write(conn_socket, tmp_write_buffer, num);
223}
224
225void write_vastr(int conn_socket, char* format, ...) {
226 va_list argptr;
227 va_start(argptr, format);
228 int num = vsnprintf(tmp_write_buffer, PARSE_BUF_LEN, format, argptr);
229 va_end(argptr);
230 tmp_write_buffer[PARSE_BUF_LEN - 1] = '\0';
231 tmp_write_buffer[PARSE_BUF_LEN - 2] = '\n';
232 write(conn_socket, tmp_write_buffer, num);
233}
234
235void send_recognition_event(int conn_socket, char* buffer, struct stub_sound_trigger_device* stdev,
236 int recognition_status) {
237 ALOGI("%s", __func__);
238 char* model_handle_str = strtok(NULL, " ");
239 if (model_handle_str == NULL) {
240 write_string(conn_socket, "Bad sound model id.\n");
241 return;
242 }
243 int index = -1;
244 if (sscanf(model_handle_str, "%d", &index) <= 0) {
245 write_vastr(conn_socket, "Unable to parse sound model index: %s\n", model_handle_str);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800246 return;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800247 }
248
Ryan Bavetta9beb06c2016-02-29 18:37:29 -0800249 if (index < (int)hw_properties.max_sound_models) {
250 ALOGI("Going to send trigger for model index #%d", index );
251 struct recognition_context *model_context = fetch_model_at_index(stdev, index);
252 if (model_context) {
253 if (model_context->recognition_callback == NULL) {
254 ALOGI("%s No matching callback for handle %d", __func__,
255 model_context->model_handle);
256 return;
257 }
258
259 if (model_context->model_type == SOUND_MODEL_TYPE_KEYPHRASE) {
260 struct sound_trigger_phrase_recognition_event *event;
261 event = (struct sound_trigger_phrase_recognition_event *)
262 sound_trigger_keyphrase_event_alloc(model_context->model_handle,
263 model_context->config,
264 recognition_status);
265 if (event) {
266 model_context->recognition_callback(event, model_context->recognition_cookie);
267 free(event);
268 }
269 } else if (model_context->model_type == SOUND_MODEL_TYPE_GENERIC) {
270 struct sound_trigger_generic_recognition_event *event;
271 event = (struct sound_trigger_generic_recognition_event *)
272 sound_trigger_generic_event_alloc(model_context->model_handle,
273 model_context->config,
274 recognition_status);
275 if (event) {
276 model_context->recognition_callback(event, model_context->recognition_cookie);
277 free(event);
278 }
279 } else {
280 ALOGI("Unknown Sound Model Type, No Event to Send");
281 }
282 } else {
283 ALOGI("Sound Model Does Not Exist at this Index: %d", index);
284 write_string(conn_socket, "Sound Model Does Not Exist at given Index.\n");
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800285 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800286 }
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800287}
288
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800289static void send_model_event(sound_model_handle_t model_handle,
290 sound_model_callback_t model_callback, void *model_cookie) {
291
292 if (model_callback == NULL) {
293 ALOGI("%s No matching callback for handle %d", __func__, model_handle);
294 return;
295 }
296
297 char *data;
298 data = (char *)calloc(1, sizeof(struct sound_trigger_model_event));
299 if (!data) {
300 ALOGW("%s Could not allocate event %d", __func__, model_handle);
301 return;
302 }
303
304 struct sound_trigger_model_event *event;
305 event = (struct sound_trigger_model_event *)data;
306 event->status = SOUND_MODEL_STATUS_UPDATED;
307 event->model = model_handle;
308
309 if (event) {
310 model_callback(&event, model_cookie);
311 free(event);
312 }
313}
314
315static bool recognition_callback_exists(struct stub_sound_trigger_device *stdev) {
316 bool callback_found = false;
317 if (stdev->root_model_context) {
318 struct recognition_context *current_model_context = stdev->root_model_context;
319 while(current_model_context) {
320 if (current_model_context->recognition_callback != NULL) {
321 callback_found = true;
322 break;
323 }
324 current_model_context = current_model_context->next;
325 }
326 }
327 return callback_found;
328}
329
330static struct recognition_context * get_model_context(struct stub_sound_trigger_device *stdev,
331 sound_model_handle_t handle) {
332 struct recognition_context *model_context = NULL;
333 if (stdev->root_model_context) {
334 struct recognition_context *current_model_context = stdev->root_model_context;
335 while(current_model_context) {
336 if (current_model_context->model_handle == handle) {
337 model_context = current_model_context;
338 break;
339 }
340 current_model_context = current_model_context->next;
341 }
342 }
343 return model_context;
344}
345
Arunesh Mishrad0535ae2016-02-20 20:52:25 -0800346static void *control_thread_loop(void *context) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700347 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)context;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800348 struct sockaddr_in incoming_info;
349 struct sockaddr_in self_info;
350 int self_socket;
351 socklen_t sock_size = sizeof(struct sockaddr_in);
352 memset(&self_info, 0, sizeof(self_info));
353 self_info.sin_family = AF_INET;
354 self_info.sin_addr.s_addr = htonl(INADDR_ANY);
355 self_info.sin_port = htons(14035);
Eric Laurentcbca9052014-04-18 17:54:10 -0700356
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800357 bool exit = false;
358 while(!exit) {
359 int received_count;
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800360 int requested_count = 2;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800361 char buffer[requested_count];
362 ALOGE("Opening socket");
363 self_socket = socket(AF_INET, SOCK_STREAM, 0);
364 if (self_socket < 0) {
365 ALOGE("Error on socket creation");
366 exit = true;
367 } else {
368 ALOGI("Socket created");
369 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700370
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800371 int reuse = 1;
372 if (setsockopt(self_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) {
373 ALOGE("setsockopt(SO_REUSEADDR) failed");
374 }
375
376 int bind_result = bind(self_socket, (struct sockaddr *)&self_info, sizeof(struct sockaddr));
377 if (bind_result < 0) {
378 ALOGE("Error on bind");
379 exit = true;
380 }
381
382 int listen_result = listen(self_socket, 1);
383 if (listen_result < 0) {
384 ALOGE("Error on Listen");
385 exit = true;
386 }
387
388 while(!exit) {
389 int con_socket = accept(self_socket, (struct sockaddr *)&incoming_info, &sock_size);
390 if (!con_socket) {
391 ALOGE("Lost socket, cannot send trigger");
392 break;
393 }
394 ALOGI("Connection from %s", inet_ntoa(incoming_info.sin_addr));
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800395 if (!parse_socket_data(con_socket, stdev)) {
396 ALOGI("Done processing commands over network. Stopping thread.");
397 exit = true;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800398 }
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800399 close(con_socket);
400 }
401 ALOGE("Closing socket");
402 close(self_socket);
Eric Laurentcbca9052014-04-18 17:54:10 -0700403 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700404
405 return NULL;
406}
407
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800408void list_models(int conn_socket, char* buffer,
409 struct stub_sound_trigger_device* stdev) {
410 ALOGI("%s", __func__);
411 struct recognition_context *last_model_context = stdev->root_model_context;
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800412 unsigned int model_index = 0;
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800413 if (!last_model_context) {
414 ALOGI("ZERO Models exist.");
415 write_string(conn_socket, "Zero models exist.\n");
416 }
417 while (last_model_context) {
418 write_vastr(conn_socket, "Model Index: %d\n", model_index);
419 ALOGI("Model Index: %d\n", model_index);
420 write_vastr(conn_socket, "Model handle: %d\n",
421 last_model_context->model_handle);
422 ALOGI("Model handle: %d\n", last_model_context->model_handle);
423 sound_trigger_sound_model_type_t model_type = last_model_context->model_type;
424
425 if (model_type == SOUND_MODEL_TYPE_KEYPHRASE) {
426 write_string(conn_socket, "Keyphrase sound Model.\n");
427 ALOGI("Keyphrase sound Model.\n");
428 } else if (model_type == SOUND_MODEL_TYPE_GENERIC) {
429 write_string(conn_socket, "Generic sound Model.\n");
430 ALOGI("Generic sound Model.\n");
431 } else {
432 write_vastr(conn_socket, "Unknown sound model type: %d\n",
433 model_type);
434 ALOGI("Unknown sound model type: %d\n", model_type);
435 }
436 write_string(conn_socket, "----\n\n");
437 ALOGI("----\n\n");
438 last_model_context = last_model_context->next;
439 model_index++;
440 }
441}
442
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800443void process_send_model_event(int conn_socket, char* buffer,
444 struct stub_sound_trigger_device* stdev) {
445 ALOGI("%s", __func__);
446 char* model_handle_str = strtok(NULL, " ");
447 if (model_handle_str == NULL) {
448 write_string(conn_socket, "Bad sound model id.\n");
449 return;
450 }
451 int index = -1;
452 if (sscanf(model_handle_str, "%d", &index) <= 0) {
453 write_vastr(conn_socket, "Unable to parse sound model index: %s\n", model_handle_str);
454 return;
455 }
456
457 if (index < (int)hw_properties.max_sound_models) {
458 ALOGI("Going to model event for model index #%d", index );
459 struct recognition_context *model_context = fetch_model_at_index(stdev, index);
460 if (model_context) {
461
462 send_model_event(model_context->model_handle,
463 model_context->model_callback,
464 model_context->model_cookie);
465 } else {
466 ALOGI("Sound Model Does Not Exist at this Index: %d", index);
467 write_string(conn_socket, "Sound Model Does Not Exist at given Index.\n");
468 }
469 }
470}
471
472// Gets the next word from buffer, replaces '\n' or ' ' with '\0'.
473char* get_command(char* buffer) {
474 char* command = strtok(buffer, " ");
475 char* newline = strchr(command, '\n');
476 if (newline != NULL) {
477 *newline = '\0';
478 }
479 return command;
480}
481
482// Parses data coming in from the local socket, executes commands. Returns when
483// done. Return code indicates whether the server should continue listening or
484// abort (true if continue listening).
485bool parse_socket_data(int conn_socket, struct stub_sound_trigger_device* stdev) {
486 ALOGI("Calling parse_socket_data");
487 bool input_done = false;
488 char buffer[PARSE_BUF_LEN];
489 FILE* input_fp = fdopen(conn_socket, "r");
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800490 bool continue_listening = true;
Arunesh Mishrae1df8132016-02-20 17:34:12 -0800491
492 // Note: Since we acquire a lock inside this loop, do not use break or other
493 // exit methods without releasing this lock.
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800494 while(!input_done) {
495 if (fgets(buffer, PARSE_BUF_LEN, input_fp) != NULL) {
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -0800496 pthread_mutex_lock(&stdev->lock);
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800497 char* command = strtok(buffer, " \n");
498 if (command == NULL) {
499 write_bad_command_error(conn_socket, command);
500 } else if (strncmp(command, COMMAND_LS, 2) == 0) {
501 list_models(conn_socket, buffer, stdev);
Ryan Bavetta9beb06c2016-02-29 18:37:29 -0800502 } else if (strcmp(command, COMMAND_RECOGNITION_TRIGGER) == 0) {
503 send_recognition_event(conn_socket, buffer, stdev, RECOGNITION_STATUS_SUCCESS);
504 } else if (strcmp(command, COMMAND_RECOGNITION_ABORT) == 0) {
505 send_recognition_event(conn_socket, buffer, stdev, RECOGNITION_STATUS_ABORT);
506 } else if (strcmp(command, COMMAND_RECOGNITION_FAILURE) == 0) {
507 send_recognition_event(conn_socket, buffer, stdev, RECOGNITION_STATUS_FAILURE);
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -0800508 } else if (strcmp(command, COMMAND_UPDATE) == 0) {
509 process_send_model_event(conn_socket, buffer, stdev);
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800510 } else if (strncmp(command, COMMAND_CLOSE, 5) == 0) {
511 ALOGI("Closing this connection.");
512 write_string(conn_socket, "Closing this connection.");
Arunesh Mishrae1df8132016-02-20 17:34:12 -0800513 input_done = true;
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800514 } else if (strncmp(command, COMMAND_END, 3) == 0) {
515 ALOGI("End command received.");
516 write_string(conn_socket, "End command received. Stopping connection.");
517 continue_listening = false;
Arunesh Mishrae1df8132016-02-20 17:34:12 -0800518 input_done = true;
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -0800519 } else {
520 write_vastr(conn_socket, "Bad command %s.\n", command);
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800521 }
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -0800522 pthread_mutex_unlock(&stdev->lock);
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800523 } else {
524 ALOGI("parse_socket_data done (got null)");
525 input_done = true; // break.
526 }
527 }
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800528 return continue_listening;
529}
530
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800531static void send_loop_kill_signal() {
532 ALOGI("Sending loop thread kill signal");
533 int self_socket = socket(AF_INET, SOCK_STREAM, 0);
534 struct sockaddr_in remote_info;
535 memset(&remote_info, 0, sizeof(remote_info));
536 remote_info.sin_family = AF_INET;
537 remote_info.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
538 remote_info.sin_port = htons(14035);
539 if (connect(self_socket, (struct sockaddr *)&remote_info, sizeof(struct sockaddr)) == 0) {
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800540 send(self_socket, COMMAND_END, 3, 0);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800541 } else {
542 ALOGI("Could not connect");
543 }
544 close(self_socket);
545 ALOGI("Sent loop thread kill signal");
546}
547
Eric Laurentcbca9052014-04-18 17:54:10 -0700548static int stdev_get_properties(const struct sound_trigger_hw_device *dev,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800549 struct sound_trigger_properties *properties) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700550 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
551
552 ALOGI("%s", __func__);
553 if (properties == NULL)
554 return -EINVAL;
555 memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties));
556 return 0;
557}
558
559static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
560 struct sound_trigger_sound_model *sound_model,
561 sound_model_callback_t callback,
562 void *cookie,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800563 sound_model_handle_t *handle) {
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800564 ALOGI("load_sound_model.");
Eric Laurentcbca9052014-04-18 17:54:10 -0700565 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
566 int status = 0;
567
568 ALOGI("%s stdev %p", __func__, stdev);
569 pthread_mutex_lock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800570
Eric Laurentcbca9052014-04-18 17:54:10 -0700571 if (handle == NULL || sound_model == NULL) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800572 pthread_mutex_unlock(&stdev->lock);
573 return -EINVAL;
Eric Laurentcbca9052014-04-18 17:54:10 -0700574 }
575 if (sound_model->data_size == 0 ||
576 sound_model->data_offset < sizeof(struct sound_trigger_sound_model)) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800577 pthread_mutex_unlock(&stdev->lock);
578 return -EINVAL;
Eric Laurentcbca9052014-04-18 17:54:10 -0700579 }
580
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800581 struct recognition_context *model_context;
582 model_context = malloc(sizeof(struct recognition_context));
583 if(!model_context) {
584 ALOGW("Could not allocate recognition_context");
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800585 pthread_mutex_unlock(&stdev->lock);
586 return -ENOSYS;
587 }
588
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800589 // Add the new model context to the recognition_context linked list
590 if (stdev->root_model_context) {
591 // Find the tail
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800592 struct recognition_context *current_model_context = stdev->root_model_context;
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800593 unsigned int model_count = 0;
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800594 while(current_model_context->next) {
595 current_model_context = current_model_context->next;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800596 model_count++;
597 if (model_count >= hw_properties.max_sound_models) {
598 ALOGW("Can't load model: reached max sound model limit");
599 free(model_context);
600 pthread_mutex_unlock(&stdev->lock);
601 return -ENOSYS;
602 }
603 }
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800604 current_model_context->next = model_context;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800605 } else {
606 stdev->root_model_context = model_context;
607 }
608
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800609 model_context->model_handle = generate_sound_model_handle(dev);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800610 *handle = model_context->model_handle;
611 model_context->model_type = sound_model->type;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800612
Eric Laurentcbca9052014-04-18 17:54:10 -0700613 char *data = (char *)sound_model + sound_model->data_offset;
614 ALOGI("%s data size %d data %d - %d", __func__,
615 sound_model->data_size, data[0], data[sound_model->data_size - 1]);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800616 model_context->model_callback = callback;
617 model_context->model_cookie = cookie;
618 model_context->config = NULL;
619 model_context->recognition_callback = NULL;
620 model_context->recognition_cookie = NULL;
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800621 model_context->next = NULL;
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800622 ALOGI("Sound model loaded: Handle %d ", *handle);
Eric Laurentcbca9052014-04-18 17:54:10 -0700623
Eric Laurentcbca9052014-04-18 17:54:10 -0700624 pthread_mutex_unlock(&stdev->lock);
625 return status;
626}
627
628static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800629 sound_model_handle_t handle) {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800630 // If recognizing, stop_recognition must be called for a sound model before unload_sound_model
Eric Laurentcbca9052014-04-18 17:54:10 -0700631 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
632 int status = 0;
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800633 ALOGI("unload_sound_model.");
Eric Laurentcbca9052014-04-18 17:54:10 -0700634 pthread_mutex_lock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800635
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800636 struct recognition_context *model_context = NULL;
637 struct recognition_context *previous_model_context = NULL;
638 if (stdev->root_model_context) {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800639 struct recognition_context *current_model_context = stdev->root_model_context;
640 while(current_model_context) {
641 if (current_model_context->model_handle == handle) {
642 model_context = current_model_context;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800643 break;
644 }
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800645 previous_model_context = current_model_context;
646 current_model_context = current_model_context->next;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800647 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700648 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800649 if (!model_context) {
650 ALOGW("Can't find sound model handle %d in registered list", handle);
Eric Laurentcbca9052014-04-18 17:54:10 -0700651 pthread_mutex_unlock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800652 return -ENOSYS;
Eric Laurentcbca9052014-04-18 17:54:10 -0700653 }
654
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800655 if(previous_model_context) {
656 previous_model_context->next = model_context->next;
657 } else {
658 stdev->root_model_context = model_context->next;
659 }
660 free(model_context->config);
661 free(model_context);
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800662 pthread_mutex_unlock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800663
Eric Laurentcbca9052014-04-18 17:54:10 -0700664 return status;
665}
666
667static int stdev_start_recognition(const struct sound_trigger_hw_device *dev,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800668 sound_model_handle_t handle,
Eric Laurent30f3e6d2014-07-06 16:08:45 -0700669 const struct sound_trigger_recognition_config *config,
Eric Laurentcbca9052014-04-18 17:54:10 -0700670 recognition_callback_t callback,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800671 void *cookie) {
672 ALOGI("%s", __func__);
Eric Laurentcbca9052014-04-18 17:54:10 -0700673 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
Eric Laurentcbca9052014-04-18 17:54:10 -0700674 pthread_mutex_lock(&stdev->lock);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800675
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800676 /* If other models running with callbacks, don't start trigger thread */
677 bool other_callbacks_found = recognition_callback_exists(stdev);
678
679 struct recognition_context *model_context = get_model_context(stdev, handle);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800680 if (!model_context) {
681 ALOGW("Can't find sound model handle %d in registered list", handle);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800682 pthread_mutex_unlock(&stdev->lock);
683 return -ENOSYS;
Eric Laurentcbca9052014-04-18 17:54:10 -0700684 }
685
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800686 free(model_context->config);
687 model_context->config = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800688 if (config) {
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800689 model_context->config = malloc(sizeof(*config));
690 if (!model_context->config) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800691 pthread_mutex_unlock(&stdev->lock);
692 return -ENOMEM;
693 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800694 memcpy(model_context->config, config, sizeof(*config));
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800695 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800696 model_context->recognition_callback = callback;
697 model_context->recognition_cookie = cookie;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800698
Eric Laurentcbca9052014-04-18 17:54:10 -0700699 pthread_mutex_unlock(&stdev->lock);
Arunesh Mishrad0535ae2016-02-20 20:52:25 -0800700 ALOGI("%s done for handle %d", __func__, handle);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800701 return 0;
Eric Laurentcbca9052014-04-18 17:54:10 -0700702}
703
704static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev,
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800705 sound_model_handle_t handle) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700706 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800707 ALOGI("%s", __func__);
Eric Laurentcbca9052014-04-18 17:54:10 -0700708 pthread_mutex_lock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800709
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800710 struct recognition_context *model_context = get_model_context(stdev, handle);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800711 if (!model_context) {
712 ALOGW("Can't find sound model handle %d in registered list", handle);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800713 pthread_mutex_unlock(&stdev->lock);
714 return -ENOSYS;
Eric Laurentcbca9052014-04-18 17:54:10 -0700715 }
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800716
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800717 free(model_context->config);
718 model_context->config = NULL;
719 model_context->recognition_callback = NULL;
720 model_context->recognition_cookie = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800721
Arunesh Mishrad0535ae2016-02-20 20:52:25 -0800722 pthread_mutex_unlock(&stdev->lock);
723 ALOGI("%s done for handle %d", __func__, handle);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800724
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800725 return 0;
Eric Laurentcbca9052014-04-18 17:54:10 -0700726}
727
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800728__attribute__ ((visibility ("default")))
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800729int sound_trigger_open_for_streaming() {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800730 int ret = 0;
731 return ret;
732}
733
734__attribute__ ((visibility ("default")))
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800735size_t sound_trigger_read_samples(int audio_handle, void *buffer, size_t buffer_len) {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800736 size_t ret = 0;
737 return ret;
738}
739
740__attribute__ ((visibility ("default")))
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800741int sound_trigger_close_for_streaming(int audio_handle __unused) {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800742 return 0;
743}
744
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800745static int stdev_close(hw_device_t *device) {
Arunesh Mishrad0535ae2016-02-20 20:52:25 -0800746 // TODO: Implement the ability to stop the control thread. Since this is a
747 // test hal, we have skipped implementing this for now. A possible method
748 // would register a signal handler for the control thread so that any
749 // blocking socket calls can be interrupted. We would send that signal here
750 // to interrupt and quit the thread.
Eric Laurentcbca9052014-04-18 17:54:10 -0700751 free(device);
752 return 0;
753}
754
755static int stdev_open(const hw_module_t* module, const char* name,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800756 hw_device_t** device) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700757 struct stub_sound_trigger_device *stdev;
758 int ret;
759
760 if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0)
761 return -EINVAL;
762
763 stdev = calloc(1, sizeof(struct stub_sound_trigger_device));
764 if (!stdev)
765 return -ENOMEM;
766
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800767 stdev->next_sound_model_id = 1;
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800768 stdev->root_model_context = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800769
Eric Laurentcbca9052014-04-18 17:54:10 -0700770 stdev->device.common.tag = HARDWARE_DEVICE_TAG;
771 stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;
772 stdev->device.common.module = (struct hw_module_t *) module;
773 stdev->device.common.close = stdev_close;
774 stdev->device.get_properties = stdev_get_properties;
775 stdev->device.load_sound_model = stdev_load_sound_model;
776 stdev->device.unload_sound_model = stdev_unload_sound_model;
777 stdev->device.start_recognition = stdev_start_recognition;
778 stdev->device.stop_recognition = stdev_stop_recognition;
779
780 pthread_mutex_init(&stdev->lock, (const pthread_mutexattr_t *) NULL);
Eric Laurentcbca9052014-04-18 17:54:10 -0700781
782 *device = &stdev->device.common;
783
Arunesh Mishrad0535ae2016-02-20 20:52:25 -0800784 pthread_create(&stdev->control_thread, (const pthread_attr_t *) NULL,
785 control_thread_loop, stdev);
786 ALOGI("Starting control thread for the stub hal.");
787
Eric Laurentcbca9052014-04-18 17:54:10 -0700788 return 0;
789}
790
791static struct hw_module_methods_t hal_module_methods = {
792 .open = stdev_open,
793};
794
795struct sound_trigger_module HAL_MODULE_INFO_SYM = {
796 .common = {
797 .tag = HARDWARE_MODULE_TAG,
798 .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0,
799 .hal_api_version = HARDWARE_HAL_API_VERSION,
800 .id = SOUND_TRIGGER_HARDWARE_MODULE_ID,
801 .name = "Default sound trigger HAL",
802 .author = "The Android Open Source Project",
803 .methods = &hal_module_methods,
804 },
805};
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800806