From c61d89a47fc793475aa7ef97b39c58d266284889 Mon Sep 17 00:00:00 2001 From: Andrey Volk Date: Sat, 27 Feb 2021 01:04:16 +0300 Subject: [PATCH] [Core] Add new switch_core_session_try_reset() API to fix a deadlock for the case when two threads want to set session codecs. --- src/include/switch_core.h | 8 ++++++++ src/switch_core_media.c | 17 +++++++++++++++-- src/switch_core_session.c | 17 +++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 92e1452aa0..6299e09c52 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -1359,6 +1359,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_set_video_write_impl(switch_ */ SWITCH_DECLARE(void) switch_core_session_reset(_In_ switch_core_session_t *session, switch_bool_t flush_dtmf, switch_bool_t reset_read_codec); +/*! + \brief Reset the buffers and resampler on a session, fail if can not lock codec mutexes + \param session the session to reset + \param flush_dtmf flush all queued dtmf events too + \return SWITCH_STATUS_SUCCESS if the session was reset +*/ +SWITCH_DECLARE(switch_status_t) switch_core_session_try_reset(switch_core_session_t* session, switch_bool_t flush_dtmf, switch_bool_t reset_read_codec); + /*! \brief Write a frame to a session \param session the session to write to diff --git a/src/switch_core_media.c b/src/switch_core_media.c index fe0abd918d..ac8b9b9f71 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -3702,9 +3702,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_ int resetting = 0; switch_media_handle_t *smh; switch_rtp_engine_t *a_engine; + switch_time_t start = switch_micro_time_now(); switch_assert(session); - + +retry: switch_mutex_lock(session->codec_init_mutex); if (!(smh = session->media_handle)) { @@ -3726,7 +3728,18 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_ (uint32_t) a_engine->read_impl.microseconds_per_packet / 1000 != a_engine->cur_payload_map->codec_ms || a_engine->read_impl.samples_per_second != a_engine->cur_payload_map->rm_rate ) { - switch_core_session_reset(session, 0, 0); + if (switch_core_session_try_reset(session, 0, 0) != SWITCH_STATUS_SUCCESS) { + switch_time_t elapsed = switch_micro_time_now() - start; + if (elapsed > 1000000) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Could not reset session in %"SWITCH_TIME_T_FMT" us. Give up.\n", elapsed); + switch_goto_status(SWITCH_STATUS_FALSE, end); + } + + switch_mutex_unlock(session->codec_init_mutex); + switch_yield(10000); + goto retry; + } + switch_channel_audio_sync(session->channel); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, diff --git a/src/switch_core_session.c b/src/switch_core_session.c index f8ebe3db72..323adfc482 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -1364,6 +1364,23 @@ SWITCH_DECLARE(uint32_t) switch_core_session_flush_private_events(switch_core_se return x; } +SWITCH_DECLARE(switch_status_t) switch_core_session_try_reset(switch_core_session_t* session, switch_bool_t flush_dtmf, switch_bool_t reset_read_codec) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + + if (switch_mutex_trylock(session->codec_read_mutex) == SWITCH_STATUS_SUCCESS) { + if (switch_mutex_trylock(session->codec_write_mutex) == SWITCH_STATUS_SUCCESS) { + switch_core_session_reset(session, flush_dtmf, reset_read_codec); + switch_mutex_unlock(session->codec_write_mutex); + status = SWITCH_STATUS_SUCCESS; + } + + switch_mutex_unlock(session->codec_read_mutex); + } + + return status; +} + SWITCH_DECLARE(void) switch_core_session_reset(switch_core_session_t *session, switch_bool_t flush_dtmf, switch_bool_t reset_read_codec) { switch_channel_t *channel = switch_core_session_get_channel(session);