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