blob: 2034fbe7f3c22024ffe983c788362051e1df0471 [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"
41#define COMMAND_TRIGGER "trig" // Argument: model index.
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -080042#define COMMAND_UPDATE "update" // Argument: model index.
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -080043#define COMMAND_CLOSE "close" // Close just closes the network port, keeps thread running.
44#define COMMAND_END "end" // Closes connection and stops the thread.
45
46#define ERROR_BAD_COMMAND "Bad command"
Eric Laurentcbca9052014-04-18 17:54:10 -070047
48#include <errno.h>
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -080049#include <stdarg.h>
Ryan Bavetta4615aad2016-01-27 16:12:04 -080050#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <unistd.h>
54#include <arpa/inet.h>
55#include <sys/types.h>
56#include <netinet/in.h>
57#include <sys/socket.h>
58
59#include <errno.h>
Eric Laurentcbca9052014-04-18 17:54:10 -070060#include <pthread.h>
61#include <sys/prctl.h>
62#include <cutils/log.h>
63
64#include <hardware/hardware.h>
65#include <system/sound_trigger.h>
66#include <hardware/sound_trigger.h>
67
68static const struct sound_trigger_properties hw_properties = {
69 "The Android Open Source Project", // implementor
70 "Sound Trigger stub HAL", // description
71 1, // version
72 { 0xed7a7d60, 0xc65e, 0x11e3, 0x9be4, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -080073 4, // max_sound_models
Eric Laurentcbca9052014-04-18 17:54:10 -070074 1, // max_key_phrases
75 1, // max_users
76 RECOGNITION_MODE_VOICE_TRIGGER, // recognition_modes
77 false, // capture_transition
78 0, // max_buffer_ms
79 false, // concurrent_capture
Eric Laurent83cd8302014-07-30 08:58:39 -070080 false, // trigger_in_event
Eric Laurentcbca9052014-04-18 17:54:10 -070081 0 // power_consumption_mw
82};
83
Ryan Bavetta4615aad2016-01-27 16:12:04 -080084struct recognition_context {
Ryan Bavettacc6541c2016-02-09 21:20:51 -080085 // Sound Model information, added in method load_sound_model
86 sound_model_handle_t model_handle;
87 sound_trigger_sound_model_type_t model_type;
88 sound_model_callback_t model_callback;
89 void *model_cookie;
Ryan Bavetta4615aad2016-01-27 16:12:04 -080090
Ryan Bavettacc6541c2016-02-09 21:20:51 -080091 // Sound Model information, added in start_recognition
Ryan Bavetta4615aad2016-01-27 16:12:04 -080092 struct sound_trigger_recognition_config *config;
93 recognition_callback_t recognition_callback;
94 void *recognition_cookie;
Ryan Bavettacc6541c2016-02-09 21:20:51 -080095
96 // Next recognition_context in the linked list
97 struct recognition_context *next;
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -080098};
Ryan Bavetta4615aad2016-01-27 16:12:04 -080099
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800100char tmp_write_buffer[PARSE_BUF_LEN];
101
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800102struct stub_sound_trigger_device {
103 struct sound_trigger_hw_device device;
Eric Laurentcbca9052014-04-18 17:54:10 -0700104 pthread_mutex_t lock;
Arunesh Mishrad0535ae2016-02-20 20:52:25 -0800105
106 // This thread opens a port that can be used to monitor and inject events
107 // into the stub HAL.
108 pthread_t control_thread;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800109
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800110 // Recognition contexts are stored as a linked list
111 struct recognition_context *root_model_context;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800112
113 int next_sound_model_id;
Eric Laurentcbca9052014-04-18 17:54:10 -0700114};
115
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800116/* Will reuse ids when overflow occurs */
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800117static sound_model_handle_t generate_sound_model_handle(const struct sound_trigger_hw_device *dev) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800118 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
119 int new_id = stdev->next_sound_model_id;
120 ++stdev->next_sound_model_id;
121 if (stdev->next_sound_model_id == 0) {
122 stdev->next_sound_model_id = 1;
123 }
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800124 return (sound_model_handle_t) new_id;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800125}
Eric Laurentcbca9052014-04-18 17:54:10 -0700126
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -0800127bool parse_socket_data(int conn_socket, struct stub_sound_trigger_device* stdev);
128
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800129static char *sound_trigger_event_alloc(sound_model_handle_t handle,
130 sound_trigger_sound_model_type_t model_type,
131 struct sound_trigger_recognition_config *config) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800132 char *data;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800133 if (model_type == SOUND_MODEL_TYPE_KEYPHRASE) {
134 struct sound_trigger_phrase_recognition_event *event;
135 data = (char *)calloc(1, sizeof(struct sound_trigger_phrase_recognition_event));
136 if (!data)
137 return NULL;
138 event = (struct sound_trigger_phrase_recognition_event *)data;
139 event->common.status = RECOGNITION_STATUS_SUCCESS;
140 event->common.type = SOUND_MODEL_TYPE_KEYPHRASE;
141 event->common.model = handle;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800142
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800143 if (config) {
144 unsigned int i;
145
146 event->num_phrases = config->num_phrases;
147 if (event->num_phrases > SOUND_TRIGGER_MAX_PHRASES)
148 event->num_phrases = SOUND_TRIGGER_MAX_PHRASES;
149 for (i=0; i < event->num_phrases; i++)
150 memcpy(&event->phrase_extras[i],
151 &config->phrases[i],
152 sizeof(struct sound_trigger_phrase_recognition_extra));
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800153 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800154
155 event->num_phrases = 1;
156 event->phrase_extras[0].confidence_level = 100;
157 event->phrase_extras[0].num_levels = 1;
158 event->phrase_extras[0].levels[0].level = 100;
159 event->phrase_extras[0].levels[0].user_id = 0;
160 // Signify that all the data is comming through streaming, not through the buffer.
161 event->common.capture_available = true;
162 event->common.audio_config = AUDIO_CONFIG_INITIALIZER;
163 event->common.audio_config.sample_rate = 16000;
164 event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO;
165 event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
166 } else if (model_type == SOUND_MODEL_TYPE_GENERIC) {
167 struct sound_trigger_generic_recognition_event *event;
168 data = (char *)calloc(1, sizeof(struct sound_trigger_generic_recognition_event));
169 if (!data)
170 return NULL;
171 event = (struct sound_trigger_generic_recognition_event *)data;
172 event->common.status = RECOGNITION_STATUS_SUCCESS;
173 event->common.type = SOUND_MODEL_TYPE_GENERIC;
174 event->common.model = handle;
175
176 // Signify that all the data is comming through streaming, not through the buffer.
177 event->common.capture_available = true;
178 event->common.audio_config = AUDIO_CONFIG_INITIALIZER;
179 event->common.audio_config.sample_rate = 16000;
180 event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO;
181 event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
182 } else {
183 ALOGW("No Valid Event Type Known");
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800184 return NULL;
185 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800186 return data;
187}
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800188
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800189static void send_recognition_event(sound_model_handle_t model_handle,
190 sound_trigger_sound_model_type_t model_type,
191 recognition_callback_t recognition_callback, void *recognition_cookie,
192 struct sound_trigger_recognition_config *config) {
193 if (recognition_callback == NULL) {
194 ALOGI("%s No matching callback for handle %d", __func__, model_handle);
195 return;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800196 }
197
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800198 if (model_type == SOUND_MODEL_TYPE_KEYPHRASE) {
199 struct sound_trigger_phrase_recognition_event *event;
200 event = (struct sound_trigger_phrase_recognition_event *)
201 sound_trigger_event_alloc(model_handle, model_type, config);
202 if (event) {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800203 recognition_callback(event, recognition_cookie);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800204 free(event);
205 }
206 } else if (model_type == SOUND_MODEL_TYPE_GENERIC) {
207 struct sound_trigger_generic_recognition_event *event;
208 event = (struct sound_trigger_generic_recognition_event *)
209 sound_trigger_event_alloc(model_handle, model_type, config);
210 if (event) {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800211 recognition_callback(event, recognition_cookie);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800212 free(event);
213 }
214 } else {
215 ALOGI("Unknown Sound Model Type, No Event to Send");
216 }
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800217}
218
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800219static void send_model_event(sound_model_handle_t model_handle,
220 sound_model_callback_t model_callback, void *model_cookie) {
221
222 if (model_callback == NULL) {
223 ALOGI("%s No matching callback for handle %d", __func__, model_handle);
224 return;
225 }
226
227 char *data;
228 data = (char *)calloc(1, sizeof(struct sound_trigger_model_event));
229 if (!data) {
230 ALOGW("%s Could not allocate event %d", __func__, model_handle);
231 return;
232 }
233
234 struct sound_trigger_model_event *event;
235 event = (struct sound_trigger_model_event *)data;
236 event->status = SOUND_MODEL_STATUS_UPDATED;
237 event->model = model_handle;
238
239 if (event) {
240 model_callback(&event, model_cookie);
241 free(event);
242 }
243}
244
245static bool recognition_callback_exists(struct stub_sound_trigger_device *stdev) {
246 bool callback_found = false;
247 if (stdev->root_model_context) {
248 struct recognition_context *current_model_context = stdev->root_model_context;
249 while(current_model_context) {
250 if (current_model_context->recognition_callback != NULL) {
251 callback_found = true;
252 break;
253 }
254 current_model_context = current_model_context->next;
255 }
256 }
257 return callback_found;
258}
259
260static struct recognition_context * get_model_context(struct stub_sound_trigger_device *stdev,
261 sound_model_handle_t handle) {
262 struct recognition_context *model_context = NULL;
263 if (stdev->root_model_context) {
264 struct recognition_context *current_model_context = stdev->root_model_context;
265 while(current_model_context) {
266 if (current_model_context->model_handle == handle) {
267 model_context = current_model_context;
268 break;
269 }
270 current_model_context = current_model_context->next;
271 }
272 }
273 return model_context;
274}
275
Arunesh Mishrad0535ae2016-02-20 20:52:25 -0800276static void *control_thread_loop(void *context) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700277 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)context;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800278 struct sockaddr_in incoming_info;
279 struct sockaddr_in self_info;
280 int self_socket;
281 socklen_t sock_size = sizeof(struct sockaddr_in);
282 memset(&self_info, 0, sizeof(self_info));
283 self_info.sin_family = AF_INET;
284 self_info.sin_addr.s_addr = htonl(INADDR_ANY);
285 self_info.sin_port = htons(14035);
Eric Laurentcbca9052014-04-18 17:54:10 -0700286
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800287 bool exit = false;
288 while(!exit) {
289 int received_count;
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800290 int requested_count = 2;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800291 char buffer[requested_count];
292 ALOGE("Opening socket");
293 self_socket = socket(AF_INET, SOCK_STREAM, 0);
294 if (self_socket < 0) {
295 ALOGE("Error on socket creation");
296 exit = true;
297 } else {
298 ALOGI("Socket created");
299 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700300
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800301 int reuse = 1;
302 if (setsockopt(self_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) {
303 ALOGE("setsockopt(SO_REUSEADDR) failed");
304 }
305
306 int bind_result = bind(self_socket, (struct sockaddr *)&self_info, sizeof(struct sockaddr));
307 if (bind_result < 0) {
308 ALOGE("Error on bind");
309 exit = true;
310 }
311
312 int listen_result = listen(self_socket, 1);
313 if (listen_result < 0) {
314 ALOGE("Error on Listen");
315 exit = true;
316 }
317
318 while(!exit) {
319 int con_socket = accept(self_socket, (struct sockaddr *)&incoming_info, &sock_size);
320 if (!con_socket) {
321 ALOGE("Lost socket, cannot send trigger");
322 break;
323 }
324 ALOGI("Connection from %s", inet_ntoa(incoming_info.sin_addr));
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800325 if (!parse_socket_data(con_socket, stdev)) {
326 ALOGI("Done processing commands over network. Stopping thread.");
327 exit = true;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800328 }
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800329 close(con_socket);
330 }
331 ALOGE("Closing socket");
332 close(self_socket);
Eric Laurentcbca9052014-04-18 17:54:10 -0700333 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700334
335 return NULL;
336}
337
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800338void write_bad_command_error(int conn_socket, char* command) {
339 int num = snprintf(tmp_write_buffer, PARSE_BUF_LEN, "Bad command received: %s", command);
340 tmp_write_buffer[PARSE_BUF_LEN - 1] = '\0'; // Just to be sure.
341 tmp_write_buffer[PARSE_BUF_LEN - 2] = '\n';
342 write(conn_socket, tmp_write_buffer, num);
343}
344
345void write_string(int conn_socket, char* str) {
346 int num = snprintf(tmp_write_buffer, PARSE_BUF_LEN, "%s", str);
347 tmp_write_buffer[PARSE_BUF_LEN - 1] = '\0';
348 tmp_write_buffer[PARSE_BUF_LEN - 2] = '\n';
349 write(conn_socket, tmp_write_buffer, num);
350}
351
352void write_vastr(int conn_socket, char* format, ...) {
353 va_list argptr;
354 va_start(argptr, format);
355 int num = vsnprintf(tmp_write_buffer, PARSE_BUF_LEN, format, argptr);
356 va_end(argptr);
357 tmp_write_buffer[PARSE_BUF_LEN - 1] = '\0';
358 tmp_write_buffer[PARSE_BUF_LEN - 2] = '\n';
359 write(conn_socket, tmp_write_buffer, num);
360}
361
362void list_models(int conn_socket, char* buffer,
363 struct stub_sound_trigger_device* stdev) {
364 ALOGI("%s", __func__);
365 struct recognition_context *last_model_context = stdev->root_model_context;
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800366 unsigned int model_index = 0;
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800367 if (!last_model_context) {
368 ALOGI("ZERO Models exist.");
369 write_string(conn_socket, "Zero models exist.\n");
370 }
371 while (last_model_context) {
372 write_vastr(conn_socket, "Model Index: %d\n", model_index);
373 ALOGI("Model Index: %d\n", model_index);
374 write_vastr(conn_socket, "Model handle: %d\n",
375 last_model_context->model_handle);
376 ALOGI("Model handle: %d\n", last_model_context->model_handle);
377 sound_trigger_sound_model_type_t model_type = last_model_context->model_type;
378
379 if (model_type == SOUND_MODEL_TYPE_KEYPHRASE) {
380 write_string(conn_socket, "Keyphrase sound Model.\n");
381 ALOGI("Keyphrase sound Model.\n");
382 } else if (model_type == SOUND_MODEL_TYPE_GENERIC) {
383 write_string(conn_socket, "Generic sound Model.\n");
384 ALOGI("Generic sound Model.\n");
385 } else {
386 write_vastr(conn_socket, "Unknown sound model type: %d\n",
387 model_type);
388 ALOGI("Unknown sound model type: %d\n", model_type);
389 }
390 write_string(conn_socket, "----\n\n");
391 ALOGI("----\n\n");
392 last_model_context = last_model_context->next;
393 model_index++;
394 }
395}
396
397// Returns model at the given index, null otherwise (error, doesn't exist, etc).
398// Note that here index starts from zero.
399struct recognition_context* fetch_model_at_index(
400 struct stub_sound_trigger_device* stdev, int index) {
401 ALOGI("%s", __func__);
402 struct recognition_context *model_context = NULL;
403 struct recognition_context *last_model_context = stdev->root_model_context;
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800404 unsigned int model_index = 0;
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800405 while(last_model_context) {
406 if (model_index == index) {
407 model_context = last_model_context;
408 break;
409 }
410 last_model_context = last_model_context->next;
411 model_index++;
412 }
413 return model_context;
414}
415
416void send_trigger(int conn_socket, char* buffer,
417 struct stub_sound_trigger_device* stdev) {
418 ALOGI("%s", __func__);
419 char* model_handle_str = strtok(NULL, " ");
420 if (model_handle_str == NULL) {
421 write_string(conn_socket, "Bad sound model id.\n");
422 return;
423 }
424 int index = -1;
425 if (sscanf(model_handle_str, "%d", &index) <= 0) {
426 write_vastr(conn_socket, "Unable to parse sound model index: %s\n", model_handle_str);
427 return;
428 }
429
430 if (index < (int)hw_properties.max_sound_models) {
431 ALOGI("Going to send trigger for model index #%d", index );
432 struct recognition_context *model_context = fetch_model_at_index(stdev, index);
433 if (model_context) {
434 send_recognition_event(model_context->model_handle,
435 model_context->model_type,
436 model_context->recognition_callback,
437 model_context->recognition_cookie,
438 model_context->config);
439 } else {
440 ALOGI("Sound Model Does Not Exist at this Index: %d", index);
441 write_string(conn_socket, "Sound Model Does Not Exist at given Index.\n");
442 }
443 }
444}
445
446void process_send_model_event(int conn_socket, char* buffer,
447 struct stub_sound_trigger_device* stdev) {
448 ALOGI("%s", __func__);
449 char* model_handle_str = strtok(NULL, " ");
450 if (model_handle_str == NULL) {
451 write_string(conn_socket, "Bad sound model id.\n");
452 return;
453 }
454 int index = -1;
455 if (sscanf(model_handle_str, "%d", &index) <= 0) {
456 write_vastr(conn_socket, "Unable to parse sound model index: %s\n", model_handle_str);
457 return;
458 }
459
460 if (index < (int)hw_properties.max_sound_models) {
461 ALOGI("Going to model event for model index #%d", index );
462 struct recognition_context *model_context = fetch_model_at_index(stdev, index);
463 if (model_context) {
464
465 send_model_event(model_context->model_handle,
466 model_context->model_callback,
467 model_context->model_cookie);
468 } else {
469 ALOGI("Sound Model Does Not Exist at this Index: %d", index);
470 write_string(conn_socket, "Sound Model Does Not Exist at given Index.\n");
471 }
472 }
473}
474
475// Gets the next word from buffer, replaces '\n' or ' ' with '\0'.
476char* get_command(char* buffer) {
477 char* command = strtok(buffer, " ");
478 char* newline = strchr(command, '\n');
479 if (newline != NULL) {
480 *newline = '\0';
481 }
482 return command;
483}
484
485// Parses data coming in from the local socket, executes commands. Returns when
486// done. Return code indicates whether the server should continue listening or
487// abort (true if continue listening).
488bool parse_socket_data(int conn_socket, struct stub_sound_trigger_device* stdev) {
489 ALOGI("Calling parse_socket_data");
490 bool input_done = false;
491 char buffer[PARSE_BUF_LEN];
492 FILE* input_fp = fdopen(conn_socket, "r");
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800493 bool continue_listening = true;
Arunesh Mishrae1df8132016-02-20 17:34:12 -0800494
495 // Note: Since we acquire a lock inside this loop, do not use break or other
496 // exit methods without releasing this lock.
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800497 while(!input_done) {
498 if (fgets(buffer, PARSE_BUF_LEN, input_fp) != NULL) {
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -0800499 pthread_mutex_lock(&stdev->lock);
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800500 char* command = strtok(buffer, " \n");
501 if (command == NULL) {
502 write_bad_command_error(conn_socket, command);
503 } else if (strncmp(command, COMMAND_LS, 2) == 0) {
504 list_models(conn_socket, buffer, stdev);
505 } else if (strcmp(command, COMMAND_TRIGGER) == 0) {
506 send_trigger(conn_socket, buffer, stdev);
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -0800507 } else if (strcmp(command, COMMAND_UPDATE) == 0) {
508 process_send_model_event(conn_socket, buffer, stdev);
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800509 } else if (strncmp(command, COMMAND_CLOSE, 5) == 0) {
510 ALOGI("Closing this connection.");
511 write_string(conn_socket, "Closing this connection.");
Arunesh Mishrae1df8132016-02-20 17:34:12 -0800512 input_done = true;
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800513 } else if (strncmp(command, COMMAND_END, 3) == 0) {
514 ALOGI("End command received.");
515 write_string(conn_socket, "End command received. Stopping connection.");
516 continue_listening = false;
Arunesh Mishrae1df8132016-02-20 17:34:12 -0800517 input_done = true;
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -0800518 } else {
519 write_vastr(conn_socket, "Bad command %s.\n", command);
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800520 }
Arunesh Mishra7db0a7a2016-02-19 16:20:10 -0800521 pthread_mutex_unlock(&stdev->lock);
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800522 } else {
523 ALOGI("parse_socket_data done (got null)");
524 input_done = true; // break.
525 }
526 }
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800527 return continue_listening;
528}
529
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800530static void send_loop_kill_signal() {
531 ALOGI("Sending loop thread kill signal");
532 int self_socket = socket(AF_INET, SOCK_STREAM, 0);
533 struct sockaddr_in remote_info;
534 memset(&remote_info, 0, sizeof(remote_info));
535 remote_info.sin_family = AF_INET;
536 remote_info.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
537 remote_info.sin_port = htons(14035);
538 if (connect(self_socket, (struct sockaddr *)&remote_info, sizeof(struct sockaddr)) == 0) {
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800539 send(self_socket, COMMAND_END, 3, 0);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800540 } else {
541 ALOGI("Could not connect");
542 }
543 close(self_socket);
544 ALOGI("Sent loop thread kill signal");
545}
546
Eric Laurentcbca9052014-04-18 17:54:10 -0700547static int stdev_get_properties(const struct sound_trigger_hw_device *dev,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800548 struct sound_trigger_properties *properties) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700549 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
550
551 ALOGI("%s", __func__);
552 if (properties == NULL)
553 return -EINVAL;
554 memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties));
555 return 0;
556}
557
558static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
559 struct sound_trigger_sound_model *sound_model,
560 sound_model_callback_t callback,
561 void *cookie,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800562 sound_model_handle_t *handle) {
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800563 ALOGI("load_sound_model.");
Eric Laurentcbca9052014-04-18 17:54:10 -0700564 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
565 int status = 0;
566
567 ALOGI("%s stdev %p", __func__, stdev);
568 pthread_mutex_lock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800569
Eric Laurentcbca9052014-04-18 17:54:10 -0700570 if (handle == NULL || sound_model == NULL) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800571 pthread_mutex_unlock(&stdev->lock);
572 return -EINVAL;
Eric Laurentcbca9052014-04-18 17:54:10 -0700573 }
574 if (sound_model->data_size == 0 ||
575 sound_model->data_offset < sizeof(struct sound_trigger_sound_model)) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800576 pthread_mutex_unlock(&stdev->lock);
577 return -EINVAL;
Eric Laurentcbca9052014-04-18 17:54:10 -0700578 }
579
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800580 struct recognition_context *model_context;
581 model_context = malloc(sizeof(struct recognition_context));
582 if(!model_context) {
583 ALOGW("Could not allocate recognition_context");
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800584 pthread_mutex_unlock(&stdev->lock);
585 return -ENOSYS;
586 }
587
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800588 // Add the new model context to the recognition_context linked list
589 if (stdev->root_model_context) {
590 // Find the tail
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800591 struct recognition_context *current_model_context = stdev->root_model_context;
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800592 unsigned int model_count = 0;
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800593 while(current_model_context->next) {
594 current_model_context = current_model_context->next;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800595 model_count++;
596 if (model_count >= hw_properties.max_sound_models) {
597 ALOGW("Can't load model: reached max sound model limit");
598 free(model_context);
599 pthread_mutex_unlock(&stdev->lock);
600 return -ENOSYS;
601 }
602 }
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800603 current_model_context->next = model_context;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800604 } else {
605 stdev->root_model_context = model_context;
606 }
607
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800608 model_context->model_handle = generate_sound_model_handle(dev);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800609 *handle = model_context->model_handle;
610 model_context->model_type = sound_model->type;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800611
Eric Laurentcbca9052014-04-18 17:54:10 -0700612 char *data = (char *)sound_model + sound_model->data_offset;
613 ALOGI("%s data size %d data %d - %d", __func__,
614 sound_model->data_size, data[0], data[sound_model->data_size - 1]);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800615 model_context->model_callback = callback;
616 model_context->model_cookie = cookie;
617 model_context->config = NULL;
618 model_context->recognition_callback = NULL;
619 model_context->recognition_cookie = NULL;
Ryan Bavettaf9f08712016-02-19 21:18:46 -0800620 model_context->next = NULL;
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800621 ALOGI("Sound model loaded: Handle %d ", *handle);
Eric Laurentcbca9052014-04-18 17:54:10 -0700622
Eric Laurentcbca9052014-04-18 17:54:10 -0700623 pthread_mutex_unlock(&stdev->lock);
624 return status;
625}
626
627static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800628 sound_model_handle_t handle) {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800629 // If recognizing, stop_recognition must be called for a sound model before unload_sound_model
Eric Laurentcbca9052014-04-18 17:54:10 -0700630 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
631 int status = 0;
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800632 ALOGI("unload_sound_model.");
Eric Laurentcbca9052014-04-18 17:54:10 -0700633 pthread_mutex_lock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800634
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800635 struct recognition_context *model_context = NULL;
636 struct recognition_context *previous_model_context = NULL;
637 if (stdev->root_model_context) {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800638 struct recognition_context *current_model_context = stdev->root_model_context;
639 while(current_model_context) {
640 if (current_model_context->model_handle == handle) {
641 model_context = current_model_context;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800642 break;
643 }
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800644 previous_model_context = current_model_context;
645 current_model_context = current_model_context->next;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800646 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700647 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800648 if (!model_context) {
649 ALOGW("Can't find sound model handle %d in registered list", handle);
Eric Laurentcbca9052014-04-18 17:54:10 -0700650 pthread_mutex_unlock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800651 return -ENOSYS;
Eric Laurentcbca9052014-04-18 17:54:10 -0700652 }
653
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800654 if(previous_model_context) {
655 previous_model_context->next = model_context->next;
656 } else {
657 stdev->root_model_context = model_context->next;
658 }
659 free(model_context->config);
660 free(model_context);
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800661 pthread_mutex_unlock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800662
Eric Laurentcbca9052014-04-18 17:54:10 -0700663 return status;
664}
665
666static int stdev_start_recognition(const struct sound_trigger_hw_device *dev,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800667 sound_model_handle_t handle,
Eric Laurent30f3e6d2014-07-06 16:08:45 -0700668 const struct sound_trigger_recognition_config *config,
Eric Laurentcbca9052014-04-18 17:54:10 -0700669 recognition_callback_t callback,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800670 void *cookie) {
671 ALOGI("%s", __func__);
Eric Laurentcbca9052014-04-18 17:54:10 -0700672 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
Eric Laurentcbca9052014-04-18 17:54:10 -0700673 pthread_mutex_lock(&stdev->lock);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800674
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800675 /* If other models running with callbacks, don't start trigger thread */
676 bool other_callbacks_found = recognition_callback_exists(stdev);
677
678 struct recognition_context *model_context = get_model_context(stdev, handle);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800679 if (!model_context) {
680 ALOGW("Can't find sound model handle %d in registered list", handle);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800681 pthread_mutex_unlock(&stdev->lock);
682 return -ENOSYS;
Eric Laurentcbca9052014-04-18 17:54:10 -0700683 }
684
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800685 free(model_context->config);
686 model_context->config = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800687 if (config) {
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800688 model_context->config = malloc(sizeof(*config));
689 if (!model_context->config) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800690 pthread_mutex_unlock(&stdev->lock);
691 return -ENOMEM;
692 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800693 memcpy(model_context->config, config, sizeof(*config));
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800694 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800695 model_context->recognition_callback = callback;
696 model_context->recognition_cookie = cookie;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800697
Eric Laurentcbca9052014-04-18 17:54:10 -0700698 pthread_mutex_unlock(&stdev->lock);
Arunesh Mishrad0535ae2016-02-20 20:52:25 -0800699 ALOGI("%s done for handle %d", __func__, handle);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800700 return 0;
Eric Laurentcbca9052014-04-18 17:54:10 -0700701}
702
703static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev,
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800704 sound_model_handle_t handle) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700705 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800706 ALOGI("%s", __func__);
Eric Laurentcbca9052014-04-18 17:54:10 -0700707 pthread_mutex_lock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800708
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800709 struct recognition_context *model_context = get_model_context(stdev, handle);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800710 if (!model_context) {
711 ALOGW("Can't find sound model handle %d in registered list", handle);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800712 pthread_mutex_unlock(&stdev->lock);
713 return -ENOSYS;
Eric Laurentcbca9052014-04-18 17:54:10 -0700714 }
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800715
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800716 free(model_context->config);
717 model_context->config = NULL;
718 model_context->recognition_callback = NULL;
719 model_context->recognition_cookie = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800720
Arunesh Mishrad0535ae2016-02-20 20:52:25 -0800721 pthread_mutex_unlock(&stdev->lock);
722 ALOGI("%s done for handle %d", __func__, handle);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800723
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800724 return 0;
Eric Laurentcbca9052014-04-18 17:54:10 -0700725}
726
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800727__attribute__ ((visibility ("default")))
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800728int sound_trigger_open_for_streaming() {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800729 int ret = 0;
730 return ret;
731}
732
733__attribute__ ((visibility ("default")))
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800734size_t sound_trigger_read_samples(int audio_handle, void *buffer, size_t buffer_len) {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800735 size_t ret = 0;
736 return ret;
737}
738
739__attribute__ ((visibility ("default")))
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800740int sound_trigger_close_for_streaming(int audio_handle __unused) {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800741 return 0;
742}
743
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800744static int stdev_close(hw_device_t *device) {
Arunesh Mishrad0535ae2016-02-20 20:52:25 -0800745 // TODO: Implement the ability to stop the control thread. Since this is a
746 // test hal, we have skipped implementing this for now. A possible method
747 // would register a signal handler for the control thread so that any
748 // blocking socket calls can be interrupted. We would send that signal here
749 // to interrupt and quit the thread.
Eric Laurentcbca9052014-04-18 17:54:10 -0700750 free(device);
751 return 0;
752}
753
754static int stdev_open(const hw_module_t* module, const char* name,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800755 hw_device_t** device) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700756 struct stub_sound_trigger_device *stdev;
757 int ret;
758
759 if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0)
760 return -EINVAL;
761
762 stdev = calloc(1, sizeof(struct stub_sound_trigger_device));
763 if (!stdev)
764 return -ENOMEM;
765
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800766 stdev->next_sound_model_id = 1;
Arunesh Mishraf1d59fc2016-02-15 17:48:27 -0800767 stdev->root_model_context = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800768
Eric Laurentcbca9052014-04-18 17:54:10 -0700769 stdev->device.common.tag = HARDWARE_DEVICE_TAG;
770 stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;
771 stdev->device.common.module = (struct hw_module_t *) module;
772 stdev->device.common.close = stdev_close;
773 stdev->device.get_properties = stdev_get_properties;
774 stdev->device.load_sound_model = stdev_load_sound_model;
775 stdev->device.unload_sound_model = stdev_unload_sound_model;
776 stdev->device.start_recognition = stdev_start_recognition;
777 stdev->device.stop_recognition = stdev_stop_recognition;
778
779 pthread_mutex_init(&stdev->lock, (const pthread_mutexattr_t *) NULL);
Eric Laurentcbca9052014-04-18 17:54:10 -0700780
781 *device = &stdev->device.common;
782
Arunesh Mishrad0535ae2016-02-20 20:52:25 -0800783 pthread_create(&stdev->control_thread, (const pthread_attr_t *) NULL,
784 control_thread_loop, stdev);
785 ALOGI("Starting control thread for the stub hal.");
786
Eric Laurentcbca9052014-04-18 17:54:10 -0700787 return 0;
788}
789
790static struct hw_module_methods_t hal_module_methods = {
791 .open = stdev_open,
792};
793
794struct sound_trigger_module HAL_MODULE_INFO_SYM = {
795 .common = {
796 .tag = HARDWARE_MODULE_TAG,
797 .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0,
798 .hal_api_version = HARDWARE_HAL_API_VERSION,
799 .id = SOUND_TRIGGER_HARDWARE_MODULE_ID,
800 .name = "Default sound trigger HAL",
801 .author = "The Android Open Source Project",
802 .methods = &hal_module_methods,
803 },
804};
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800805