From 349b02c2e65e9f3b900fa0c4d51f9d6fb02ac922 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 18 Nov 2009 19:22:45 +0000 Subject: [PATCH] video improvements git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@15524 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_types.h | 3 +- src/mod/endpoints/mod_sofia/mod_sofia.c | 14 +++- src/mod/endpoints/mod_sofia/sofia.c | 5 +- src/mod/endpoints/mod_sofia/sofia_glue.c | 93 +++++++++++++++++++++++- src/switch_ivr_bridge.c | 40 ++++++---- src/switch_rtp.c | 28 +++++-- 6 files changed, 150 insertions(+), 33 deletions(-) diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 91d20f68e7..fa098f23aa 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -515,7 +515,8 @@ typedef enum { SWITCH_ZRTP_FLAG_SECURE_MITM_SEND = (1 << 25), SWITCH_ZRTP_FLAG_SECURE_MITM_RECV = (1 << 26), SWITCH_RTP_FLAG_DEBUG_RTP_READ = (1 << 27), - SWITCH_RTP_FLAG_DEBUG_RTP_WRITE = (1 << 28) + SWITCH_RTP_FLAG_DEBUG_RTP_WRITE = (1 << 28), + SWITCH_RTP_FLAG_VIDEO = (1 << 29) } switch_rtp_flag_enum_t; typedef uint32_t switch_rtp_flag_t; diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 98f148259b..4890a54c85 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -293,6 +293,14 @@ switch_status_t sofia_on_destroy(switch_core_session_t *session) switch_core_codec_destroy(&tech_pvt->write_codec); } + if (switch_core_codec_ready(&tech_pvt->video_read_codec)) { + switch_core_codec_destroy(&tech_pvt->video_read_codec); + } + + if (switch_core_codec_ready(&tech_pvt->video_write_codec)) { + switch_core_codec_destroy(&tech_pvt->video_write_codec); + } + switch_core_session_unset_read_codec(session); switch_core_session_unset_write_codec(session); @@ -685,7 +693,7 @@ static switch_status_t sofia_write_video_frame(switch_core_session_t *session, s { private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session); switch_channel_t *channel = switch_core_session_get_channel(session); - switch_status_t status = SWITCH_STATUS_SUCCESS; + int wrote = 0; switch_assert(tech_pvt != NULL); @@ -710,10 +718,10 @@ static switch_status_t sofia_write_video_frame(switch_core_session_t *session, s } if (!switch_test_flag(frame, SFF_CNG)) { - switch_rtp_write_frame(tech_pvt->video_rtp_session, frame); + wrote = switch_rtp_write_frame(tech_pvt->video_rtp_session, frame); } - return status; + return wrote > 0 ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_GENERR; } static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index e172b945fe..67b094edad 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -2565,7 +2565,7 @@ switch_status_t config_sofia(int reload, char *profile_name) } } else if (!strcasecmp(var, "rtp-ip")) { char *ip = mod_sofia_globals.guess_ip; - + if (!strcmp(val, "0.0.0.0")) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid IP 0.0.0.0 replaced with %s\n", mod_sofia_globals.guess_ip); } else { @@ -4057,12 +4057,11 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Processing updated SDP\n"); if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "RTP Error!\n"); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); goto done; - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Processing updated SDP\n"); } } else { sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index f857a392c4..5c38b4c09a 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -2537,6 +2537,86 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f sofia_glue_check_video_codecs(tech_pvt); + /******************************************************************************************/ + if (tech_pvt->video_rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) { + //const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE); + //const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE); + char *remote_host = switch_rtp_get_remote_host(tech_pvt->video_rtp_session); + switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->video_rtp_session); + + if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_video_ip) && remote_port == tech_pvt->remote_sdp_video_port) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Video params are unchanged for %s.\n", switch_channel_get_name(tech_pvt->channel)); + goto video_up; + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Video params changed for %s from %s:%d to %s:%d\n", + switch_channel_get_name(tech_pvt->channel), + remote_host, remote_port, tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port); + } + } + + if (!switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "VIDEO RTP [%s] %s port %d -> %s port %d codec: %u ms: %d\n", + switch_channel_get_name(tech_pvt->channel), + tech_pvt->local_sdp_audio_ip, + tech_pvt->local_sdp_video_port, + tech_pvt->remote_sdp_video_ip, + tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000); + } + + switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->local_sdp_video_port); + switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip); + switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp); + + if (tech_pvt->video_rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) { + sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE); + + if (switch_rtp_set_remote_address(tech_pvt->video_rtp_session, tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port, SWITCH_TRUE, &err) != + SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", err); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "VIDEO RTP CHANGING DEST TO: [%s:%d]\n", + tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port); + if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) && + !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) { + /* Reactivate the NAT buster flag. */ + switch_rtp_set_flag(tech_pvt->video_rtp_session, SWITCH_RTP_FLAG_AUTOADJ); + } + } + goto video_up; + } + + if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) { + if ((status = sofia_glue_tech_proxy_remote_addr(tech_pvt)) != SWITCH_STATUS_SUCCESS) { + goto end; + } + + if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) && + !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) { + flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_PROXY_MEDIA | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT); + } else { + flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_PROXY_MEDIA | SWITCH_RTP_FLAG_DATAWAIT); + } + timer_name = NULL; + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, + "PROXY VIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n", + switch_channel_get_name(tech_pvt->channel), + tech_pvt->local_sdp_audio_ip, + tech_pvt->local_sdp_video_port, + tech_pvt->remote_sdp_video_ip, + tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000); + + } else { + timer_name = tech_pvt->profile->timer_name; + + if ((var = switch_channel_get_variable(tech_pvt->channel, "rtp_timer_name"))) { + timer_name = (char *) var; + } + } + + /******************************************************************************************/ + + if (sofia_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding && tech_pvt->remote_sdp_video_port) { if (!tech_pvt->local_sdp_video_port) { sofia_glue_tech_choose_video_port(tech_pvt, 1); @@ -2545,9 +2625,9 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) && !switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) { flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_USE_TIMER | SWITCH_RTP_FLAG_AUTOADJ | - SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_NOBLOCK | SWITCH_RTP_FLAG_RAW_WRITE); + SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_RAW_WRITE); } else { - flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_USE_TIMER | SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_NOBLOCK | SWITCH_RTP_FLAG_RAW_WRITE); + flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_USE_TIMER | SWITCH_RTP_FLAG_DATAWAIT | SWITCH_RTP_FLAG_RAW_WRITE); } if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) { @@ -2555,13 +2635,15 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f } sofia_glue_tech_set_video_codec(tech_pvt, 0); - /* set video timer to 10ms so it can co-exist with audio */ + flags &= ~(SWITCH_RTP_FLAG_USE_TIMER | SWITCH_RTP_FLAG_NOBLOCK); + flags |= SWITCH_RTP_FLAG_VIDEO | SWITCH_RTP_FLAG_PROXY_MEDIA; + tech_pvt->video_rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip, tech_pvt->local_sdp_video_port, tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt, - 1, 10000, (switch_rtp_flag_t) flags, NULL, &err, switch_core_session_get_pool(tech_pvt->session)); + 1, 90000, (switch_rtp_flag_t) flags, NULL, &err, switch_core_session_get_pool(tech_pvt->session)); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%sVIDEO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n", switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA) ? "PROXY " : "", @@ -2580,6 +2662,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f goto end; } } + } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err)); switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); @@ -2588,6 +2671,8 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f goto end; } + video_up: + sofia_set_flag(tech_pvt, TFLAG_IO); status = SWITCH_STATUS_SUCCESS; diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index dc18f0648c..ae5a69cf84 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -59,22 +59,29 @@ static void *SWITCH_THREAD_FUNC video_bridge_thread(switch_thread_t *thread, voi break; } - switch_core_session_write_video_frame(vh->session_b, read_frame, SWITCH_IO_FLAG_NONE, 0); + if (!switch_test_flag(read_frame, SFF_CNG)) { + if (switch_core_session_write_video_frame(vh->session_b, read_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) { + break; + } + } } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s video thread ended.\n", switch_channel_get_name(channel)); + vh->up = 0; return NULL; } -static void launch_video(struct vid_helper *vh) +static switch_thread_t *launch_video(struct vid_helper *vh) { switch_thread_t *thread; switch_threadattr_t *thd_attr = NULL; switch_threadattr_create(&thd_attr, switch_core_session_get_pool(vh->session_a)); - switch_threadattr_detach_set(thd_attr, 1); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); switch_thread_create(&thread, thd_attr, video_bridge_thread, vh, switch_core_session_get_pool(vh->session_a)); + return thread; } #endif @@ -172,6 +179,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) time_t answer_limit = 0; #ifdef SWITCH_VIDEO_IN_THREADS + switch_thread_t *vid_thread = NULL; struct vid_helper vh = { 0 }; uint32_t vid_launch = 0; #endif @@ -325,7 +333,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) vid_launch++; vh.session_a = session_a; vh.session_b = session_b; - launch_video(&vh); + vid_thread = launch_video(&vh); } #endif @@ -468,17 +476,6 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) switch_core_codec_destroy(&silence_codec); } - -#ifdef SWITCH_VIDEO_IN_THREADS - if (vh.up) { - vh.up = -1; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ending video thread.\n"); - while (vh.up) { - switch_yield(100000); - } - } -#endif - if (!inner_bridge) { hook_var = switch_channel_get_variable(chan_a, SWITCH_API_BRIDGE_END_VARIABLE); } @@ -530,6 +527,19 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) end: +#ifdef SWITCH_VIDEO_IN_THREADS + if (vid_thread) { + switch_status_t st; + vh.up = -1; + switch_core_session_kill_channel(session_a, SWITCH_SIG_BREAK); + switch_core_session_kill_channel(session_b, SWITCH_SIG_BREAK); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ending video thread.\n"); + switch_thread_join(&st, vid_thread); + } +#endif + + + switch_core_session_reset(session_a, SWITCH_TRUE, SWITCH_TRUE); switch_channel_set_variable(chan_a, SWITCH_BRIDGE_VARIABLE, NULL); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "BRIDGE THREAD DONE [%s]\n", switch_channel_get_name(chan_a)); diff --git a/src/switch_rtp.c b/src/switch_rtp.c index de3bf129af..7fcf2257d7 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -1997,7 +1997,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ if (!bytes && (io_flags & SWITCH_IO_FLAG_NOBLOCK)) { return_cng_frame(); - } + } if (check && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_AUTO_CNG) && @@ -2896,23 +2896,33 @@ SWITCH_DECLARE(int) switch_rtp_write_frame(switch_rtp_t *rtp_session, switch_fra uint8_t fwd = 0; void *data = NULL; uint32_t len, ts = 0; - switch_payload_t payload; + switch_payload_t payload = 0; rtp_msg_t *send_msg = NULL; - + if (!switch_rtp_ready(rtp_session) || !rtp_session->remote_addr) { return -1; } if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA)) { switch_size_t bytes; - + char bufa[30]; + const char *tx_host; /* Fast PASS! */ if (!switch_test_flag(frame, SFF_PROXY_PACKET)) { return 0; } bytes = frame->packetlen; - if (switch_socket_sendto(rtp_session->sock_output, rtp_session->remote_addr, 0, frame->packet, &bytes) != SWITCH_STATUS_SUCCESS) { - return -1; + tx_host = switch_get_addr(bufa, sizeof(bufa), rtp_session->remote_addr); + + + send_msg = frame->packet; + + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO)) { + send_msg->header.pt = rtp_session->payload; + + if (switch_socket_sendto(rtp_session->sock_output, rtp_session->remote_addr, 0, frame->packet, &bytes) != SWITCH_STATUS_SUCCESS) { + return -1; + } } rtp_session->stats.outbound.raw_bytes += bytes; @@ -2947,7 +2957,11 @@ SWITCH_DECLARE(int) switch_rtp_write_frame(switch_rtp_t *rtp_session, switch_fra switch_assert(frame != NULL); if (switch_test_flag(frame, SFF_CNG)) { - payload = rtp_session->cng_pt; + if (rtp_session->cng_pt) { + payload = rtp_session->cng_pt; + } else { + return (int)frame->packetlen; + } } else { payload = rtp_session->payload; }