From f8b3d447b17a9f61d82211cbe4df43415d027234 Mon Sep 17 00:00:00 2001 From: adrojaankur Date: Wed, 19 Nov 2025 16:54:34 +0530 Subject: [PATCH 1/3] Update certificate selector to use static cert path --- src/auth/ctrlm_auth_certificate.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/auth/ctrlm_auth_certificate.cpp b/src/auth/ctrlm_auth_certificate.cpp index 63ff900c..9ffbf49b 100644 --- a/src/auth/ctrlm_auth_certificate.cpp +++ b/src/auth/ctrlm_auth_certificate.cpp @@ -29,6 +29,7 @@ #include "ctrlm_log.h" #define CERT_FILENAME_PREFIX "file://" +#define STATIC_CERT "/etc/ssl/certsel/static-cert.cfg" ctrlm_auth_certificate_t *ctrlm_auth_certificate_get() { return(new(ctrlm_auth_certificate_t)); @@ -42,7 +43,7 @@ ctrlm_auth_certificate_t::ctrlm_auth_certificate_t() { char *cert_path = NULL; char *cert_password = NULL; - rdkcertselector_h cert_selector = rdkcertselector_new( NULL, NULL, "MTLS" ); + rdkcertselector_h cert_selector = rdkcertselector_new( STATIC_CERT, NULL, "MTLS" ); if(cert_selector == NULL){ XLOGD_TELEMETRY("cert selector init failed"); From 7239417e05e378c7a38ce24fcdfe52477fdf5a83 Mon Sep 17 00:00:00 2001 From: adrojaankur Date: Wed, 19 Nov 2025 20:58:59 +0530 Subject: [PATCH 2/3] Update certificate selector initialization parameters --- src/auth/ctrlm_auth_certificate.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/auth/ctrlm_auth_certificate.cpp b/src/auth/ctrlm_auth_certificate.cpp index 9ffbf49b..0c4c3153 100644 --- a/src/auth/ctrlm_auth_certificate.cpp +++ b/src/auth/ctrlm_auth_certificate.cpp @@ -29,7 +29,6 @@ #include "ctrlm_log.h" #define CERT_FILENAME_PREFIX "file://" -#define STATIC_CERT "/etc/ssl/certsel/static-cert.cfg" ctrlm_auth_certificate_t *ctrlm_auth_certificate_get() { return(new(ctrlm_auth_certificate_t)); @@ -43,7 +42,7 @@ ctrlm_auth_certificate_t::ctrlm_auth_certificate_t() { char *cert_path = NULL; char *cert_password = NULL; - rdkcertselector_h cert_selector = rdkcertselector_new( STATIC_CERT, NULL, "MTLS" ); + rdkcertselector_h cert_selector = rdkcertselector_new( NULL, NULL, "FW_MTLS" ); if(cert_selector == NULL){ XLOGD_TELEMETRY("cert selector init failed"); From 526c6a8f4ebb7835cea8f6c0cc3b9f3f96a37ee7 Mon Sep 17 00:00:00 2001 From: adrojaankur Date: Wed, 19 Nov 2025 22:02:35 +0530 Subject: [PATCH 3/3] Rebase (#150) * RDKEMW-10480 : ctrlm release v1.1.6, xr-voice-sdk v1.0.7 (#149) * RDKEMW-9600: FIRST_PACKET_TIMEOUTs (#135) --------- Co-authored-by: dwolaver <44593664+dwolaver@users.noreply.github.com> Co-authored-by: Kelvin Lu <119349872+klu339@users.noreply.github.com> --- CHANGELOG.md | 16 ++ src/ble/ctrlm_ble_network.cpp | 79 ++++-- src/ble/ctrlm_ble_network.h | 2 + src/ctrlm_network.cpp | 5 + src/ctrlm_network.h | 2 + src/rf4ce/ctrlm_rf4ce_network.cpp | 226 ++++++++++-------- src/rf4ce/ctrlm_rf4ce_network.h | 2 + src/voice/ctrlm_voice_obj.cpp | 15 +- src/voice/ctrlm_voice_obj.h | 29 ++- .../ipc/ctrlm_voice_ipc_iarm_thunder.cpp | 3 +- 10 files changed, 262 insertions(+), 117 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef1e336b..ea63c55d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,22 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.1.6](https://github.com/rdkcentral/control/compare/1.1.5...1.1.6) + +> 19 November 2025 + +- RDKEMW-9124 : remove xr-voice-sdk build flags - XRAUDIO_CURTAIL XLOG_CURTAIL [`#132`](https://github.com/rdkcentral/control/pull/132) +- RDKEMW-8676 : remove ctrlm build flags - MIC_TAP, LOCAL_MIC, LOCAL_MIC_DISABLE_VIA_PRIVACY [`#120`](https://github.com/rdkcentral/control/pull/120) +- RDKEMW-8664 : remove ctrlm build flags - MEM_DEBUG, ASSERT_ON_WRONG_THREAD [`#118`](https://github.com/rdkcentral/control/pull/118) +- RDKEMW-8297 : remove ctrlm build flags - A5000_ENABLE [`#117`](https://github.com/rdkcentral/control/pull/117) +- RDKEMW-8668 : modify ctrlm build flag - BREAKPAD [`#119`](https://github.com/rdkcentral/control/pull/119) +- RDKEMW-8296 : remove ctrlm build flags - DEEPSLEEP_CLOSE_DB [`#112`](https://github.com/rdkcentral/control/pull/112) +- RDKEMW-8295 : remove ctrlm build flags - MEMORY_LOCK [`#111`](https://github.com/rdkcentral/control/pull/111) +- RDKEMW-7905 : remove ctrlm build flags - ANSI_CODES_DISABLED [`#110`](https://github.com/rdkcentral/control/pull/110) +- Revert "RDKEMW-8929 (#129)" [`#145`](https://github.com/rdkcentral/control/pull/145) +- RDKEMW-10311 : RF4CE update key mapping [`#140`](https://github.com/rdkcentral/control/pull/140) +- RDKEMW-10164: update CHANGELOG for release v1.1.5 [`#139`](https://github.com/rdkcentral/control/pull/139) + #### [1.1.5](https://github.com/rdkcentral/control/compare/1.1.4...1.1.5) > 5 November 2025 diff --git a/src/ble/ctrlm_ble_network.cpp b/src/ble/ctrlm_ble_network.cpp index dca4c78f..1e141823 100644 --- a/src/ble/ctrlm_ble_network.cpp +++ b/src/ble/ctrlm_ble_network.cpp @@ -525,7 +525,6 @@ void ctrlm_obj_network_ble_t::req_process_voice_session_begin(void *data, int si // only support ADPCM from ble-rcu component ctrlm_hal_ble_VoiceEncoding_t encoding = CTRLM_HAL_BLE_ENCODING_ADPCM; - ctrlm_hal_ble_VoiceStreamEnd_t streamEnd = CTRLM_HAL_BLE_VOICE_STREAM_END_ON_KEY_UP; ctrlm_voice_format_t voice_format = { .type = CTRLM_VOICE_FORMAT_INVALID }; @@ -543,18 +542,21 @@ void ctrlm_obj_network_ble_t::req_process_voice_session_begin(void *data, int si audio_format.getHeaderInfoAdpcm(adpcm_frame->offset_step_size_index, adpcm_frame->offset_predicted_sample_lsb, adpcm_frame->offset_predicted_sample_msb, adpcm_frame->offset_sequence_value, adpcm_frame->shift_sequence_value, adpcm_frame->sequence_value_min, adpcm_frame->sequence_value_max); pressAndHoldSupport = audio_format.getPressAndHoldSupport(); - if(!pressAndHoldSupport) { - streamEnd = CTRLM_HAL_BLE_VOICE_STREAM_END_ON_AUDIO_DURATION; - } controllers_[controller_id]->setPressAndHoldSupport(pressAndHoldSupport); } } + ctrlm_voice_start_audio_params_t audio_start_params; + audio_start_params.m_controller_id = controller_id; + audio_start_params.m_fd = -1; + audio_start_params.m_started = false; + auto audio_start_cb = std::bind(&ctrlm_obj_network_ble_t::start_controller_audio_streaming, this, std::placeholders::_1); + voice_status = ctrlm_get_voice_obj()->voice_session_req(network_id_get(), controller_id, device, voice_format, NULL, controllers_[controller_id]->get_model().c_str(), controllers_[controller_id]->get_sw_revision().to_string().c_str(), controllers_[controller_id]->get_hw_revision().to_string().c_str(), 0.0, - false, NULL, NULL, NULL, true, pressAndHoldSupport); + false, NULL, NULL, NULL, true, pressAndHoldSupport, audio_start_cb, &audio_start_params); if (!controllers_[controller_id]->get_capabilities().has_capability(ctrlm_controller_capabilities_t::capability::PAR) && (VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE == voice_status)) { XLOGD_WARN("PAR voice is enabled but not supported by BLE controller treating as normal voice session"); voice_status = VOICE_SESSION_RESPONSE_AVAILABLE; @@ -562,24 +564,21 @@ void ctrlm_obj_network_ble_t::req_process_voice_session_begin(void *data, int si if (VOICE_SESSION_RESPONSE_AVAILABLE != voice_status) { XLOGD_TELEMETRY("Failed opening voice session in ctrlm_voice_t, error = <%d>", voice_status); } else { + int fd = -1; bool success = false; - if (ble_rcu_interface_) { - int fd = -1; - - if (!ble_rcu_interface_->startAudioStreaming(ieee_address, encoding, streamEnd, fd)) { - XLOGD_ERROR("failed to start audio streaming on remote"); - } else { + if (!audio_start_params.m_started) { // voice session req did not need to start audio + start_controller_audio_streaming(&audio_start_params); + } + fd = audio_start_params.m_fd; - if (fd < 0) { - XLOGD_ERROR("Voice streaming pipe invalid (fd = <%d>), aborting voice session", fd); - success = false; - } else { - XLOGD_INFO("Acquired voice streaming pipe fd = <%d>, sending to voice engine", fd); - //Send the fd acquired from bluez to the voice engine - success = ctrlm_get_voice_obj()->voice_session_data(network_id_get(), controller_id, fd); - } - } + if (fd < 0) { + XLOGD_ERROR("Voice streaming pipe invalid (fd = <%d>), aborting voice session", fd); + success = false; + } else { + XLOGD_INFO("Acquired voice streaming pipe fd = <%d>, sending to voice engine", fd); + //Send the fd acquired from bluez to the voice engine + success = ctrlm_get_voice_obj()->voice_session_data(network_id_get(), controller_id, fd); } if (false == success) { @@ -2616,3 +2615,43 @@ ctrlm_controller_id_t ctrlm_obj_network_ble_t::find_controller_from_upgrade_sess } return id; } + +void ctrlm_obj_network_ble_t::start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params) { + THREAD_ID_VALIDATE(); + int fd = -1; + ctrlm_controller_id_t id = params->m_controller_id; + params->m_fd = fd; + params->m_started = false; + + if (!ready_) { + XLOGD_FATAL("Network is not ready!"); + return; + } + + if(!controller_exists(id)) { + XLOGD_WARN("Controller %u doesn't exist.", id); + return; + } + + if (!ble_rcu_interface_) { + XLOGD_WARN("ble rcu interface not ready"); + return; + } + + ctrlm_hal_ble_VoiceEncoding_t encoding = CTRLM_HAL_BLE_ENCODING_ADPCM; + ctrlm_hal_ble_VoiceStreamEnd_t streamEnd = CTRLM_HAL_BLE_VOICE_STREAM_END_ON_KEY_UP; + auto rcu = controllers_.at(id); + + if (rcu->getPressAndHoldSupport()) { + streamEnd = CTRLM_HAL_BLE_VOICE_STREAM_END_ON_AUDIO_DURATION; + } + + uint64_t ieee_address = rcu->ieee_address_get().get_value(); + if (!ble_rcu_interface_->startAudioStreaming(ieee_address, encoding, streamEnd, fd)) { + XLOGD_ERROR("failed to start audio streaming on remote"); + return; + } + + params->m_fd = fd; + params->m_started = true; +} diff --git a/src/ble/ctrlm_ble_network.h b/src/ble/ctrlm_ble_network.h index 92868ca1..787bb8b8 100644 --- a/src/ble/ctrlm_ble_network.h +++ b/src/ble/ctrlm_ble_network.h @@ -192,6 +192,8 @@ class ctrlm_obj_network_ble_t : public ctrlm_obj_network_t { std::shared_ptr getConfigSettings(); + virtual void start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params); + private: ctrlm_obj_network_ble_t(); diff --git a/src/ctrlm_network.cpp b/src/ctrlm_network.cpp index 74ff4129..69fa462b 100644 --- a/src/ctrlm_network.cpp +++ b/src/ctrlm_network.cpp @@ -1074,3 +1074,8 @@ void ctrlm_obj_network_t::iarm_event_rcu_firmware_status(const ctrlm_obj_control } #endif } + +void ctrlm_obj_network_t::start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params) { + XLOGD_WARN("not implemented for %s network", name_get()); + return; +} diff --git a/src/ctrlm_network.h b/src/ctrlm_network.h index ab22b51b..c39f3285 100644 --- a/src/ctrlm_network.h +++ b/src/ctrlm_network.h @@ -289,6 +289,8 @@ class ctrlm_obj_network_t virtual void iarm_event_rcu_validation_status(void); virtual void iarm_event_rcu_firmware_status(const ctrlm_obj_controller_t &rcu); + virtual void start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params); + // Internal methods std::string version_; diff --git a/src/rf4ce/ctrlm_rf4ce_network.cpp b/src/rf4ce/ctrlm_rf4ce_network.cpp index de5a22ff..5fea2cd3 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.cpp +++ b/src/rf4ce/ctrlm_rf4ce_network.cpp @@ -3751,94 +3751,35 @@ void ctrlm_obj_network_rf4ce_t::ind_process_voice_session_request(void *data, in XLOGD_INFO("processing session request - type <%s> voice format <%s>", ctrlm_voice_device_str(device_type), ctrlm_voice_format_str(voice_format)); } - std::string controller_name = controllers_[dqm->controller_id]->product_name_get(); - ctrlm_hal_rf4ce_cfm_data_t cb_confirm_rf4ce = NULL; - void * cb_confirm_param = NULL; + std::string controller_name = controllers_[dqm->controller_id]->product_name_get(); + void * cb_confirm_param = NULL; ctrlm_voice_session_rsp_confirm_t cb_confirm_voice_obj = NULL; + ctrlm_voice_start_audio_params_t start_audio_params; + start_audio_params.m_controller_id = dqm->controller_id; + start_audio_params.m_use_stream_params = use_stream_params; + start_audio_params.m_offset = offset; + start_audio_params.m_started = false; + start_audio_params.m_timestamp = dqm->timestamp; + start_audio_params.m_device_type = device_type; + auto audio_start_cb = std::bind(&ctrlm_obj_network_rf4ce_t::start_controller_audio_streaming, this, std::placeholders::_1); + session = ctrlm_get_voice_obj()->voice_session_req(network_id_get(), dqm->controller_id, device_type, voice_format, use_stream_params ? &stream_params : NULL, controller_name.c_str(), sw_version.to_string().c_str(), hw_version.to_string().c_str(), (((double)battery_status.get_voltage_loaded()) * 4.0 / 255), command_status, - &dqm->timestamp, &cb_confirm_voice_obj, &cb_confirm_param); - if(session == VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE) { - if(controllers_[dqm->controller_id]->get_capabilities().has_capability(ctrlm_controller_capabilities_t::capability::PAR)) { - session = VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE; - } else { - session = VOICE_SESSION_RESPONSE_AVAILABLE; - } - } - if(session == VOICE_SESSION_RESPONSE_AVAILABLE) { - session = VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK; - } - - XLOGD_INFO("Voice Session Response Status <%#x>", session); - - // Send the response back to the HAL device - guchar response[5]; - guchar response_len = 2; - - response[0] = MSO_VOICE_CMD_ID_VOICE_SESSION_RESPONSE; - response[1] = session; - if(use_stream_params && session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK) { // Add stream params in the response - response[1] |= 0x80; - response[2] = (guchar) stream_begin_; - response[3] = (offset & 0xFF); - response[4] = (offset >> 8); - response_len = 5; - } - - if(session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE) { - voice_params_par_t params; - ctrlm_get_voice_obj()->voice_params_par_get(¶ms); + &dqm->timestamp, &cb_confirm_voice_obj, &cb_confirm_param, + false, false, audio_start_cb, &start_audio_params); - XLOGD_INFO("PAR Voice EOS data bytes timeout <%d> method <%d>", params.par_voice_eos_timeout, params.par_voice_eos_method); - response[2] = params.par_voice_eos_method; - response[3] = (params.par_voice_eos_timeout & 0xFF); - response[4] = (params.par_voice_eos_timeout >> 8); - response_len = 5; + if(!start_audio_params.m_started) { + start_audio_params.m_cb_confirm_voice_obj = cb_confirm_voice_obj; + start_audio_params.m_cb_confirm_param = cb_confirm_param; + start_audio_params.m_status = session; + start_controller_audio_streaming(&start_audio_params); } - ctrlm_timestamp_t hal_timestamp = dqm->timestamp; - - // Determine when to send the response (50 ms after receipt) - if(controller_type_get(dqm->controller_id) == RF4CE_CONTROLLER_TYPE_XR19) { - ctrlm_timestamp_add_ms(&dqm->timestamp, response_idle_time_ff_); - } else { - ctrlm_timestamp_add_ms(&dqm->timestamp, CTRLM_RF4CE_CONST_RESPONSE_IDLE_TIME); - } - - - if(cb_confirm_voice_obj != NULL && (session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK || - session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE)) { // Only confirm response for accepted session so there is only ever one response stored - voice_session_rsp_confirm_ = cb_confirm_voice_obj; - voice_session_rsp_confirm_param_ = cb_confirm_param; - - timestamp_voice_session_request_ = hal_timestamp; - timestamp_voice_first_packet_ = hal_timestamp; - - cb_confirm_rf4ce = ctrlm_network_rf4ce_cfm_voice_session_rsp; - cb_confirm_param = voice_session_rsp_params_.network_id; - - // Store controller id, packet and timestamp for retransmission in case of send error - voice_session_rsp_params_.controller_id = dqm->controller_id; - voice_session_rsp_params_.response_len = response_len; - voice_session_rsp_params_.timestamp_hal = hal_timestamp; - voice_session_rsp_params_.timestamp_begin = dqm->timestamp; - voice_session_rsp_params_.timestamp_end = dqm->timestamp; - voice_session_rsp_params_.retries = 0; - ctrlm_timestamp_add_ms(&voice_session_rsp_params_.timestamp_end, CTRLM_RF4CE_CONST_RESPONSE_WAIT_TIME); - errno_t safec_rc = memcpy_s(&voice_session_rsp_params_.response, sizeof(voice_session_rsp_params_.response),response, response_len); - ERR_CHK(safec_rc); - ctrlm_timestamp_get(&voice_session_rsp_params_.timestamp_rsp_req); - } - - req_data(CTRLM_RF4CE_PROFILE_ID_VOICE, dqm->controller_id, dqm->timestamp, response_len, response, NULL, NULL, false, single_channel_rsp_, cb_confirm_rf4ce, cb_confirm_param); - - XLOGD_INFO("session response delivered"); - if(session != VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK && session != VOICE_SESSION_RESPONSE_AVAILABLE && session != VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE && session != VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE) { voice_session_active_count_--; @@ -3847,26 +3788,10 @@ void ctrlm_obj_network_rf4ce_t::ind_process_voice_session_request(void *data, in property.state = CTRLM_HAL_FREQUENCY_AGILITY_ENABLE; ctrlm_network_property_set(network_id_get(), CTRLM_HAL_NETWORK_PROPERTY_FREQUENCY_AGILITY, (void *)&property, sizeof(property)); } - - if(device_type == CTRLM_VOICE_DEVICE_PTT) { - // Send voice key up event since the session was not accepted - process_event_key(dqm->controller_id, CTRLM_KEY_STATUS_UP, CTRLM_KEY_CODE_PUSH_TO_TALK); - } } if(dqm->status != VOICE_SESSION_RESPONSE_AVAILABLE && dqm->status != VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK) { // Session was aborted XLOGD_INFO("voice session abort"); - - // // Broadcast the event over the iarm bus - // ctrlm_voice_iarm_event_session_abort_t event; - // event.api_revision = CTRLM_VOICE_IARM_BUS_API_REVISION; - // event.network_id = dqm->header.network_id; - // event.network_type = ctrlm_network_type_get(dqm->header.network_id); - // event.controller_id = dqm->controller_id; - // event.session_id = ctrlm_voice_session_id_get_next(); - // event.reason = dqm->reason; - - // ctrlm_voice_iarm_event_session_abort(&event); } } @@ -3901,7 +3826,6 @@ void ctrlm_obj_network_rf4ce_t::cfm_voice_session_rsp(void *data, int size) { } ctrlm_timestamp_t now; ctrlm_timestamp_get(&now); - double loadavg[3] = { -1, -1, -1 }; getloadavg(loadavg, 3); struct sysinfo s_info; @@ -5093,3 +5017,117 @@ void ctrlm_obj_network_rf4ce_t::controller_init_uinput(ctrlm_controller_id_t con return; } } + +void ctrlm_obj_network_rf4ce_t::start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params) { + THREAD_ID_VALIDATE(); + params->m_started = false; + ctrlm_controller_id_t controller_id = params->m_controller_id; + ctrlm_voice_device_t device_type = params->m_device_type; + + if(!ready_) { + XLOGD_FATAL("Network is not ready!"); + return; + } + + if(!controller_exists(controller_id)) { + XLOGD_WARN("Controller %u doesn't exist.", controller_id); + return; + } + + ctrlm_voice_session_response_status_t session = params->m_status; + + if(session == VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE) { + if(controllers_[controller_id]->get_capabilities().has_capability(ctrlm_controller_capabilities_t::capability::PAR)) { + session = VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE; + } else { + session = VOICE_SESSION_RESPONSE_AVAILABLE; + } + } + if(session == VOICE_SESSION_RESPONSE_AVAILABLE) { + session = VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK; + } + + XLOGD_INFO("Voice Session Response Status <%#x>", session); + + // Send the response back to the HAL device + guchar response[5]; + guchar response_len = 2; + gint16 offset = params->m_offset; + + response[0] = MSO_VOICE_CMD_ID_VOICE_SESSION_RESPONSE; + response[1] = session; + if(params->m_use_stream_params && session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK) { // Add stream params in the response + response[1] |= 0x80; + response[2] = (guchar) stream_begin_; + response[3] = (offset & 0xFF); + response[4] = (offset >> 8); + response_len = 5; + } + + if(session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE) { + voice_params_par_t voice_params; + ctrlm_get_voice_obj()->voice_params_par_get(&voice_params); + + XLOGD_INFO("PAR Voice EOS data bytes timeout <%d> method <%d>", voice_params.par_voice_eos_timeout, voice_params.par_voice_eos_method); + response[2] = voice_params.par_voice_eos_method; + response[3] = (voice_params.par_voice_eos_timeout & 0xFF); + response[4] = (voice_params.par_voice_eos_timeout >> 8); + response_len = 5; + } + + ctrlm_timestamp_t hal_timestamp = params->m_timestamp; + + // Determine when to send the response (50 ms after receipt) + if(controller_type_get(controller_id) == RF4CE_CONTROLLER_TYPE_XR19) { + ctrlm_timestamp_add_ms(¶ms->m_timestamp, response_idle_time_ff_); + } else { + ctrlm_timestamp_add_ms(¶ms->m_timestamp, CTRLM_RF4CE_CONST_RESPONSE_IDLE_TIME); + } + + ctrlm_hal_rf4ce_cfm_data_t cb_confirm_rf4ce = NULL; + + if(params->m_cb_confirm_voice_obj != NULL && (session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK || + session == VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE)) { // Only confirm response for accepted session so there is only ever one response stored + voice_session_rsp_confirm_ = params->m_cb_confirm_voice_obj; + voice_session_rsp_confirm_param_ = params->m_cb_confirm_param; + + timestamp_voice_session_request_ = hal_timestamp; + timestamp_voice_first_packet_ = hal_timestamp; + + cb_confirm_rf4ce = ctrlm_network_rf4ce_cfm_voice_session_rsp; + params->m_cb_confirm_param = voice_session_rsp_params_.network_id; + + // Store controller id, packet and timestamp for retransmission in case of send error + voice_session_rsp_params_.controller_id = controller_id; + voice_session_rsp_params_.response_len = response_len; + voice_session_rsp_params_.timestamp_hal = hal_timestamp; + voice_session_rsp_params_.timestamp_begin = params->m_timestamp; + voice_session_rsp_params_.timestamp_end = params->m_timestamp; + voice_session_rsp_params_.retries = 0; + ctrlm_timestamp_add_ms(&voice_session_rsp_params_.timestamp_end, CTRLM_RF4CE_CONST_RESPONSE_WAIT_TIME); + errno_t safec_rc = memcpy_s(&voice_session_rsp_params_.response, sizeof(voice_session_rsp_params_.response),response, response_len); + ERR_CHK(safec_rc); + ctrlm_timestamp_get(&voice_session_rsp_params_.timestamp_rsp_req); + } + + req_data(CTRLM_RF4CE_PROFILE_ID_VOICE, controller_id, params->m_timestamp, response_len, response, NULL, NULL, false, single_channel_rsp_, cb_confirm_rf4ce, params->m_cb_confirm_param); + + XLOGD_INFO("session response delivered"); + + if(session != VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK && session != VOICE_SESSION_RESPONSE_AVAILABLE && + session != VOICE_SESSION_RESPONSE_AVAILABLE_SKIP_CHAN_CHECK_PAR_VOICE && session != VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE) { + voice_session_active_count_--; + if(voice_session_active_count_ == 0) { // Re-enable frequency agility if the no other active RF4CE voice sessions + ctrlm_hal_network_property_frequency_agility_t property; + property.state = CTRLM_HAL_FREQUENCY_AGILITY_ENABLE; + ctrlm_network_property_set(network_id_get(), CTRLM_HAL_NETWORK_PROPERTY_FREQUENCY_AGILITY, (void *)&property, sizeof(property)); + } + + if(device_type == CTRLM_VOICE_DEVICE_PTT) { + // Send voice key up event since the session was not accepted + process_event_key(controller_id, CTRLM_KEY_STATUS_UP, CTRLM_KEY_CODE_PUSH_TO_TALK); + } + } + + params->m_started = true; +} diff --git a/src/rf4ce/ctrlm_rf4ce_network.h b/src/rf4ce/ctrlm_rf4ce_network.h index 1e4ce251..07298971 100644 --- a/src/rf4ce/ctrlm_rf4ce_network.h +++ b/src/rf4ce/ctrlm_rf4ce_network.h @@ -462,6 +462,8 @@ class ctrlm_obj_network_rf4ce_t : public ctrlm_obj_network_t virtual std::vector get_controller_obj_list() const; void rcu_timeout_key_release(void *data, int data_size); + virtual void start_controller_audio_streaming(ctrlm_voice_start_audio_params_t *params); + protected: virtual gboolean key_event_hook(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id, ctrlm_key_status_t key_status, ctrlm_key_code_t key_code); diff --git a/src/voice/ctrlm_voice_obj.cpp b/src/voice/ctrlm_voice_obj.cpp index 93c12ac2..4a26f316 100644 --- a/src/voice/ctrlm_voice_obj.cpp +++ b/src/voice/ctrlm_voice_obj.cpp @@ -1344,7 +1344,7 @@ ctrlm_voice_session_response_status_t ctrlm_voice_t::voice_session_req(ctrlm_net ctrlm_voice_device_t device_type, ctrlm_voice_format_t format, voice_session_req_stream_params *stream_params, const char *controller_name, const char *sw_version, const char *hw_version, double voltage, bool command_status, - ctrlm_timestamp_t *timestamp, ctrlm_voice_session_rsp_confirm_t *cb_confirm, void **cb_confirm_param, bool use_external_data_pipe, bool press_and_hold, const char *l_transcription_in, const char *audio_file_in, const uuid_t *uuid, bool low_latency, bool low_cpu_util, int audio_fd) { + ctrlm_timestamp_t *timestamp, ctrlm_voice_session_rsp_confirm_t *cb_confirm, void **cb_confirm_param, bool use_external_data_pipe, bool press_and_hold, std::function cb_start_audio, ctrlm_voice_start_audio_params_t *cb_audio_start_params, const char *l_transcription_in, const char *audio_file_in, const uuid_t *uuid, bool low_latency, bool low_cpu_util, int audio_fd) { ctrlm_voice_session_t *session = &this->voice_session[voice_device_to_session_group(device_type)]; @@ -1376,6 +1376,7 @@ ctrlm_voice_session_response_status_t ctrlm_voice_t::voice_session_req(ctrlm_net // Cancel current speech router session XLOGD_INFO("Waiting on the results from previous session, aborting this and continuing.."); + pre_session_terminate(cb_start_audio, cb_audio_start_params, cb_confirm, cb_confirm_param); xrsr_session_terminate(voice_device_to_xrsr(session->voice_device)); // Synchronous - this will take a bit of time. Might need to revisit this down the road. } bool request_new_session = true; @@ -1387,6 +1388,7 @@ ctrlm_voice_session_response_status_t ctrlm_voice_t::voice_session_req(ctrlm_net request_new_session = false; } else { // Cancel current speech router session XLOGD_WARN("Session in progress with same controller - src <%s> dst <%s>, aborting this and continuing..", ctrlm_voice_state_src_str(session->state_src), ctrlm_voice_state_dst_str(session->state_dst)); + pre_session_terminate(cb_start_audio, cb_audio_start_params, cb_confirm, cb_confirm_param); xrsr_session_terminate(voice_device_to_xrsr(session->voice_device)); // Synchronous - this will take a bit of time. Might need to revisit this down the road. } } else { // session in progress with different controller @@ -4244,3 +4246,14 @@ void ctrlm_voice_t::url_hostname_patterns(const std::vector &obj_se this->url_hostname_pattern_add(itr.c_str()); } } + +void ctrlm_voice_t::pre_session_terminate(std::function cb_start_audio, ctrlm_voice_start_audio_params_t *cb_audio_start_params, ctrlm_voice_session_rsp_confirm_t *cb_confirm, void **cb_confirm_param) { + if (cb_start_audio != nullptr && cb_audio_start_params != nullptr) { + if(cb_confirm != NULL && cb_confirm_param != NULL) { + cb_audio_start_params->m_cb_confirm_voice_obj = ctrlm_voice_session_response_confirm; + cb_audio_start_params->m_cb_confirm_param = NULL; + cb_audio_start_params->m_status = (this->prefs.par_voice_enabled) ? VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE : VOICE_SESSION_RESPONSE_AVAILABLE; + } + cb_start_audio(cb_audio_start_params); + } +} diff --git a/src/voice/ctrlm_voice_obj.h b/src/voice/ctrlm_voice_obj.h index bd8de16c..3976a62c 100644 --- a/src/voice/ctrlm_voice_obj.h +++ b/src/voice/ctrlm_voice_obj.h @@ -389,6 +389,29 @@ typedef struct { typedef void (*ctrlm_voice_session_rsp_confirm_t)(bool result, signed long long rsp_time, unsigned int rsp_window, const std::string &err_str, ctrlm_timestamp_t *timestamp, void *user_data); +class ctrlm_voice_start_audio_params_t +{ +public: + // Generic + ctrlm_voice_start_audio_params_t() = default; + virtual ~ctrlm_voice_start_audio_params_t() = default; + + ctrlm_controller_id_t m_controller_id = -1; + bool m_started = false; + + // BLE + int m_fd = -1; + + // RF4CE + bool m_use_stream_params = false; + int16_t m_offset = 0; + ctrlm_timestamp_t m_timestamp; + ctrlm_voice_session_rsp_confirm_t m_cb_confirm_voice_obj; + void * m_cb_confirm_param; + ctrlm_voice_session_response_status_t m_status; + ctrlm_voice_device_t m_device_type; +}; + typedef struct { ctrlm_network_id_t network_id; ctrlm_network_type_t network_type; @@ -471,7 +494,7 @@ class ctrlm_voice_t { ctrlm_voice_t(); virtual ~ctrlm_voice_t(); - ctrlm_voice_session_response_status_t voice_session_req(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id, ctrlm_voice_device_t device_type, ctrlm_voice_format_t format, voice_session_req_stream_params *stream_params, const char *controller_name, const char *sw_version, const char *hw_version, double voltage, bool command_status=false, ctrlm_timestamp_t *timestamp=NULL, ctrlm_voice_session_rsp_confirm_t *cb_confirm=NULL, void **cb_confirm_param=NULL, bool use_external_data_pipe=false, bool press_and_hold=true, const char *transcription_in=NULL, const char *audio_file_in=NULL, const uuid_t *uuid = NULL, bool low_latency=false, bool low_cpu_util=false, int audio_fd = -1); + ctrlm_voice_session_response_status_t voice_session_req(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id, ctrlm_voice_device_t device_type, ctrlm_voice_format_t format, voice_session_req_stream_params *stream_params, const char *controller_name, const char *sw_version, const char *hw_version, double voltage, bool command_status=false, ctrlm_timestamp_t *timestamp=NULL, ctrlm_voice_session_rsp_confirm_t *cb_confirm=NULL, void **cb_confirm_param=NULL, bool use_external_data_pipe=false, bool press_and_hold=true, std::function cb_start_audio=NULL, ctrlm_voice_start_audio_params_t *cb_audio_start_params=NULL, const char *transcription_in=NULL, const char *audio_file_in=NULL, const uuid_t *uuid = NULL, bool low_latency=false, bool low_cpu_util=false, int audio_fd = -1); void voice_session_rsp_confirm(bool result, signed long long rsp_time, unsigned int rsp_window, const std::string &err_str, ctrlm_timestamp_t *timestamp); bool voice_session_data(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id, const char *buffer, long unsigned int length, ctrlm_timestamp_t *timestamp=NULL, uint8_t *lqi=NULL); bool voice_session_data(ctrlm_network_id_t network_id, ctrlm_controller_id_t controller_id, int fd, const uuid_t *uuid=NULL); @@ -723,6 +746,10 @@ class ctrlm_voice_t { void audio_state_set(bool session); bool vsdk_is_privacy_enabled(void); double vsdk_keyword_sensitivity_limit_check(double sensitivity); + void pre_session_terminate(std::function cb_start_audio, + ctrlm_voice_start_audio_params_t *cb_audio_start_params, + ctrlm_voice_session_rsp_confirm_t *cb_confirm, + void **cb_confirm_param); }; // Helper Functions diff --git a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp index 022b71f4..f88d6fb9 100644 --- a/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp +++ b/src/voice/ipc/ctrlm_voice_ipc_iarm_thunder.cpp @@ -793,7 +793,8 @@ IARM_Result_t ctrlm_voice_ipc_iarm_thunder_t::voice_session_request(void *data) ctrlm_voice_session_response_status_t voice_status = voice_obj->voice_session_req( CTRLM_MAIN_NETWORK_ID_INVALID, CTRLM_MAIN_CONTROLLER_ID_INVALID, request_config.device, request_config.format, NULL, str_name_of_source.c_str(), "0.0.0.0", "0.0.0.0", 0.0, - false, NULL, NULL, NULL, (fd >= 0) ? true : false, true, str_transcription.empty() ? NULL : str_transcription.c_str(), str_audio_file.empty() ? NULL : str_audio_file.c_str(), &request_uuid, request_config.low_latency, request_config.low_cpu_util, fd); + false, NULL, NULL, NULL, (fd >= 0) ? true : false, true, NULL, NULL, + str_transcription.empty() ? NULL : str_transcription.c_str(), str_audio_file.empty() ? NULL : str_audio_file.c_str(), &request_uuid, request_config.low_latency, request_config.low_cpu_util, fd); if (voice_status != VOICE_SESSION_RESPONSE_AVAILABLE && voice_status != VOICE_SESSION_RESPONSE_AVAILABLE_PAR_VOICE) { XLOGD_ERROR("Failed opening voice session <%s>", ctrlm_voice_session_response_status_str(voice_status));