]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
[Core] Add new switch_core_session_try_reset() API to fix a deadlock for the case...
authorAndrey Volk <andywolk@gmail.com>
Fri, 26 Feb 2021 22:04:16 +0000 (01:04 +0300)
committerAndrey Volk <andywolk@gmail.com>
Mon, 22 Mar 2021 15:47:46 +0000 (18:47 +0300)
src/include/switch_core.h
src/switch_core_media.c
src/switch_core_session.c

index 92e1452aa09b6a14c77fdcec30a044ee8bd2a146..6299e09c52191889f3ddeda22882a8a49e9cf92e 100644 (file)
@@ -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
index fe0abd918d51e673f88843040c4e80fb01ff3273..ac8b9b9f71b3a3d232403987401c47e52dc0d1f5 100644 (file)
@@ -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,
index f8ebe3db723cc5c862e4e99ab37d916ddb9bbf10..323adfc48268f601a975c27d4d47c963643720fe 100644 (file)
@@ -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);