summaryrefslogtreecommitdiff
path: root/sound_trigger_hw_iaxxx.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound_trigger_hw_iaxxx.c')
-rw-r--r--sound_trigger_hw_iaxxx.c242
1 files changed, 161 insertions, 81 deletions
diff --git a/sound_trigger_hw_iaxxx.c b/sound_trigger_hw_iaxxx.c
index 52e17be..3ca1505 100644
--- a/sound_trigger_hw_iaxxx.c
+++ b/sound_trigger_hw_iaxxx.c
@@ -72,6 +72,7 @@
#define MAX_SND_CARD (8)
#define RETRY_NUMBER (10)
#define RETRY_US (500000)
+#define TUNNEL_TIMEOUT 5
#define SENSOR_CREATE_WAIT_TIME_IN_S (1)
#define SENSOR_CREATE_WAIT_MAX_COUNT (5)
@@ -128,7 +129,9 @@ struct knowles_sound_trigger_device {
struct model_info models[MAX_MODELS];
sound_trigger_uuid_t authkw_model_uuid;
pthread_t callback_thread;
+ pthread_t monitor_thread;
pthread_mutex_t lock;
+ pthread_cond_t tunnel_create;
pthread_cond_t sensor_create;
pthread_cond_t chre_create;
int opened;
@@ -143,6 +146,7 @@ struct knowles_sound_trigger_device {
size_t (*adnc_strm_read)(long, void *, size_t);
int (*adnc_strm_close)(long);
long adnc_strm_handle[MAX_MODELS];
+ struct timespec adnc_strm_last_read[MAX_MODELS];
sound_trigger_uuid_t hotword_model_uuid;
sound_trigger_uuid_t sensor_model_uuid;
@@ -204,10 +208,13 @@ struct knowles_sound_trigger_device {
static struct knowles_sound_trigger_device g_stdev =
{
.lock = PTHREAD_MUTEX_INITIALIZER,
+ .tunnel_create = PTHREAD_COND_INITIALIZER,
.sensor_create = PTHREAD_COND_INITIALIZER,
.chre_create = PTHREAD_COND_INITIALIZER
};
+static struct timespec reset_time = {0};
+
static enum sthal_mode get_sthal_mode(struct knowles_sound_trigger_device *stdev)
{
enum sthal_mode stmode = CON_DISABLED_ST;
@@ -1194,6 +1201,7 @@ static bool do_handle_functions(struct knowles_sound_trigger_device *stdev,
ALOGD("%s: stop tunnling for index:%d", __func__, i);
stdev->adnc_strm_close(stdev->adnc_strm_handle[i]);
stdev->adnc_strm_handle[i] = 0;
+ stdev->adnc_strm_last_read[i] = reset_time;
}
}
stdev->is_streaming = 0;
@@ -1535,32 +1543,19 @@ reload_oslo:
}
stdev->is_sensor_route_enabled = false;
- if (stdev->is_sensor_destroy_in_prog == true) {
- stdev->is_sensor_destroy_in_prog = false;
- pthread_cond_signal(&stdev->sensor_create);
-
- // A timer would have been created during stop,
- // check and delete it, as there is nothing to destroy
- // at this point
- if (stdev->ss_timer_created) {
- timer_delete(stdev->ss_timer);
- stdev->ss_timer_created = false;
- }
- } else {
- // setup the sensor route
- err = setup_sensor_package(stdev->odsp_hdl);
- if (err != 0) {
- ALOGE("%s: setup Sensor package failed", __func__);
- goto exit;
- }
+ // setup the sensor route
+ err = setup_sensor_package(stdev->odsp_hdl);
+ if (err != 0) {
+ ALOGE("%s: setup Sensor package failed", __func__);
+ goto exit;
+ }
- err = set_sensor_route(stdev->route_hdl, true);
- if (err != 0) {
- ALOGE("%s: Sensor route fail", __func__);
- goto exit;
- }
- stdev->is_sensor_route_enabled = true;
+ err = set_sensor_route(stdev->route_hdl, true);
+ if (err != 0) {
+ ALOGE("%s: Sensor route fail", __func__);
+ goto exit;
}
+ stdev->is_sensor_route_enabled = true;
}
}
}
@@ -1592,6 +1587,40 @@ exit:
return err;
}
+static void sensor_crash_handler(struct knowles_sound_trigger_device *stdev)
+{
+ int i;
+
+ if (stdev->is_sensor_destroy_in_prog == false)
+ return;
+
+ if (stdev->ss_timer_created) {
+ timer_delete(stdev->ss_timer);
+ stdev->ss_timer_created = false;
+ }
+
+ if (stdev->is_sensor_route_enabled == true) {
+ for (i = 0; i < MAX_MODELS; i++) {
+ if (check_uuid_equality(stdev->models[i].uuid,
+ stdev->sensor_model_uuid) &&
+ stdev->models[i].is_loaded == true) {
+ stdev->models[i].is_loaded = false;
+ memset(&stdev->models[i].uuid, 0,
+ sizeof(sound_trigger_uuid_t));
+ break;
+ }
+ }
+ stdev->is_sensor_route_enabled = false;
+ stdev->current_enable &= ~OSLO_MASK;
+ }
+ stdev->is_sensor_destroy_in_prog = false;
+
+ // There could be another thread waiting for us to destroy
+ // so signal that thread, if no one is waiting then this signal
+ // will have no effect
+ pthread_cond_signal(&stdev->sensor_create);
+}
+
static void destroy_sensor_model(struct knowles_sound_trigger_device *stdev)
{
int ret, i;
@@ -1615,7 +1644,8 @@ static void destroy_sensor_model(struct knowles_sound_trigger_device *stdev)
// now we can change the flag
for (i = 0 ; i < MAX_MODELS ; i++) {
if (check_uuid_equality(stdev->models[i].uuid,
- stdev->sensor_model_uuid)) {
+ stdev->sensor_model_uuid) &&
+ stdev->models[i].is_loaded == true) {
memset(&stdev->models[i].uuid, 0, sizeof(sound_trigger_uuid_t));
stdev->models[i].is_loaded = false;
break;
@@ -1632,16 +1662,26 @@ static void destroy_sensor_model(struct knowles_sound_trigger_device *stdev)
ALOGD("-%s-", __func__);
}
-static void sensor_stop_timeout()
+static void sensor_timeout_recover()
{
+ int err = 0;
ALOGD("+%s+", __func__);
struct knowles_sound_trigger_device *stdev = &g_stdev;
pthread_mutex_lock(&stdev->lock);
// We are here because we timed out so check if we still need to destroy
- // the sensor package, if yes then go ahead otherwise do nothing
+ // the sensor package, if yes then reset the firmware
if (stdev->is_sensor_destroy_in_prog == true) {
- destroy_sensor_model(stdev);
+ if (stdev->is_st_hal_ready) {
+ stdev->is_st_hal_ready = false;
+ // reset the firmware and wait for firmware download complete
+ err = reset_fw(stdev->odsp_hdl);
+ if (err == -1) {
+ ALOGE("%s: ERROR: Failed to reset the firmware %d(%s)",
+ __func__, errno, strerror(errno));
+ }
+ sensor_crash_handler(stdev);
+ }
}
pthread_mutex_unlock(&stdev->lock);
ALOGD("-%s-", __func__);
@@ -1668,28 +1708,18 @@ static int start_sensor_model(struct knowles_sound_trigger_device * stdev)
}
}
- // Reset timedout error
- err = 0;
+ // If firmware crashed when we are waiting
+ if (stdev->is_st_hal_ready == false) {
+ err = -EAGAIN;
+ goto exit;
+ }
if (stdev->is_sensor_destroy_in_prog == true) {
ALOGE("%s: ERROR: Waited for %ds but we didn't get the event from "
- "Host 1, forcing a destroy", __func__,
+ "Host 1, and fw reset is not yet complete", __func__,
SENSOR_CREATE_WAIT_TIME_IN_S * SENSOR_CREATE_WAIT_MAX_COUNT);
- stdev->is_sensor_destroy_in_prog = false;
-
- if (stdev->is_sensor_route_enabled == true) {
- err = set_sensor_route(stdev->route_hdl, false);
- if (err) {
- ALOGE("%s: Failed to tear sensor route", __func__);
- goto exit;
- }
- err = destroy_sensor_package(stdev->odsp_hdl);
- if (err) {
- ALOGE("%s: ERROR: Failed to destroy sensor package", __func__);
- goto exit;
- }
- stdev->is_sensor_route_enabled = false;
- }
+ err = -EAGAIN;
+ goto exit;
}
// setup the sensor route
@@ -1720,7 +1750,7 @@ exit:
return err;
}
-static void crash_handler_chre(struct knowles_sound_trigger_device *stdev)
+static void chre_crash_handler(struct knowles_sound_trigger_device *stdev)
{
int i;
@@ -1735,7 +1765,8 @@ static void crash_handler_chre(struct knowles_sound_trigger_device *stdev)
if (stdev->is_chre_route_enabled == true) {
for (i = 0; i < MAX_MODELS; i++) {
if (check_uuid_equality(stdev->models[i].uuid,
- stdev->chre_model_uuid)) {
+ stdev->chre_model_uuid) &&
+ stdev->models[i].is_active == true) {
stdev->models[i].is_active = false;
stdev->models[i].is_loaded = false;
memset(&stdev->models[i].uuid, 0,
@@ -1784,22 +1815,10 @@ static int start_chre_model(struct knowles_sound_trigger_device *stdev,
if (stdev->is_chre_destroy_in_prog == true) {
ALOGE("%s: ERROR: Waited for %ds but we didn't get the event from "
- "Host 1, forcing a destroy", __func__,
+ "Host 1, and fw reset is not yet complete", __func__,
CHRE_CREATE_WAIT_TIME_IN_S * CHRE_CREATE_WAIT_MAX_COUNT);
- stdev->is_chre_destroy_in_prog = false;
- // Reset timedout error
- err = 0;
-
- if (stdev->is_chre_route_enabled == true) {
- tear_chre_audio_route(stdev->route_hdl,
- stdev->is_bargein_route_enabled);
- err = destroy_chre_package(stdev->odsp_hdl);
- if (err != 0) {
- ALOGE("%s: ERROR: Failed to destroy chre package", __func__);
- goto exit;
- }
- stdev->is_chre_route_enabled = false;
- }
+ err = -EAGAIN;
+ goto exit;
}
// setup the sensor route
@@ -1848,7 +1867,8 @@ static void destroy_chre_model(struct knowles_sound_trigger_device *stdev)
// now we can change the flag
for (i = 0; i < MAX_MODELS; i++) {
if (check_uuid_equality(stdev->models[i].uuid,
- stdev->chre_model_uuid)) {
+ stdev->chre_model_uuid) &&
+ stdev->models[i].is_active == true) {
stdev->models[i].is_active = false;
stdev->models[i].is_loaded = false;
memset(&stdev->models[i].uuid, 0,
@@ -1876,21 +1896,67 @@ static void destroy_chre_model(struct knowles_sound_trigger_device *stdev)
ALOGD("-%s-", __func__);
}
-static void chre_stop_timeout()
+static void chre_timeout_recover()
{
+ int err = 0;
ALOGD("+%s+", __func__);
struct knowles_sound_trigger_device *stdev = &g_stdev;
pthread_mutex_lock(&stdev->lock);
// We are here because we timed out so check if we still need to destroy
- // the chre package, if yes then go ahead otherwise do nothing
+ // the chre package, if yes then reset the firmware
if (stdev->is_chre_destroy_in_prog == true) {
- destroy_chre_model(stdev);
+ if (stdev->is_st_hal_ready) {
+ stdev->is_st_hal_ready = false;
+ // reset the firmware and wait for firmware download complete
+ err = reset_fw(stdev->odsp_hdl);
+ if (err == -1) {
+ ALOGE("%s: ERROR: Failed to reset the firmware %d(%s)",
+ __func__, errno, strerror(errno));
+ }
+ chre_crash_handler(stdev);
+ }
}
pthread_mutex_unlock(&stdev->lock);
ALOGD("-%s-", __func__);
}
+static void *monitor_thread_loop(void *context)
+{
+ struct knowles_sound_trigger_device *stdev =
+ (struct knowles_sound_trigger_device *)context;
+ struct timespec now;
+ double diff;
+
+ pthread_mutex_lock(&stdev->lock);
+ while (1) {
+ if (!stdev->is_streaming)
+ pthread_cond_wait(&stdev->tunnel_create, &stdev->lock);
+ pthread_mutex_unlock(&stdev->lock);
+
+ sleep(TUNNEL_TIMEOUT);
+
+ pthread_mutex_lock(&stdev->lock);
+
+ clock_gettime(CLOCK_REALTIME, &now);
+ for (int i = 0; i < MAX_MODELS; i++) {
+ if (stdev->adnc_strm_handle[i] != 0) {
+ diff = (now.tv_sec - stdev->adnc_strm_last_read[i].tv_sec)
+ + (double) ((now.tv_nsec) - (stdev->adnc_strm_last_read[i].tv_nsec))
+ / 1000000000.0;
+
+ if (diff > TUNNEL_TIMEOUT) {
+ ALOGE("%s: Waiting timeout for %f sec", __func__, diff);
+ stdev->adnc_strm_close(stdev->adnc_strm_handle[i]);
+ stdev->adnc_strm_handle[i] = 0;
+ stdev->is_streaming--;
+ stdev->adnc_strm_last_read[i] = reset_time;
+ }
+ }
+ }
+ }
+ pthread_mutex_unlock(&stdev->lock);
+}
static void *callback_thread_loop(void *context)
{
@@ -2014,32 +2080,31 @@ static void *callback_thread_loop(void *context)
ALOGD("Eventid received is OSLO_EP_DISCONNECT %d",
OSLO_EP_DISCONNECT);
if (stdev->is_sensor_destroy_in_prog == true) {
- destroy_sensor_model(stdev);
-
// A timer would have been created during stop,
// check and delete it
if (stdev->ss_timer_created) {
timer_delete(stdev->ss_timer);
stdev->ss_timer_created = false;
}
+
+ destroy_sensor_model(stdev);
} else {
ALOGE("Unexpected OSLO_EP_DISCONNECT received"
", ignoring..");
}
-
break;
} else if (ge.event_id == CHRE_EP_DISCONNECT) {
ALOGD("Eventid received is CHRE_EP_DISCONNECT %d",
CHRE_EP_DISCONNECT);
if (stdev->is_chre_destroy_in_prog == true) {
- destroy_chre_model(stdev);
-
// A timer would have been created during stop,
// check and delete it
if (stdev->chre_timer_created) {
timer_delete(stdev->chre_timer);
stdev->chre_timer_created = false;
}
+
+ destroy_chre_model(stdev);
} else {
ALOGE("Unexpected CHRE_EP_DISCONNECT received"
", ignoring..");
@@ -2093,10 +2158,11 @@ static void *callback_thread_loop(void *context)
ALOGD("Firmware has crashed");
// Don't allow any op on ST HAL until recovery is complete
stdev->is_st_hal_ready = false;
- stdev->is_streaming = false;
+ stdev->is_streaming = 0;
- // Firmware crashed, cancel CHRE timer and flags here
- crash_handler_chre(stdev);
+ // Firmware crashed, clear CHRE/Oslo timer and flags here
+ sensor_crash_handler(stdev);
+ chre_crash_handler(stdev);
}
i += strlen(msg + i) + 1;
@@ -2271,6 +2337,7 @@ static int stop_recognition(struct knowles_sound_trigger_device *stdev,
stdev->adnc_strm_close(stdev->adnc_strm_handle[handle]);
stdev->adnc_strm_handle[handle] = 0;
stdev->is_streaming--;
+ stdev->adnc_strm_last_read[handle] = reset_time;
}
model->is_active = false;
@@ -2406,7 +2473,7 @@ static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
ret = start_sensor_model(stdev);
if (ret) {
ALOGE("%s: ERROR: Failed to start sensor model", __func__);
- goto exit;
+ goto error;
}
stdev->models[i].kw_id = USELESS_KW_ID;
} else if (check_uuid_equality(sound_model->vendor_uuid,
@@ -2414,13 +2481,13 @@ static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
ret = start_chre_model(stdev, i);
if (ret) {
ALOGE("%s: ERROR: Failed to start chre model", __func__);
- goto exit;
+ goto error;
}
stdev->models[i].kw_id = USELESS_KW_ID;
} else {
ALOGE("%s: ERROR: unknown keyword model file", __func__);
ret = -EINVAL;
- goto exit;
+ goto error;
}
*handle = i;
@@ -2437,7 +2504,7 @@ static int stdev_load_sound_model(const struct sound_trigger_hw_device *dev,
stdev->models[i].is_loaded = true;
-exit:
+error:
if (ret != 0) {
if (stdev->models[i].data) {
free(stdev->models[i].data);
@@ -2449,6 +2516,8 @@ exit:
stdev->is_buffer_package_loaded = false;
}
}
+
+exit:
pthread_mutex_unlock(&stdev->lock);
ALOGD("-%s handle %d-", __func__, *handle);
return ret;
@@ -2499,7 +2568,7 @@ static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
// Start timer for 5 seconds
ss_sigevent.sigev_notify = SIGEV_THREAD;
- ss_sigevent.sigev_notify_function = sensor_stop_timeout;
+ ss_sigevent.sigev_notify_function = sensor_timeout_recover;
ss_sigevent.sigev_notify_attributes = NULL;
ss_timer_spec.it_interval.tv_sec = 0;
@@ -2541,7 +2610,7 @@ static int stdev_unload_sound_model(const struct sound_trigger_hw_device *dev,
// Start timer for 5 seconds
chre_sigevent.sigev_notify = SIGEV_THREAD;
- chre_sigevent.sigev_notify_function = chre_stop_timeout;
+ chre_sigevent.sigev_notify_function = chre_timeout_recover;
chre_sigevent.sigev_notify_attributes = NULL;
chre_timer_spec.it_interval.tv_sec = 0;
@@ -2886,6 +2955,7 @@ static int open_streaming_lib(struct knowles_sound_trigger_device *stdev) {
__func__, ADNC_STRM_LIBRARY_PATH);
for (int index = 0; index < MAX_MODELS; index++) {
stdev->adnc_strm_handle[index] = 0;
+ stdev->adnc_strm_last_read[index] = reset_time;
}
stdev->adnc_strm_open =
(int (*)(bool, int, int))dlsym(stdev->adnc_cvq_strm_lib,
@@ -3192,6 +3262,9 @@ static int stdev_open(const hw_module_t *module, const char *name,
pthread_create(&stdev->callback_thread, (const pthread_attr_t *) NULL,
callback_thread_loop, stdev);
+ pthread_create(&stdev->monitor_thread, (const pthread_attr_t *) NULL,
+ monitor_thread_loop, stdev);
+
*device = &stdev->device.common; /* same address as stdev */
exit:
pthread_mutex_unlock(&stdev->lock);
@@ -3612,6 +3685,7 @@ int sound_trigger_hw_call_back(audio_event_type_t event,
stdev->adnc_strm_close(stdev->adnc_strm_handle[i]);
stdev->adnc_strm_handle[i] = 0;
stdev->is_streaming--;
+ stdev->adnc_strm_last_read[i] = reset_time;
}
}
goto exit;
@@ -3623,6 +3697,7 @@ int sound_trigger_hw_call_back(audio_event_type_t event,
stdev->adnc_strm_close(stdev->adnc_strm_handle[index]);
stdev->adnc_strm_handle[index] = 0;
stdev->is_streaming--;
+ stdev->adnc_strm_last_read[index] = reset_time;
}
break;
@@ -3676,6 +3751,10 @@ int sound_trigger_hw_call_back(audio_event_type_t event,
ALOGD("Successfully opened adnc strm! index %d handle %d",
index, config->u.aud_info.ses_info->capture_handle);
stdev->is_streaming++;
+
+ clock_gettime(CLOCK_REALTIME, &stdev->adnc_strm_last_read[index]);
+ if (stdev->is_streaming == 1)
+ pthread_cond_signal(&stdev->tunnel_create);
} else {
ALOGE("%s: DSP is currently not streaming", __func__);
}
@@ -3684,6 +3763,7 @@ int sound_trigger_hw_call_back(audio_event_type_t event,
if (index != -1 && stdev->adnc_strm_handle[index] != 0) {
//ALOGD("%s: soundtrigger HAL adnc_strm_read", __func__);
+ clock_gettime(CLOCK_REALTIME, &stdev->adnc_strm_last_read[index]);
pthread_mutex_unlock(&stdev->lock);
stdev->adnc_strm_read(stdev->adnc_strm_handle[index],
config->u.aud_info.buf,