blob: 972c52085cd77e28e51fe82315b47017f3b62e89 [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
22 * echo $'\001' | nc -q -1 localhost 14035
23 *
24 * $'\001' corresponds to the index_position of loaded sound
25 * model, you can also send $'\002' etc. $'\000' is the kill
26 * signal for the trigger listening thread.
27 *
Ryan Bavettac2bdc552016-02-15 15:51:46 -080028 * The default event type is a Recognition event, to specify a
29 * type of event, you can send another byte. $'\000' corresponds
30 * to a recognition event, $'\001' is a sound model event.
31 *
32 * adb forward tcp:14035 tcp:14035
33 * echo $'\001'$'\001' | nc -q -1 localhost 14035
34 *
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -080035 * To enable this file, you can make with command line parameter
36 * SOUND_TRIGGER_USE_STUB_MODULE=1
Ryan Bavetta4615aad2016-01-27 16:12:04 -080037 */
38
Eric Laurentcbca9052014-04-18 17:54:10 -070039#define LOG_TAG "sound_trigger_hw_default"
Ryan Bavettacc6541c2016-02-09 21:20:51 -080040#define LOG_NDEBUG 1
Eric Laurentcbca9052014-04-18 17:54:10 -070041
42#include <errno.h>
Ryan Bavetta4615aad2016-01-27 16:12:04 -080043#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <unistd.h>
47#include <arpa/inet.h>
48#include <sys/types.h>
49#include <netinet/in.h>
50#include <sys/socket.h>
51
52#include <errno.h>
Eric Laurentcbca9052014-04-18 17:54:10 -070053#include <pthread.h>
54#include <sys/prctl.h>
55#include <cutils/log.h>
56
57#include <hardware/hardware.h>
58#include <system/sound_trigger.h>
59#include <hardware/sound_trigger.h>
60
61static const struct sound_trigger_properties hw_properties = {
62 "The Android Open Source Project", // implementor
63 "Sound Trigger stub HAL", // description
64 1, // version
65 { 0xed7a7d60, 0xc65e, 0x11e3, 0x9be4, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
Ryan Bavetta4615aad2016-01-27 16:12:04 -080066 2, // max_sound_models
Eric Laurentcbca9052014-04-18 17:54:10 -070067 1, // max_key_phrases
68 1, // max_users
69 RECOGNITION_MODE_VOICE_TRIGGER, // recognition_modes
70 false, // capture_transition
71 0, // max_buffer_ms
72 false, // concurrent_capture
Eric Laurent83cd8302014-07-30 08:58:39 -070073 false, // trigger_in_event
Eric Laurentcbca9052014-04-18 17:54:10 -070074 0 // power_consumption_mw
75};
76
Ryan Bavetta4615aad2016-01-27 16:12:04 -080077struct recognition_context {
Ryan Bavettacc6541c2016-02-09 21:20:51 -080078 // Sound Model information, added in method load_sound_model
79 sound_model_handle_t model_handle;
80 sound_trigger_sound_model_type_t model_type;
81 sound_model_callback_t model_callback;
82 void *model_cookie;
Ryan Bavetta4615aad2016-01-27 16:12:04 -080083
Ryan Bavettacc6541c2016-02-09 21:20:51 -080084 // Sound Model information, added in start_recognition
Ryan Bavetta4615aad2016-01-27 16:12:04 -080085 struct sound_trigger_recognition_config *config;
86 recognition_callback_t recognition_callback;
87 void *recognition_cookie;
Ryan Bavettacc6541c2016-02-09 21:20:51 -080088
89 // Next recognition_context in the linked list
90 struct recognition_context *next;
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -080091};
Ryan Bavetta4615aad2016-01-27 16:12:04 -080092
93struct stub_sound_trigger_device {
94 struct sound_trigger_hw_device device;
Eric Laurentcbca9052014-04-18 17:54:10 -070095 pthread_mutex_t lock;
Ryan Bavetta4615aad2016-01-27 16:12:04 -080096 pthread_t callback_thread;
97
Ryan Bavettacc6541c2016-02-09 21:20:51 -080098 // Recognition contexts are stored as a linked list
99 struct recognition_context *root_model_context;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800100
101 int next_sound_model_id;
Eric Laurentcbca9052014-04-18 17:54:10 -0700102};
103
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800104/* Will reuse ids when overflow occurs */
105static unsigned int generate_sound_model_id(const struct sound_trigger_hw_device *dev) {
106 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
107 int new_id = stdev->next_sound_model_id;
108 ++stdev->next_sound_model_id;
109 if (stdev->next_sound_model_id == 0) {
110 stdev->next_sound_model_id = 1;
111 }
112 return new_id;
113}
Eric Laurentcbca9052014-04-18 17:54:10 -0700114
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800115static char *sound_trigger_event_alloc(sound_model_handle_t handle,
116 sound_trigger_sound_model_type_t model_type,
117 struct sound_trigger_recognition_config *config) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800118 char *data;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800119 if (model_type == SOUND_MODEL_TYPE_KEYPHRASE) {
120 struct sound_trigger_phrase_recognition_event *event;
121 data = (char *)calloc(1, sizeof(struct sound_trigger_phrase_recognition_event));
122 if (!data)
123 return NULL;
124 event = (struct sound_trigger_phrase_recognition_event *)data;
125 event->common.status = RECOGNITION_STATUS_SUCCESS;
126 event->common.type = SOUND_MODEL_TYPE_KEYPHRASE;
127 event->common.model = handle;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800128
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800129 if (config) {
130 unsigned int i;
131
132 event->num_phrases = config->num_phrases;
133 if (event->num_phrases > SOUND_TRIGGER_MAX_PHRASES)
134 event->num_phrases = SOUND_TRIGGER_MAX_PHRASES;
135 for (i=0; i < event->num_phrases; i++)
136 memcpy(&event->phrase_extras[i],
137 &config->phrases[i],
138 sizeof(struct sound_trigger_phrase_recognition_extra));
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800139 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800140
141 event->num_phrases = 1;
142 event->phrase_extras[0].confidence_level = 100;
143 event->phrase_extras[0].num_levels = 1;
144 event->phrase_extras[0].levels[0].level = 100;
145 event->phrase_extras[0].levels[0].user_id = 0;
146 // Signify that all the data is comming through streaming, not through the buffer.
147 event->common.capture_available = true;
148 event->common.audio_config = AUDIO_CONFIG_INITIALIZER;
149 event->common.audio_config.sample_rate = 16000;
150 event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO;
151 event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
152 } else if (model_type == SOUND_MODEL_TYPE_GENERIC) {
153 struct sound_trigger_generic_recognition_event *event;
154 data = (char *)calloc(1, sizeof(struct sound_trigger_generic_recognition_event));
155 if (!data)
156 return NULL;
157 event = (struct sound_trigger_generic_recognition_event *)data;
158 event->common.status = RECOGNITION_STATUS_SUCCESS;
159 event->common.type = SOUND_MODEL_TYPE_GENERIC;
160 event->common.model = handle;
161
162 // Signify that all the data is comming through streaming, not through the buffer.
163 event->common.capture_available = true;
164 event->common.audio_config = AUDIO_CONFIG_INITIALIZER;
165 event->common.audio_config.sample_rate = 16000;
166 event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO;
167 event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
168 } else {
169 ALOGW("No Valid Event Type Known");
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800170 return NULL;
171 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800172 return data;
173}
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800174
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800175static void send_recognition_event(sound_model_handle_t model_handle,
176 sound_trigger_sound_model_type_t model_type,
177 recognition_callback_t recognition_callback, void *recognition_cookie,
178 struct sound_trigger_recognition_config *config) {
179 if (recognition_callback == NULL) {
180 ALOGI("%s No matching callback for handle %d", __func__, model_handle);
181 return;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800182 }
183
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800184 if (model_type == SOUND_MODEL_TYPE_KEYPHRASE) {
185 struct sound_trigger_phrase_recognition_event *event;
186 event = (struct sound_trigger_phrase_recognition_event *)
187 sound_trigger_event_alloc(model_handle, model_type, config);
188 if (event) {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800189 recognition_callback(event, recognition_cookie);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800190 free(event);
191 }
192 } else if (model_type == SOUND_MODEL_TYPE_GENERIC) {
193 struct sound_trigger_generic_recognition_event *event;
194 event = (struct sound_trigger_generic_recognition_event *)
195 sound_trigger_event_alloc(model_handle, model_type, config);
196 if (event) {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800197 recognition_callback(event, recognition_cookie);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800198 free(event);
199 }
200 } else {
201 ALOGI("Unknown Sound Model Type, No Event to Send");
202 }
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800203}
204
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800205static void send_model_event(sound_model_handle_t model_handle,
206 sound_model_callback_t model_callback, void *model_cookie) {
207
208 if (model_callback == NULL) {
209 ALOGI("%s No matching callback for handle %d", __func__, model_handle);
210 return;
211 }
212
213 char *data;
214 data = (char *)calloc(1, sizeof(struct sound_trigger_model_event));
215 if (!data) {
216 ALOGW("%s Could not allocate event %d", __func__, model_handle);
217 return;
218 }
219
220 struct sound_trigger_model_event *event;
221 event = (struct sound_trigger_model_event *)data;
222 event->status = SOUND_MODEL_STATUS_UPDATED;
223 event->model = model_handle;
224
225 if (event) {
226 model_callback(&event, model_cookie);
227 free(event);
228 }
229}
230
231static bool recognition_callback_exists(struct stub_sound_trigger_device *stdev) {
232 bool callback_found = false;
233 if (stdev->root_model_context) {
234 struct recognition_context *current_model_context = stdev->root_model_context;
235 while(current_model_context) {
236 if (current_model_context->recognition_callback != NULL) {
237 callback_found = true;
238 break;
239 }
240 current_model_context = current_model_context->next;
241 }
242 }
243 return callback_found;
244}
245
246static struct recognition_context * get_model_context(struct stub_sound_trigger_device *stdev,
247 sound_model_handle_t handle) {
248 struct recognition_context *model_context = NULL;
249 if (stdev->root_model_context) {
250 struct recognition_context *current_model_context = stdev->root_model_context;
251 while(current_model_context) {
252 if (current_model_context->model_handle == handle) {
253 model_context = current_model_context;
254 break;
255 }
256 current_model_context = current_model_context->next;
257 }
258 }
259 return model_context;
260}
261
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800262static void *callback_thread_loop(void *context) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700263 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)context;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800264 struct sockaddr_in incoming_info;
265 struct sockaddr_in self_info;
266 int self_socket;
267 socklen_t sock_size = sizeof(struct sockaddr_in);
268 memset(&self_info, 0, sizeof(self_info));
269 self_info.sin_family = AF_INET;
270 self_info.sin_addr.s_addr = htonl(INADDR_ANY);
271 self_info.sin_port = htons(14035);
Eric Laurentcbca9052014-04-18 17:54:10 -0700272
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800273 bool exit = false;
274 while(!exit) {
275 int received_count;
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800276 int requested_count = 2;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800277 char buffer[requested_count];
278 ALOGE("Opening socket");
279 self_socket = socket(AF_INET, SOCK_STREAM, 0);
280 if (self_socket < 0) {
281 ALOGE("Error on socket creation");
282 exit = true;
283 } else {
284 ALOGI("Socket created");
285 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700286
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800287 int reuse = 1;
288 if (setsockopt(self_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) {
289 ALOGE("setsockopt(SO_REUSEADDR) failed");
290 }
291
292 int bind_result = bind(self_socket, (struct sockaddr *)&self_info, sizeof(struct sockaddr));
293 if (bind_result < 0) {
294 ALOGE("Error on bind");
295 exit = true;
296 }
297
298 int listen_result = listen(self_socket, 1);
299 if (listen_result < 0) {
300 ALOGE("Error on Listen");
301 exit = true;
302 }
303
304 while(!exit) {
305 int con_socket = accept(self_socket, (struct sockaddr *)&incoming_info, &sock_size);
306 if (!con_socket) {
307 ALOGE("Lost socket, cannot send trigger");
308 break;
309 }
310 ALOGI("Connection from %s", inet_ntoa(incoming_info.sin_addr));
311 received_count = recv(con_socket, buffer, requested_count, 0);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800312 pthread_mutex_lock(&stdev->lock);
313 if (received_count > 0) {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800314 unsigned int index = buffer[0] - 1;
315 ALOGI("Received data");
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800316 if (buffer[0] == 0) {
317 ALOGI("Received kill signal: stop listening to incoming server messages");
318 exit = true;
319 } else if (index < hw_properties.max_sound_models) {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800320 int TYPE_RECOGNITION = 0;
321 int TYPE_MODEL_UPDATE = 1;
322 int action = TYPE_RECOGNITION;
323
324 if (received_count > 1) {
325 // got a second instruction
326 action = buffer[1];
327 ALOGI("Got action instruction: %d", action);
328 }
329
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800330 struct recognition_context *model_context = NULL;
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800331 struct recognition_context *current_model_context = stdev->root_model_context;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800332 int model_index = 0;
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800333 while(current_model_context) {
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800334 if (model_index == index) {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800335 model_context = current_model_context;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800336 break;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800337 }
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800338 current_model_context = current_model_context->next;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800339 model_index++;
340 }
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800341
342 if (!model_context) {
343 ALOGI("Sound Model Does Not Exist at this Index: %d", index);
344 } else if (action == TYPE_RECOGNITION) {
345 ALOGI("Going to send trigger for model index #%d", index );
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800346 send_recognition_event(model_context->model_handle,
347 model_context->model_type,
348 model_context->recognition_callback,
349 model_context->recognition_cookie,
350 model_context->config);
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800351
352 // After recognition callback, stop recognition
353 free(model_context->config);
354 model_context->config = NULL;
355 model_context->recognition_callback = NULL;
356 model_context->recognition_cookie = NULL;
357 if (!recognition_callback_exists(stdev)) {
358 exit = true;
359 }
360 } else if (action == TYPE_MODEL_UPDATE) {
361 ALOGI("Going to send sound model update for model index #%d", index );
362 send_model_event(model_context->model_handle,
363 model_context->model_callback,
364 model_context->model_cookie);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800365 } else {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800366 ALOGI("Action/event type is not recognized: %d", action);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800367 }
368 } else {
369 ALOGI("Data is not recognized: %d", index);
370 }
371 } else {
372 ALOGI("Received sata is size 0");
373 }
374 pthread_mutex_unlock(&stdev->lock);
375 close(con_socket);
376 }
377 ALOGE("Closing socket");
378 close(self_socket);
Eric Laurentcbca9052014-04-18 17:54:10 -0700379 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700380
381 return NULL;
382}
383
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800384static void send_loop_kill_signal() {
385 ALOGI("Sending loop thread kill signal");
386 int self_socket = socket(AF_INET, SOCK_STREAM, 0);
387 struct sockaddr_in remote_info;
388 memset(&remote_info, 0, sizeof(remote_info));
389 remote_info.sin_family = AF_INET;
390 remote_info.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
391 remote_info.sin_port = htons(14035);
392 if (connect(self_socket, (struct sockaddr *)&remote_info, sizeof(struct sockaddr)) == 0) {
393 char msg[] = {0};
394 send(self_socket, msg, 1, 0);
395 } else {
396 ALOGI("Could not connect");
397 }
398 close(self_socket);
399 ALOGI("Sent loop thread kill signal");
400}
401
Eric Laurentcbca9052014-04-18 17:54:10 -0700402static int stdev_get_properties(const struct sound_trigger_hw_device *dev,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800403 struct sound_trigger_properties *properties) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700404 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
405
406 ALOGI("%s", __func__);
407 if (properties == NULL)
408 return -EINVAL;
409 memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties));
410 return 0;
411}
412
413static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
414 struct sound_trigger_sound_model *sound_model,
415 sound_model_callback_t callback,
416 void *cookie,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800417 sound_model_handle_t *handle) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700418 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
419 int status = 0;
420
421 ALOGI("%s stdev %p", __func__, stdev);
422 pthread_mutex_lock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800423
Eric Laurentcbca9052014-04-18 17:54:10 -0700424 if (handle == NULL || sound_model == NULL) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800425 pthread_mutex_unlock(&stdev->lock);
426 return -EINVAL;
Eric Laurentcbca9052014-04-18 17:54:10 -0700427 }
428 if (sound_model->data_size == 0 ||
429 sound_model->data_offset < sizeof(struct sound_trigger_sound_model)) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800430 pthread_mutex_unlock(&stdev->lock);
431 return -EINVAL;
Eric Laurentcbca9052014-04-18 17:54:10 -0700432 }
433
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800434 struct recognition_context *model_context;
435 model_context = malloc(sizeof(struct recognition_context));
436 if(!model_context) {
437 ALOGW("Could not allocate recognition_context");
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800438 pthread_mutex_unlock(&stdev->lock);
439 return -ENOSYS;
440 }
441
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800442 // Add the new model context to the recognition_context linked list
443 if (stdev->root_model_context) {
444 // Find the tail
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800445 struct recognition_context *current_model_context = stdev->root_model_context;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800446 int model_count = 0;
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800447 while(current_model_context->next) {
448 current_model_context = current_model_context->next;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800449 model_count++;
450 if (model_count >= hw_properties.max_sound_models) {
451 ALOGW("Can't load model: reached max sound model limit");
452 free(model_context);
453 pthread_mutex_unlock(&stdev->lock);
454 return -ENOSYS;
455 }
456 }
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800457 current_model_context->next = model_context;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800458 } else {
459 stdev->root_model_context = model_context;
460 }
461
462 model_context->model_handle = generate_sound_model_id(dev);
463 *handle = model_context->model_handle;
464 model_context->model_type = sound_model->type;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800465
Eric Laurentcbca9052014-04-18 17:54:10 -0700466 char *data = (char *)sound_model + sound_model->data_offset;
467 ALOGI("%s data size %d data %d - %d", __func__,
468 sound_model->data_size, data[0], data[sound_model->data_size - 1]);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800469 model_context->model_callback = callback;
470 model_context->model_cookie = cookie;
471 model_context->config = NULL;
472 model_context->recognition_callback = NULL;
473 model_context->recognition_cookie = NULL;
Eric Laurentcbca9052014-04-18 17:54:10 -0700474
Eric Laurentcbca9052014-04-18 17:54:10 -0700475 pthread_mutex_unlock(&stdev->lock);
476 return status;
477}
478
479static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800480 sound_model_handle_t handle) {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800481 // If recognizing, stop_recognition must be called for a sound model before unload_sound_model
Eric Laurentcbca9052014-04-18 17:54:10 -0700482 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
483 int status = 0;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800484 ALOGI("unload_sound_model");
Eric Laurentcbca9052014-04-18 17:54:10 -0700485 pthread_mutex_lock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800486
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800487 struct recognition_context *model_context = NULL;
488 struct recognition_context *previous_model_context = NULL;
489 if (stdev->root_model_context) {
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800490 struct recognition_context *current_model_context = stdev->root_model_context;
491 while(current_model_context) {
492 if (current_model_context->model_handle == handle) {
493 model_context = current_model_context;
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800494 break;
495 }
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800496 previous_model_context = current_model_context;
497 current_model_context = current_model_context->next;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800498 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700499 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800500 if (!model_context) {
501 ALOGW("Can't find sound model handle %d in registered list", handle);
Eric Laurentcbca9052014-04-18 17:54:10 -0700502 pthread_mutex_unlock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800503 return -ENOSYS;
Eric Laurentcbca9052014-04-18 17:54:10 -0700504 }
505
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800506 if(previous_model_context) {
507 previous_model_context->next = model_context->next;
508 } else {
509 stdev->root_model_context = model_context->next;
510 }
511 free(model_context->config);
512 free(model_context);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800513
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800514 pthread_mutex_unlock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800515
Eric Laurentcbca9052014-04-18 17:54:10 -0700516 return status;
517}
518
519static int stdev_start_recognition(const struct sound_trigger_hw_device *dev,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800520 sound_model_handle_t handle,
Eric Laurent30f3e6d2014-07-06 16:08:45 -0700521 const struct sound_trigger_recognition_config *config,
Eric Laurentcbca9052014-04-18 17:54:10 -0700522 recognition_callback_t callback,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800523 void *cookie) {
524 ALOGI("%s", __func__);
Eric Laurentcbca9052014-04-18 17:54:10 -0700525 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
Eric Laurentcbca9052014-04-18 17:54:10 -0700526 pthread_mutex_lock(&stdev->lock);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800527
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800528 /* If other models running with callbacks, don't start trigger thread */
529 bool other_callbacks_found = recognition_callback_exists(stdev);
530
531 struct recognition_context *model_context = get_model_context(stdev, handle);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800532 if (!model_context) {
533 ALOGW("Can't find sound model handle %d in registered list", handle);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800534 pthread_mutex_unlock(&stdev->lock);
535 return -ENOSYS;
Eric Laurentcbca9052014-04-18 17:54:10 -0700536 }
537
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800538 free(model_context->config);
539 model_context->config = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800540 if (config) {
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800541 model_context->config = malloc(sizeof(*config));
542 if (!model_context->config) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800543 pthread_mutex_unlock(&stdev->lock);
544 return -ENOMEM;
545 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800546 memcpy(model_context->config, config, sizeof(*config));
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800547 }
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800548 model_context->recognition_callback = callback;
549 model_context->recognition_cookie = cookie;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800550
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800551 if (!other_callbacks_found) {
552 pthread_create(&stdev->callback_thread, (const pthread_attr_t *) NULL,
553 callback_thread_loop, stdev);
554 }
555
Eric Laurentcbca9052014-04-18 17:54:10 -0700556 pthread_mutex_unlock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800557 return 0;
Eric Laurentcbca9052014-04-18 17:54:10 -0700558}
559
560static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev,
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800561 sound_model_handle_t handle) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700562 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800563 ALOGI("%s", __func__);
Eric Laurentcbca9052014-04-18 17:54:10 -0700564 pthread_mutex_lock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800565
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800566 struct recognition_context *model_context = get_model_context(stdev, handle);
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800567 if (!model_context) {
568 ALOGW("Can't find sound model handle %d in registered list", handle);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800569 pthread_mutex_unlock(&stdev->lock);
570 return -ENOSYS;
Eric Laurentcbca9052014-04-18 17:54:10 -0700571 }
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800572
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800573 free(model_context->config);
574 model_context->config = NULL;
575 model_context->recognition_callback = NULL;
576 model_context->recognition_cookie = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800577
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800578 /* If no more models running with callbacks, stop trigger thread */
Ryan Bavettac2bdc552016-02-15 15:51:46 -0800579 if (!recognition_callback_exists(stdev)) {
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800580 send_loop_kill_signal();
581 pthread_mutex_unlock(&stdev->lock);
582 pthread_join(stdev->callback_thread, (void **)NULL);
583 } else {
584 pthread_mutex_unlock(&stdev->lock);
585 }
586
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800587 return 0;
Eric Laurentcbca9052014-04-18 17:54:10 -0700588}
589
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800590__attribute__ ((visibility ("default")))
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800591int sound_trigger_open_for_streaming() {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800592 int ret = 0;
593 return ret;
594}
595
596__attribute__ ((visibility ("default")))
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800597size_t sound_trigger_read_samples(int audio_handle, void *buffer, size_t buffer_len) {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800598 size_t ret = 0;
599 return ret;
600}
601
602__attribute__ ((visibility ("default")))
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800603int sound_trigger_close_for_streaming(int audio_handle __unused) {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800604 return 0;
605}
606
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800607static int stdev_close(hw_device_t *device) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700608 free(device);
609 return 0;
610}
611
612static int stdev_open(const hw_module_t* module, const char* name,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800613 hw_device_t** device) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700614 struct stub_sound_trigger_device *stdev;
615 int ret;
616
617 if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0)
618 return -EINVAL;
619
620 stdev = calloc(1, sizeof(struct stub_sound_trigger_device));
621 if (!stdev)
622 return -ENOMEM;
623
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800624 stdev->next_sound_model_id = 1;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800625
Eric Laurentcbca9052014-04-18 17:54:10 -0700626 stdev->device.common.tag = HARDWARE_DEVICE_TAG;
627 stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;
628 stdev->device.common.module = (struct hw_module_t *) module;
629 stdev->device.common.close = stdev_close;
630 stdev->device.get_properties = stdev_get_properties;
631 stdev->device.load_sound_model = stdev_load_sound_model;
632 stdev->device.unload_sound_model = stdev_unload_sound_model;
633 stdev->device.start_recognition = stdev_start_recognition;
634 stdev->device.stop_recognition = stdev_stop_recognition;
635
636 pthread_mutex_init(&stdev->lock, (const pthread_mutexattr_t *) NULL);
Eric Laurentcbca9052014-04-18 17:54:10 -0700637
638 *device = &stdev->device.common;
639
640 return 0;
641}
642
643static struct hw_module_methods_t hal_module_methods = {
644 .open = stdev_open,
645};
646
647struct sound_trigger_module HAL_MODULE_INFO_SYM = {
648 .common = {
649 .tag = HARDWARE_MODULE_TAG,
650 .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0,
651 .hal_api_version = HARDWARE_HAL_API_VERSION,
652 .id = SOUND_TRIGGER_HARDWARE_MODULE_ID,
653 .name = "Default sound trigger HAL",
654 .author = "The Android Open Source Project",
655 .methods = &hal_module_methods,
656 },
657};
Ryan Bavettacc6541c2016-02-09 21:20:51 -0800658