blob: 2c1cc9c4388948d65170658257fc1946462bf75c [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 Bavettabe0c8fd2016-02-01 15:17:12 -080028 * To enable this file, you can make with command line parameter
29 * SOUND_TRIGGER_USE_STUB_MODULE=1
Ryan Bavetta4615aad2016-01-27 16:12:04 -080030 */
31
Eric Laurentcbca9052014-04-18 17:54:10 -070032#define LOG_TAG "sound_trigger_hw_default"
33/*#define LOG_NDEBUG 0*/
34
35#include <errno.h>
Ryan Bavetta4615aad2016-01-27 16:12:04 -080036#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40#include <arpa/inet.h>
41#include <sys/types.h>
42#include <netinet/in.h>
43#include <sys/socket.h>
44
45#include <errno.h>
Eric Laurentcbca9052014-04-18 17:54:10 -070046#include <pthread.h>
47#include <sys/prctl.h>
48#include <cutils/log.h>
49
50#include <hardware/hardware.h>
51#include <system/sound_trigger.h>
52#include <hardware/sound_trigger.h>
53
Ryan Bavetta4615aad2016-01-27 16:12:04 -080054/* Although max_sound_models is specified in sound_trigger_properties, having a maximum maximum
55allows a dramatic simplification of data structures in this file */
56#define MAX_MAX_SOUND_MODELS 5
57
Eric Laurentcbca9052014-04-18 17:54:10 -070058static const struct sound_trigger_properties hw_properties = {
59 "The Android Open Source Project", // implementor
60 "Sound Trigger stub HAL", // description
61 1, // version
62 { 0xed7a7d60, 0xc65e, 0x11e3, 0x9be4, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
Ryan Bavetta4615aad2016-01-27 16:12:04 -080063 2, // max_sound_models
Eric Laurentcbca9052014-04-18 17:54:10 -070064 1, // max_key_phrases
65 1, // max_users
66 RECOGNITION_MODE_VOICE_TRIGGER, // recognition_modes
67 false, // capture_transition
68 0, // max_buffer_ms
69 false, // concurrent_capture
Eric Laurent83cd8302014-07-30 08:58:39 -070070 false, // trigger_in_event
Eric Laurentcbca9052014-04-18 17:54:10 -070071 0 // power_consumption_mw
72};
73
Ryan Bavetta4615aad2016-01-27 16:12:04 -080074struct recognition_context {
75 /* Sound Model Information Modified On Load */
76 sound_model_handle_t loaded_sound_model;
Eric Laurentcbca9052014-04-18 17:54:10 -070077 sound_model_callback_t sound_model_callback;
78 void *sound_model_cookie;
Ryan Bavetta4615aad2016-01-27 16:12:04 -080079
80 /* Sound Model Information Modified On Recognition Start */
81 struct sound_trigger_recognition_config *config;
82 recognition_callback_t recognition_callback;
83 void *recognition_cookie;
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -080084};
Ryan Bavetta4615aad2016-01-27 16:12:04 -080085
86struct stub_sound_trigger_device {
87 struct sound_trigger_hw_device device;
Eric Laurentcbca9052014-04-18 17:54:10 -070088 pthread_mutex_t lock;
Ryan Bavetta4615aad2016-01-27 16:12:04 -080089 pthread_t callback_thread;
90
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -080091 struct recognition_context model_context[MAX_MAX_SOUND_MODELS];
Ryan Bavetta4615aad2016-01-27 16:12:04 -080092
93 int next_sound_model_id;
Eric Laurentcbca9052014-04-18 17:54:10 -070094};
95
Ryan Bavetta4615aad2016-01-27 16:12:04 -080096/* Will reuse ids when overflow occurs */
97static unsigned int generate_sound_model_id(const struct sound_trigger_hw_device *dev) {
98 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
99 int new_id = stdev->next_sound_model_id;
100 ++stdev->next_sound_model_id;
101 if (stdev->next_sound_model_id == 0) {
102 stdev->next_sound_model_id = 1;
103 }
104 return new_id;
105}
Eric Laurentcbca9052014-04-18 17:54:10 -0700106
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800107static char *sound_trigger_event_alloc(struct stub_sound_trigger_device *stdev,
108 sound_model_handle_t handle) {
109 struct sound_trigger_phrase_recognition_event *event;
110 char *data;
111 data = (char *)calloc(1, sizeof(struct sound_trigger_phrase_recognition_event));
112 if (!data)
113 return NULL;
114
115 unsigned int model_index;
116 bool found = false;
117 for(model_index = 0; model_index < hw_properties.max_sound_models; model_index++) {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800118 if (stdev->model_context[model_index].loaded_sound_model == handle) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800119 found = true;
120 break;
121 }
122 }
123 if (found == false) {
124 ALOGW("Can't find model");
125 return NULL;
126 }
127
128 event = (struct sound_trigger_phrase_recognition_event *)data;
129 event->common.status = RECOGNITION_STATUS_SUCCESS;
130 event->common.type = SOUND_MODEL_TYPE_KEYPHRASE;
131 event->common.model = handle;
132
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800133 if (stdev->model_context[model_index].config) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800134 unsigned int i;
135
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800136 event->num_phrases = stdev->model_context[model_index].config->num_phrases;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800137 if (event->num_phrases > SOUND_TRIGGER_MAX_PHRASES)
138 event->num_phrases = SOUND_TRIGGER_MAX_PHRASES;
139 for (i=0; i < event->num_phrases; i++)
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800140 memcpy(&event->phrase_extras[i], &stdev->model_context[model_index].config->phrases[i],
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800141 sizeof(struct sound_trigger_phrase_recognition_extra));
142 }
143
144 event->num_phrases = 1;
145 event->phrase_extras[0].confidence_level = 100;
146 event->phrase_extras[0].num_levels = 1;
147 event->phrase_extras[0].levels[0].level = 100;
148 event->phrase_extras[0].levels[0].user_id = 0;
149 // Signify that all the data is comming through streaming, not through the buffer.
150 event->common.capture_available = true;
151
152 event->common.audio_config = AUDIO_CONFIG_INITIALIZER;
153 event->common.audio_config.sample_rate = 16000;
154 event->common.audio_config.channel_mask = AUDIO_CHANNEL_IN_MONO;
155 event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
156
157 return data;
158}
159
160static void *callback_thread_loop(void *context) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700161 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)context;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800162 struct sockaddr_in incoming_info;
163 struct sockaddr_in self_info;
164 int self_socket;
165 socklen_t sock_size = sizeof(struct sockaddr_in);
166 memset(&self_info, 0, sizeof(self_info));
167 self_info.sin_family = AF_INET;
168 self_info.sin_addr.s_addr = htonl(INADDR_ANY);
169 self_info.sin_port = htons(14035);
Eric Laurentcbca9052014-04-18 17:54:10 -0700170
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800171 bool exit = false;
172 while(!exit) {
173 int received_count;
174 int requested_count = 1;
175 char buffer[requested_count];
176 ALOGE("Opening socket");
177 self_socket = socket(AF_INET, SOCK_STREAM, 0);
178 if (self_socket < 0) {
179 ALOGE("Error on socket creation");
180 exit = true;
181 } else {
182 ALOGI("Socket created");
183 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700184
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800185 int reuse = 1;
186 if (setsockopt(self_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) {
187 ALOGE("setsockopt(SO_REUSEADDR) failed");
188 }
189
190 int bind_result = bind(self_socket, (struct sockaddr *)&self_info, sizeof(struct sockaddr));
191 if (bind_result < 0) {
192 ALOGE("Error on bind");
193 exit = true;
194 }
195
196 int listen_result = listen(self_socket, 1);
197 if (listen_result < 0) {
198 ALOGE("Error on Listen");
199 exit = true;
200 }
201
202 while(!exit) {
203 int con_socket = accept(self_socket, (struct sockaddr *)&incoming_info, &sock_size);
204 if (!con_socket) {
205 ALOGE("Lost socket, cannot send trigger");
206 break;
207 }
208 ALOGI("Connection from %s", inet_ntoa(incoming_info.sin_addr));
209 received_count = recv(con_socket, buffer, requested_count, 0);
210 unsigned int index = buffer[0] - 1;
211 ALOGI("Received data");
212 pthread_mutex_lock(&stdev->lock);
213 if (received_count > 0) {
214 if (buffer[0] == 0) {
215 ALOGI("Received kill signal: stop listening to incoming server messages");
216 exit = true;
217 } else if (index < hw_properties.max_sound_models) {
218 ALOGI("Going to send trigger for model #%d", index );
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800219 if (stdev->model_context[index].recognition_callback != NULL) {
220 sound_model_handle_t handle = stdev->model_context[index].loaded_sound_model;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800221 if (handle == 0) {
222 ALOGW("This trigger is not loaded");
223 } else {
224 struct sound_trigger_phrase_recognition_event *event;
225 event = (struct sound_trigger_phrase_recognition_event *)
226 sound_trigger_event_alloc(stdev, handle);
227 if (event) {
228 ALOGI("%s send callback model %d", __func__, index);
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800229 stdev->model_context[index].recognition_callback(&event->common,
230 stdev->model_context[index].recognition_cookie);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800231 free(event);
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800232 stdev->model_context[index].recognition_callback = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800233 }
234 exit = true;
235 }
236 } else {
237 ALOGI("%s No matching callback for %d", __func__, index);
238 }
239 } else {
240 ALOGI("Data is not recognized: %d", index);
241 }
242 } else {
243 ALOGI("Received sata is size 0");
244 }
245 pthread_mutex_unlock(&stdev->lock);
246 close(con_socket);
247 }
248 ALOGE("Closing socket");
249 close(self_socket);
Eric Laurentcbca9052014-04-18 17:54:10 -0700250 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700251
252 return NULL;
253}
254
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800255static void send_loop_kill_signal() {
256 ALOGI("Sending loop thread kill signal");
257 int self_socket = socket(AF_INET, SOCK_STREAM, 0);
258 struct sockaddr_in remote_info;
259 memset(&remote_info, 0, sizeof(remote_info));
260 remote_info.sin_family = AF_INET;
261 remote_info.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
262 remote_info.sin_port = htons(14035);
263 if (connect(self_socket, (struct sockaddr *)&remote_info, sizeof(struct sockaddr)) == 0) {
264 char msg[] = {0};
265 send(self_socket, msg, 1, 0);
266 } else {
267 ALOGI("Could not connect");
268 }
269 close(self_socket);
270 ALOGI("Sent loop thread kill signal");
271}
272
Eric Laurentcbca9052014-04-18 17:54:10 -0700273static int stdev_get_properties(const struct sound_trigger_hw_device *dev,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800274 struct sound_trigger_properties *properties) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700275 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
276
277 ALOGI("%s", __func__);
278 if (properties == NULL)
279 return -EINVAL;
280 memcpy(properties, &hw_properties, sizeof(struct sound_trigger_properties));
281 return 0;
282}
283
284static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
285 struct sound_trigger_sound_model *sound_model,
286 sound_model_callback_t callback,
287 void *cookie,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800288 sound_model_handle_t *handle) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700289 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
290 int status = 0;
291
292 ALOGI("%s stdev %p", __func__, stdev);
293 pthread_mutex_lock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800294
Eric Laurentcbca9052014-04-18 17:54:10 -0700295 if (handle == NULL || sound_model == NULL) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800296 pthread_mutex_unlock(&stdev->lock);
297 return -EINVAL;
Eric Laurentcbca9052014-04-18 17:54:10 -0700298 }
299 if (sound_model->data_size == 0 ||
300 sound_model->data_offset < sizeof(struct sound_trigger_sound_model)) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800301 pthread_mutex_unlock(&stdev->lock);
302 return -EINVAL;
Eric Laurentcbca9052014-04-18 17:54:10 -0700303 }
304
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800305 /* Find if there is space for this sound model */
306 unsigned int model_index;
307 bool found = false;
308 for(model_index = 0; model_index < hw_properties.max_sound_models; model_index++) {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800309 if (stdev->model_context[model_index].loaded_sound_model == 0) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800310 found = true;
311 break;
312 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700313 }
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800314 if (found == false) {
315 ALOGW("Can't load model: reached max sound model limit");
316 pthread_mutex_unlock(&stdev->lock);
317 return -ENOSYS;
318 }
319
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800320 stdev->model_context[model_index].loaded_sound_model = generate_sound_model_id(dev);
321 *handle = stdev->model_context[model_index].loaded_sound_model;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800322
Eric Laurentcbca9052014-04-18 17:54:10 -0700323 char *data = (char *)sound_model + sound_model->data_offset;
324 ALOGI("%s data size %d data %d - %d", __func__,
325 sound_model->data_size, data[0], data[sound_model->data_size - 1]);
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800326 stdev->model_context[model_index].sound_model_callback = callback;
327 stdev->model_context[model_index].sound_model_cookie = cookie;
Eric Laurentcbca9052014-04-18 17:54:10 -0700328
Eric Laurentcbca9052014-04-18 17:54:10 -0700329 pthread_mutex_unlock(&stdev->lock);
330 return status;
331}
332
333static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800334 sound_model_handle_t handle) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700335 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
336 int status = 0;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800337 ALOGI("unload_sound_model");
Eric Laurentcbca9052014-04-18 17:54:10 -0700338 pthread_mutex_lock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800339
340 unsigned int i;
341 unsigned int model_index;
342 bool found = false;
343 bool other_callbacks_found = false;
344 for(i = 0; i < hw_properties.max_sound_models; i++) {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800345 if (stdev->model_context[i].loaded_sound_model == handle) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800346 found = true;
347 model_index = i;
348 break;
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800349 } else if (stdev->model_context[i].recognition_callback != NULL) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800350 other_callbacks_found = true;
351 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700352 }
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800353 if (found == false) {
354 ALOGW("Can't sound model %d in registered list", handle);
Eric Laurentcbca9052014-04-18 17:54:10 -0700355 pthread_mutex_unlock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800356 return -ENOSYS;
Eric Laurentcbca9052014-04-18 17:54:10 -0700357 }
358
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800359 stdev->model_context[i].loaded_sound_model = 0;
360 stdev->model_context[i].sound_model_callback = NULL;
361 stdev->model_context[i].sound_model_cookie = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800362
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800363 free(stdev->model_context[i].config);
364 stdev->model_context[i].config = NULL;
365 stdev->model_context[i].recognition_callback = NULL;
366 stdev->model_context[i].recognition_cookie = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800367
368 /* If no more models running with callbacks, stop trigger thread */
369 if (!other_callbacks_found) {
370 send_loop_kill_signal();
371 pthread_mutex_unlock(&stdev->lock);
372 pthread_join(stdev->callback_thread, (void **)NULL);
373 } else {
374 pthread_mutex_unlock(&stdev->lock);
375 }
376
Eric Laurentcbca9052014-04-18 17:54:10 -0700377 return status;
378}
379
380static int stdev_start_recognition(const struct sound_trigger_hw_device *dev,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800381 sound_model_handle_t handle,
Eric Laurent30f3e6d2014-07-06 16:08:45 -0700382 const struct sound_trigger_recognition_config *config,
Eric Laurentcbca9052014-04-18 17:54:10 -0700383 recognition_callback_t callback,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800384 void *cookie) {
385 ALOGI("%s", __func__);
Eric Laurentcbca9052014-04-18 17:54:10 -0700386 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
Eric Laurentcbca9052014-04-18 17:54:10 -0700387 pthread_mutex_lock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800388 unsigned int i;
389 bool found = false;
390 for(i = 0; i < hw_properties.max_sound_models; i++) {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800391 if (stdev->model_context[i].loaded_sound_model == handle) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800392 found = true;
393 break;
394 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700395 }
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800396 if (found == false) {
397 ALOGW("Can't sound model %d in registered list", handle);
398 pthread_mutex_unlock(&stdev->lock);
399 return -ENOSYS;
Eric Laurentcbca9052014-04-18 17:54:10 -0700400 }
401
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800402 free(stdev->model_context[i].config);
403 stdev->model_context[i].config = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800404 if (config) {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800405 stdev->model_context[i].config = malloc(sizeof(*config));
406 if (!stdev->model_context[i].config) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800407 pthread_mutex_unlock(&stdev->lock);
408 return -ENOMEM;
409 }
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800410 memcpy(stdev->model_context[i].config, config, sizeof(*config));
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800411 }
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800412 stdev->model_context[i].recognition_callback = callback;
413 stdev->model_context[i].recognition_cookie = cookie;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800414
Eric Laurentcbca9052014-04-18 17:54:10 -0700415 pthread_create(&stdev->callback_thread, (const pthread_attr_t *) NULL,
416 callback_thread_loop, stdev);
Eric Laurentcbca9052014-04-18 17:54:10 -0700417 pthread_mutex_unlock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800418 return 0;
Eric Laurentcbca9052014-04-18 17:54:10 -0700419}
420
421static int stdev_stop_recognition(const struct sound_trigger_hw_device *dev,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800422 sound_model_handle_t handle) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700423 struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800424 ALOGI("%s", __func__);
Eric Laurentcbca9052014-04-18 17:54:10 -0700425 pthread_mutex_lock(&stdev->lock);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800426
427 unsigned int i;
428 bool found = false;
429 for(i = 0; i < hw_properties.max_sound_models; i++) {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800430 if (stdev->model_context[i].loaded_sound_model == handle) {
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800431 found = true;
432 break;
433 }
Eric Laurentcbca9052014-04-18 17:54:10 -0700434 }
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800435 if (found == false) {
436 ALOGW("Can't sound model %d in registered list", handle);
437 pthread_mutex_unlock(&stdev->lock);
438 return -ENOSYS;
Eric Laurentcbca9052014-04-18 17:54:10 -0700439 }
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800440
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800441 free(stdev->model_context[i].config);
442 stdev->model_context[i].config = NULL;
443 stdev->model_context[i].recognition_callback = NULL;
444 stdev->model_context[i].recognition_cookie = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800445
446 send_loop_kill_signal();
Eric Laurentcbca9052014-04-18 17:54:10 -0700447 pthread_mutex_unlock(&stdev->lock);
448 pthread_join(stdev->callback_thread, (void **) NULL);
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800449 return 0;
Eric Laurentcbca9052014-04-18 17:54:10 -0700450}
451
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800452__attribute__ ((visibility ("default")))
453int sound_trigger_open_for_streaming()
454{
455 int ret = 0;
456 return ret;
457}
458
459__attribute__ ((visibility ("default")))
460size_t sound_trigger_read_samples(int audio_handle, void *buffer, size_t buffer_len)
461{
462 size_t ret = 0;
463 return ret;
464}
465
466__attribute__ ((visibility ("default")))
467int sound_trigger_close_for_streaming(int audio_handle __unused)
468{
469 return 0;
470}
471
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800472static int stdev_close(hw_device_t *device) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700473 free(device);
474 return 0;
475}
476
477static int stdev_open(const hw_module_t* module, const char* name,
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800478 hw_device_t** device) {
Eric Laurentcbca9052014-04-18 17:54:10 -0700479 struct stub_sound_trigger_device *stdev;
480 int ret;
481
482 if (strcmp(name, SOUND_TRIGGER_HARDWARE_INTERFACE) != 0)
483 return -EINVAL;
484
485 stdev = calloc(1, sizeof(struct stub_sound_trigger_device));
486 if (!stdev)
487 return -ENOMEM;
488
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800489 if (MAX_MAX_SOUND_MODELS < hw_properties.max_sound_models) {
490 ALOGW("max_sound_models is greater than the allowed %d", MAX_MAX_SOUND_MODELS);
491 return -EINVAL;
492 }
493
494 stdev->next_sound_model_id = 1;
495 unsigned int i;
496 for(i = 0; i < hw_properties.max_sound_models; i++) {
Ryan Bavettabe0c8fd2016-02-01 15:17:12 -0800497 stdev->model_context[i].loaded_sound_model = 0;
498 stdev->model_context[i].sound_model_callback = NULL;
499 stdev->model_context[i].sound_model_cookie = NULL;
500 stdev->model_context[i].config = NULL;
501 stdev->model_context[i].recognition_callback = NULL;
502 stdev->model_context[i].recognition_cookie = NULL;
Ryan Bavetta4615aad2016-01-27 16:12:04 -0800503 }
504
Eric Laurentcbca9052014-04-18 17:54:10 -0700505 stdev->device.common.tag = HARDWARE_DEVICE_TAG;
506 stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;
507 stdev->device.common.module = (struct hw_module_t *) module;
508 stdev->device.common.close = stdev_close;
509 stdev->device.get_properties = stdev_get_properties;
510 stdev->device.load_sound_model = stdev_load_sound_model;
511 stdev->device.unload_sound_model = stdev_unload_sound_model;
512 stdev->device.start_recognition = stdev_start_recognition;
513 stdev->device.stop_recognition = stdev_stop_recognition;
514
515 pthread_mutex_init(&stdev->lock, (const pthread_mutexattr_t *) NULL);
Eric Laurentcbca9052014-04-18 17:54:10 -0700516
517 *device = &stdev->device.common;
518
519 return 0;
520}
521
522static struct hw_module_methods_t hal_module_methods = {
523 .open = stdev_open,
524};
525
526struct sound_trigger_module HAL_MODULE_INFO_SYM = {
527 .common = {
528 .tag = HARDWARE_MODULE_TAG,
529 .module_api_version = SOUND_TRIGGER_MODULE_API_VERSION_1_0,
530 .hal_api_version = HARDWARE_HAL_API_VERSION,
531 .id = SOUND_TRIGGER_HARDWARE_MODULE_ID,
532 .name = "Default sound trigger HAL",
533 .author = "The Android Open Source Project",
534 .methods = &hal_module_methods,
535 },
536};