From 56a68e3ad9dcb61dd939c87f457e14455ef056a7 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 23 Dec 2015 16:03:35 -0600 Subject: [PATCH] FS-8677 #resolve [Crash (possible memory corruption) after codec change] --- src/include/switch_core_media.h | 3 +- src/include/switch_rtp.h | 1 + .../mod_conference/conference_loop.c | 23 ++++-- .../mod_conference/conference_member.c | 11 +-- .../mod_conference/mod_conference.h | 1 + src/switch_channel.c | 37 +++++---- src/switch_core_media.c | 75 +++++++++++++++---- src/switch_ivr_bridge.c | 2 +- src/switch_rtp.c | 9 +++ 9 files changed, 116 insertions(+), 46 deletions(-) diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index c8ddcf2c62..c021d0a90e 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -342,7 +342,8 @@ SWITCH_DECLARE(switch_file_handle_t *) switch_core_media_get_video_file(switch_c SWITCH_DECLARE(switch_bool_t) switch_core_session_in_video_thread(switch_core_session_t *session); SWITCH_DECLARE(switch_bool_t) switch_core_media_check_dtls(switch_core_session_t *session, switch_media_type_t type); SWITCH_DECLARE(switch_status_t) switch_core_media_set_outgoing_bitrate(switch_core_session_t *session, switch_media_type_t type, uint32_t bitrate); - +SWITCH_DECLARE(switch_status_t) switch_core_media_reset_jb(switch_core_session_t *session, switch_media_type_t type); + SWITCH_END_EXTERN_C #endif /* For Emacs: diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index 2c5dce8f58..3fdd1ed325 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -269,6 +269,7 @@ SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host, SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_session, const char *host, switch_port_t port, switch_port_t remote_rtcp_port, switch_bool_t change_adv_addr, const char **err); +SWITCH_DECLARE(void) switch_rtp_reset_jb(switch_rtp_t *rtp_session); SWITCH_DECLARE(char *) switch_rtp_get_remote_host(switch_rtp_t *rtp_session); SWITCH_DECLARE(switch_port_t) switch_rtp_get_remote_port(switch_rtp_t *rtp_session); SWITCH_DECLARE(void) switch_rtp_reset_media_timer(switch_rtp_t *rtp_session); diff --git a/src/mod/applications/mod_conference/conference_loop.c b/src/mod/applications/mod_conference/conference_loop.c index c31fb6ddcd..ed2d54bf12 100644 --- a/src/mod/applications/mod_conference/conference_loop.c +++ b/src/mod/applications/mod_conference/conference_loop.c @@ -746,15 +746,24 @@ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *ob } if (switch_channel_test_flag(member->channel, CF_CONFERENCE_RESET_MEDIA)) { + member->reset_media = 10; + switch_channel_audio_sync(member->channel); switch_channel_clear_flag(member->channel, CF_CONFERENCE_RESET_MEDIA); - member->loop_loop = 1; - + } + + if (member->reset_media) { + if (--member->reset_media > 0) { + goto do_continue; + } + if (conference_member_setup_media(member, member->conference)) { switch_mutex_unlock(member->read_mutex); break; } + + member->loop_loop = 1; - goto do_continue; + goto do_continue; } if (switch_test_flag(read_frame, SFF_CNG)) { @@ -1199,10 +1208,10 @@ void conference_loop_output(conference_member_t *member) uint32_t mux_used = 0; - if (switch_channel_test_flag(member->channel, CF_CONFERENCE_RESET_MEDIA)) { - switch_cond_next(); - continue; - } + //if (member->reset_media || switch_channel_test_flag(member->channel, CF_CONFERENCE_RESET_MEDIA)) { + // switch_cond_next(); + // continue; + //} switch_mutex_lock(member->write_mutex); diff --git a/src/mod/applications/mod_conference/conference_member.c b/src/mod/applications/mod_conference/conference_member.c index 9f3fd8a89f..827812d162 100644 --- a/src/mod/applications/mod_conference/conference_member.c +++ b/src/mod/applications/mod_conference/conference_member.c @@ -1620,13 +1620,7 @@ int conference_member_setup_media(conference_member_t *member, conference_obj_t switch_mutex_lock(member->audio_out_mutex); - if (!member->orig_read_impl.samples_per_second) { - switch_core_session_get_read_impl(member->session, &member->orig_read_impl); - member->native_rate = read_impl.samples_per_second; - } - - read_impl = member->orig_read_impl; - + switch_core_session_get_read_impl(member->session, &read_impl); if (switch_core_codec_ready(&member->read_codec)) { switch_core_codec_destroy(&member->read_codec); @@ -1642,6 +1636,9 @@ int conference_member_setup_media(conference_member_t *member, conference_obj_t switch_resample_destroy(&member->read_resampler); } + switch_core_session_get_read_impl(member->session, &member->orig_read_impl); + member->native_rate = member->orig_read_impl.samples_per_second; + /* Setup a Signed Linear codec for reading audio. */ if (switch_core_codec_init(&member->read_codec, "L16", diff --git a/src/mod/applications/mod_conference/mod_conference.h b/src/mod/applications/mod_conference/mod_conference.h index 0554bfd53c..d4a03cfb2e 100644 --- a/src/mod/applications/mod_conference/mod_conference.h +++ b/src/mod/applications/mod_conference/mod_conference.h @@ -769,6 +769,7 @@ struct conference_member { int max_bw_in; int force_bw_in; int max_bw_out; + int reset_media; }; typedef enum { diff --git a/src/switch_channel.c b/src/switch_channel.c index 1b8f1e894e..8a7a5ceab7 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -350,27 +350,36 @@ SWITCH_DECLARE(switch_channel_callstate_t) switch_channel_str2callstate(const ch SWITCH_DECLARE(void) switch_channel_perform_audio_sync(switch_channel_t *channel, const char *file, const char *func, int line) { if (switch_channel_media_up(channel)) { - switch_core_session_message_t msg = { 0 }; - msg.message_id = SWITCH_MESSAGE_INDICATE_AUDIO_SYNC; - msg.from = channel->name; - msg._file = file; - msg._func = func; - msg._line = line; - switch_core_session_receive_message(channel->session, &msg); + switch_core_session_message_t *msg = NULL; + + msg = switch_core_session_alloc(channel->session, sizeof(*msg)); + MESSAGE_STAMP_FFL(msg); + msg->message_id = SWITCH_MESSAGE_INDICATE_AUDIO_SYNC; + msg->from = channel->name; + msg->_file = file; + msg->_func = func; + msg->_line = line; + + switch_core_session_queue_message(channel->session, msg); } } SWITCH_DECLARE(void) switch_channel_perform_video_sync(switch_channel_t *channel, const char *file, const char *func, int line) { + if (switch_channel_media_up(channel)) { - switch_core_session_message_t msg = { 0 }; - msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_SYNC; - msg.from = channel->name; - msg._file = file; - msg._func = func; - msg._line = line; - switch_core_session_receive_message(channel->session, &msg); + switch_core_session_message_t *msg = NULL; + + msg = switch_core_session_alloc(channel->session, sizeof(*msg)); + MESSAGE_STAMP_FFL(msg); + msg->message_id = SWITCH_MESSAGE_INDICATE_VIDEO_SYNC; + msg->from = channel->name; + msg->_file = file; + msg->_func = func; + msg->_line = line; + + switch_core_session_queue_message(channel->session, msg); } } diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 2456925ce9..6513eb9a66 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -2120,6 +2120,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session return SWITCH_STATUS_FALSE; } + if (switch_channel_test_flag(session->channel, CF_LEG_HOLDING)) { + return SWITCH_STATUS_INUSE; + } + if (smh->read_mutex[type] && switch_mutex_trylock(smh->read_mutex[type]) != SWITCH_STATUS_SUCCESS) { /* return CNG, another thread is already reading */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s is already being read for %s\n", @@ -2180,7 +2184,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session if (type == SWITCH_MEDIA_TYPE_VIDEO) { switch_core_media_set_video_codec(session, 1); } else { - if (switch_core_media_set_codec(session, 1, 0) != SWITCH_STATUS_SUCCESS) { + if (switch_core_media_set_codec(session, 1, smh->mparams->codec_flags) != SWITCH_STATUS_SUCCESS) { *frame = NULL; switch_goto_status(SWITCH_STATUS_GENERR, end); } @@ -2777,6 +2781,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_ if (!force) { switch_goto_status(SWITCH_STATUS_SUCCESS, end); } + if (strcasecmp(a_engine->read_impl.iananame, a_engine->cur_payload_map->iananame) || (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 ) { @@ -2802,7 +2807,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_ "Changing Codec from %s@%dms@%dhz to %s@%dms@%luhz\n", a_engine->read_impl.iananame, a_engine->read_impl.microseconds_per_packet / 1000, - a_engine->read_impl.samples_per_second, + a_engine->read_impl.actual_samples_per_second, a_engine->cur_payload_map->iananame, a_engine->cur_payload_map->codec_ms, @@ -2860,6 +2865,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_ a_engine->write_codec.session = session; + if (switch_rtp_ready(a_engine->rtp_session)) { + switch_channel_audio_sync(session->channel); + switch_rtp_reset_jb(a_engine->rtp_session); + } + switch_channel_set_variable(session->channel, "rtp_use_codec_name", a_engine->cur_payload_map->iananame); switch_channel_set_variable(session->channel, "rtp_use_codec_fmtp", a_engine->cur_payload_map->rm_fmtp); switch_channel_set_variable_printf(session->channel, "rtp_use_codec_rate", "%d", a_engine->cur_payload_map->rm_rate); @@ -4383,24 +4393,28 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->cur_payload_map->recv_pt); switch_channel_set_variable(session->channel, "rtp_audio_recv_pt", tmp); - if (switch_core_codec_ready(&a_engine->read_codec) && - (strcasecmp(matches[0].imp->iananame, a_engine->read_codec.implementation->iananame) || - matches[0].imp->microseconds_per_packet != a_engine->read_codec.implementation->microseconds_per_packet || - matches[0].imp->samples_per_second != a_engine->read_codec.implementation->samples_per_second - )) { + if (a_engine->read_impl.iananame) { + if (!switch_core_codec_ready(&a_engine->read_codec) || + ((strcasecmp(matches[0].imp->iananame, a_engine->read_impl.iananame) || + matches[0].imp->microseconds_per_packet != a_engine->read_impl.microseconds_per_packet || + matches[0].imp->samples_per_second != a_engine->read_impl.samples_per_second + ))) { - a_engine->reset_codec = 1; - } - - if (switch_core_media_set_codec(session, 0, smh->mparams->codec_flags) == SWITCH_STATUS_SUCCESS) { - if (check_ice(smh, SWITCH_MEDIA_TYPE_AUDIO, sdp, m) == SWITCH_STATUS_FALSE) { - match = 0; - } else { - got_audio = 1; + a_engine->reset_codec = 1; } - } else { + } else if (switch_core_media_set_codec(session, 0, smh->mparams->codec_flags) != SWITCH_STATUS_SUCCESS) { match = 0; } + + if (match) { + if (check_ice(smh, SWITCH_MEDIA_TYPE_AUDIO, sdp, m) == SWITCH_STATUS_FALSE) { + match = 0; + got_audio = 0; + } else { + got_audio = 1; + } + } + } for (map = m->m_rtpmaps; map; map = map->rm_next) { @@ -8919,6 +8933,28 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_outgoing_bitrate(switch_co return status; } +//? +SWITCH_DECLARE(switch_status_t) switch_core_media_reset_jb(switch_core_session_t *session, switch_media_type_t type) +{ + switch_media_handle_t *smh; + switch_rtp_engine_t *engine; + + switch_assert(session); + + if (!(smh = session->media_handle)) { + return SWITCH_STATUS_FALSE; + } + + engine = &smh->engines[type]; + + if (switch_rtp_ready(engine->rtp_session)) { + switch_rtp_reset_jb(engine->rtp_session); + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; +} + //? SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) { @@ -8943,6 +8979,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se case SWITCH_MESSAGE_RESAMPLE_EVENT: { + if (switch_rtp_ready(a_engine->rtp_session)) { + switch_channel_audio_sync(session->channel); + switch_rtp_reset_jb(a_engine->rtp_session); + } + if (switch_channel_test_flag(session->channel, CF_CONFERENCE)) { switch_channel_set_flag(session->channel, CF_CONFERENCE_RESET_MEDIA); } @@ -9211,12 +9252,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC: if (switch_rtp_ready(a_engine->rtp_session)) { rtp_flush_read_buffer(a_engine->rtp_session, SWITCH_RTP_FLUSH_ONCE); + switch_rtp_reset_jb(a_engine->rtp_session); } goto end; case SWITCH_MESSAGE_INDICATE_VIDEO_SYNC: if (switch_rtp_ready(v_engine->rtp_session)) { switch_rtp_flush(v_engine->rtp_session); + switch_rtp_reset_jb(v_engine->rtp_session); } goto end; case SWITCH_MESSAGE_INDICATE_3P_MEDIA: diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index 5e8a5a50be..cdebd44558 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -694,7 +694,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) continue; } - if (status != SWITCH_STATUS_BREAK && !switch_channel_test_flag(chan_a, CF_HOLD)) { + if (status != SWITCH_STATUS_BREAK && !switch_channel_test_flag(chan_a, CF_HOLD) && !switch_channel_test_flag(chan_b, CF_LEG_HOLDING)) { if (switch_core_session_write_frame(session_b, read_frame, SWITCH_IO_FLAG_NONE, stream_id) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session_a), SWITCH_LOG_DEBUG, "%s ending bridge by request from write function\n", switch_channel_get_name(chan_b)); diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 811ff437e8..5646b8e86e 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -2740,6 +2740,15 @@ SWITCH_DECLARE(void) switch_rtp_set_max_missed_packets(switch_rtp_t *rtp_session rtp_session->max_missed_packets = max; } +SWITCH_DECLARE(void) switch_rtp_reset_jb(switch_rtp_t *rtp_session) +{ + if (switch_rtp_ready(rtp_session)) { + if (rtp_session->jb) { + switch_jb_reset(rtp_session->jb); + } + } +} + SWITCH_DECLARE(void) switch_rtp_reset_vb(switch_rtp_t *rtp_session) { if (rtp_session->vb) {