diff options
Diffstat (limited to 'sound_trigger_hw_iaxxx.c')
-rw-r--r-- | sound_trigger_hw_iaxxx.c | 242 |
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, |