Stub sound trigger HAL changes:
- Added a simple command parsing ability for text commands.
- Ability to output text via the socket interface.
Bug: 27227051
Change-Id: I9ea06897d69cf55b58aba5cc30f1c32773b3da00
diff --git a/modules/soundtrigger/sound_trigger_hw.c b/modules/soundtrigger/sound_trigger_hw.c
index 972c520..8aad1aa 100644
--- a/modules/soundtrigger/sound_trigger_hw.c
+++ b/modules/soundtrigger/sound_trigger_hw.c
@@ -38,8 +38,19 @@
#define LOG_TAG "sound_trigger_hw_default"
#define LOG_NDEBUG 1
+#define PARSE_BUF_LEN 1024 // Length of the parsing buffer.S
+
+// The following commands work with the network port:
+#define COMMAND_LS "ls"
+#define COMMAND_TRIGGER "trig" // Argument: model index.
+#define COMMAND_MODEL_EVENT "model_event" // Argument: model index.
+#define COMMAND_CLOSE "close" // Close just closes the network port, keeps thread running.
+#define COMMAND_END "end" // Closes connection and stops the thread.
+
+#define ERROR_BAD_COMMAND "Bad command"
#include <errno.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -63,7 +74,7 @@
"Sound Trigger stub HAL", // description
1, // version
{ 0xed7a7d60, 0xc65e, 0x11e3, 0x9be4, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
- 2, // max_sound_models
+ 4, // max_sound_models
1, // max_key_phrases
1, // max_users
RECOGNITION_MODE_VOICE_TRIGGER, // recognition_modes
@@ -90,6 +101,8 @@
struct recognition_context *next;
};
+char tmp_write_buffer[PARSE_BUF_LEN];
+
struct stub_sound_trigger_device {
struct sound_trigger_hw_device device;
pthread_mutex_t lock;
@@ -308,70 +321,10 @@
break;
}
ALOGI("Connection from %s", inet_ntoa(incoming_info.sin_addr));
- received_count = recv(con_socket, buffer, requested_count, 0);
- pthread_mutex_lock(&stdev->lock);
- if (received_count > 0) {
- unsigned int index = buffer[0] - 1;
- ALOGI("Received data");
- if (buffer[0] == 0) {
- ALOGI("Received kill signal: stop listening to incoming server messages");
- exit = true;
- } else if (index < hw_properties.max_sound_models) {
- int TYPE_RECOGNITION = 0;
- int TYPE_MODEL_UPDATE = 1;
- int action = TYPE_RECOGNITION;
-
- if (received_count > 1) {
- // got a second instruction
- action = buffer[1];
- ALOGI("Got action instruction: %d", action);
- }
-
- struct recognition_context *model_context = NULL;
- struct recognition_context *current_model_context = stdev->root_model_context;
- int model_index = 0;
- while(current_model_context) {
- if (model_index == index) {
- model_context = current_model_context;
- break;
- }
- current_model_context = current_model_context->next;
- model_index++;
- }
-
- if (!model_context) {
- ALOGI("Sound Model Does Not Exist at this Index: %d", index);
- } else if (action == TYPE_RECOGNITION) {
- ALOGI("Going to send trigger for model index #%d", index );
- send_recognition_event(model_context->model_handle,
- model_context->model_type,
- model_context->recognition_callback,
- model_context->recognition_cookie,
- model_context->config);
-
- // After recognition callback, stop recognition
- free(model_context->config);
- model_context->config = NULL;
- model_context->recognition_callback = NULL;
- model_context->recognition_cookie = NULL;
- if (!recognition_callback_exists(stdev)) {
- exit = true;
- }
- } else if (action == TYPE_MODEL_UPDATE) {
- ALOGI("Going to send sound model update for model index #%d", index );
- send_model_event(model_context->model_handle,
- model_context->model_callback,
- model_context->model_cookie);
- } else {
- ALOGI("Action/event type is not recognized: %d", action);
- }
- } else {
- ALOGI("Data is not recognized: %d", index);
- }
- } else {
- ALOGI("Received sata is size 0");
+ if (!parse_socket_data(con_socket, stdev)) {
+ ALOGI("Done processing commands over network. Stopping thread.");
+ exit = true;
}
- pthread_mutex_unlock(&stdev->lock);
close(con_socket);
}
ALOGE("Closing socket");
@@ -381,6 +334,193 @@
return NULL;
}
+void write_bad_command_error(int conn_socket, char* command) {
+ int num = snprintf(tmp_write_buffer, PARSE_BUF_LEN, "Bad command received: %s", command);
+ tmp_write_buffer[PARSE_BUF_LEN - 1] = '\0'; // Just to be sure.
+ tmp_write_buffer[PARSE_BUF_LEN - 2] = '\n';
+ write(conn_socket, tmp_write_buffer, num);
+}
+
+void write_string(int conn_socket, char* str) {
+ int num = snprintf(tmp_write_buffer, PARSE_BUF_LEN, "%s", str);
+ tmp_write_buffer[PARSE_BUF_LEN - 1] = '\0';
+ tmp_write_buffer[PARSE_BUF_LEN - 2] = '\n';
+ write(conn_socket, tmp_write_buffer, num);
+}
+
+void write_vastr(int conn_socket, char* format, ...) {
+ va_list argptr;
+ va_start(argptr, format);
+ int num = vsnprintf(tmp_write_buffer, PARSE_BUF_LEN, format, argptr);
+ va_end(argptr);
+ tmp_write_buffer[PARSE_BUF_LEN - 1] = '\0';
+ tmp_write_buffer[PARSE_BUF_LEN - 2] = '\n';
+ write(conn_socket, tmp_write_buffer, num);
+}
+
+void list_models(int conn_socket, char* buffer,
+ struct stub_sound_trigger_device* stdev) {
+ ALOGI("%s", __func__);
+ struct recognition_context *last_model_context = stdev->root_model_context;
+ int model_index = 0;
+ if (!last_model_context) {
+ ALOGI("ZERO Models exist.");
+ write_string(conn_socket, "Zero models exist.\n");
+ }
+ while (last_model_context) {
+ write_vastr(conn_socket, "Model Index: %d\n", model_index);
+ ALOGI("Model Index: %d\n", model_index);
+ write_vastr(conn_socket, "Model handle: %d\n",
+ last_model_context->model_handle);
+ ALOGI("Model handle: %d\n", last_model_context->model_handle);
+ sound_trigger_sound_model_type_t model_type = last_model_context->model_type;
+
+ if (model_type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ write_string(conn_socket, "Keyphrase sound Model.\n");
+ ALOGI("Keyphrase sound Model.\n");
+ } else if (model_type == SOUND_MODEL_TYPE_GENERIC) {
+ write_string(conn_socket, "Generic sound Model.\n");
+ ALOGI("Generic sound Model.\n");
+ } else {
+ write_vastr(conn_socket, "Unknown sound model type: %d\n",
+ model_type);
+ ALOGI("Unknown sound model type: %d\n", model_type);
+ }
+ write_string(conn_socket, "----\n\n");
+ ALOGI("----\n\n");
+ last_model_context = last_model_context->next;
+ model_index++;
+ }
+}
+
+// Returns model at the given index, null otherwise (error, doesn't exist, etc).
+// Note that here index starts from zero.
+struct recognition_context* fetch_model_at_index(
+ struct stub_sound_trigger_device* stdev, int index) {
+ ALOGI("%s", __func__);
+ struct recognition_context *model_context = NULL;
+ struct recognition_context *last_model_context = stdev->root_model_context;
+ int model_index = 0;
+ while(last_model_context) {
+ if (model_index == index) {
+ model_context = last_model_context;
+ break;
+ }
+ last_model_context = last_model_context->next;
+ model_index++;
+ }
+ return model_context;
+}
+
+void send_trigger(int conn_socket, char* buffer,
+ struct stub_sound_trigger_device* stdev) {
+ ALOGI("%s", __func__);
+ char* model_handle_str = strtok(NULL, " ");
+ if (model_handle_str == NULL) {
+ write_string(conn_socket, "Bad sound model id.\n");
+ return;
+ }
+ int index = -1;
+ if (sscanf(model_handle_str, "%d", &index) <= 0) {
+ write_vastr(conn_socket, "Unable to parse sound model index: %s\n", model_handle_str);
+ return;
+ }
+
+ if (index < (int)hw_properties.max_sound_models) {
+ ALOGI("Going to send trigger for model index #%d", index );
+ struct recognition_context *model_context = fetch_model_at_index(stdev, index);
+ if (model_context) {
+ send_recognition_event(model_context->model_handle,
+ model_context->model_type,
+ model_context->recognition_callback,
+ model_context->recognition_cookie,
+ model_context->config);
+ } else {
+ ALOGI("Sound Model Does Not Exist at this Index: %d", index);
+ write_string(conn_socket, "Sound Model Does Not Exist at given Index.\n");
+ }
+ }
+}
+
+void process_send_model_event(int conn_socket, char* buffer,
+ struct stub_sound_trigger_device* stdev) {
+ ALOGI("%s", __func__);
+ char* model_handle_str = strtok(NULL, " ");
+ if (model_handle_str == NULL) {
+ write_string(conn_socket, "Bad sound model id.\n");
+ return;
+ }
+ int index = -1;
+ if (sscanf(model_handle_str, "%d", &index) <= 0) {
+ write_vastr(conn_socket, "Unable to parse sound model index: %s\n", model_handle_str);
+ return;
+ }
+
+ if (index < (int)hw_properties.max_sound_models) {
+ ALOGI("Going to model event for model index #%d", index );
+ struct recognition_context *model_context = fetch_model_at_index(stdev, index);
+ if (model_context) {
+
+ send_model_event(model_context->model_handle,
+ model_context->model_callback,
+ model_context->model_cookie);
+ } else {
+ ALOGI("Sound Model Does Not Exist at this Index: %d", index);
+ write_string(conn_socket, "Sound Model Does Not Exist at given Index.\n");
+ }
+ }
+}
+
+// Gets the next word from buffer, replaces '\n' or ' ' with '\0'.
+char* get_command(char* buffer) {
+ char* command = strtok(buffer, " ");
+ char* newline = strchr(command, '\n');
+ if (newline != NULL) {
+ *newline = '\0';
+ }
+ return command;
+}
+
+// Parses data coming in from the local socket, executes commands. Returns when
+// done. Return code indicates whether the server should continue listening or
+// abort (true if continue listening).
+bool parse_socket_data(int conn_socket, struct stub_sound_trigger_device* stdev) {
+ ALOGI("Calling parse_socket_data");
+ bool input_done = false;
+ char buffer[PARSE_BUF_LEN];
+ FILE* input_fp = fdopen(conn_socket, "r");
+ pthread_mutex_lock(&stdev->lock);
+ bool continue_listening = true;
+ while(!input_done) {
+ if (fgets(buffer, PARSE_BUF_LEN, input_fp) != NULL) {
+ char* command = strtok(buffer, " \n");
+ if (command == NULL) {
+ write_bad_command_error(conn_socket, command);
+ } else if (strncmp(command, COMMAND_LS, 2) == 0) {
+ list_models(conn_socket, buffer, stdev);
+ } else if (strcmp(command, COMMAND_TRIGGER) == 0) {
+ send_trigger(conn_socket, buffer, stdev);
+ } else if (strcmp(command, COMMAND_MODEL_EVENT) == 0) {
+ send_model_event(conn_socket, buffer, stdev);
+ } else if (strncmp(command, COMMAND_CLOSE, 5) == 0) {
+ ALOGI("Closing this connection.");
+ write_string(conn_socket, "Closing this connection.");
+ break;
+ } else if (strncmp(command, COMMAND_END, 3) == 0) {
+ ALOGI("End command received.");
+ write_string(conn_socket, "End command received. Stopping connection.");
+ continue_listening = false;
+ break;
+ }
+ } else {
+ ALOGI("parse_socket_data done (got null)");
+ input_done = true; // break.
+ }
+ }
+ pthread_mutex_unlock(&stdev->lock);
+ return continue_listening;
+}
+
static void send_loop_kill_signal() {
ALOGI("Sending loop thread kill signal");
int self_socket = socket(AF_INET, SOCK_STREAM, 0);
@@ -390,8 +530,7 @@
remote_info.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
remote_info.sin_port = htons(14035);
if (connect(self_socket, (struct sockaddr *)&remote_info, sizeof(struct sockaddr)) == 0) {
- char msg[] = {0};
- send(self_socket, msg, 1, 0);
+ send(self_socket, COMMAND_END, 1, 0);
} else {
ALOGI("Could not connect");
}
@@ -415,6 +554,7 @@
sound_model_callback_t callback,
void *cookie,
sound_model_handle_t *handle) {
+ ALOGI("load_sound_model.");
struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
int status = 0;
@@ -471,6 +611,7 @@
model_context->config = NULL;
model_context->recognition_callback = NULL;
model_context->recognition_cookie = NULL;
+ ALOGI("Sound model loaded: Handle %d ", *handle);
pthread_mutex_unlock(&stdev->lock);
return status;
@@ -481,7 +622,7 @@
// If recognizing, stop_recognition must be called for a sound model before unload_sound_model
struct stub_sound_trigger_device *stdev = (struct stub_sound_trigger_device *)dev;
int status = 0;
- ALOGI("unload_sound_model");
+ ALOGI("unload_sound_model.");
pthread_mutex_lock(&stdev->lock);
struct recognition_context *model_context = NULL;
@@ -510,7 +651,6 @@
}
free(model_context->config);
free(model_context);
-
pthread_mutex_unlock(&stdev->lock);
return status;
@@ -622,6 +762,7 @@
return -ENOMEM;
stdev->next_sound_model_id = 1;
+ stdev->root_model_context = NULL;
stdev->device.common.tag = HARDWARE_DEVICE_TAG;
stdev->device.common.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_0;