From d6af3a1fddb3806860b1e1140df4b90ccf52d7a9 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 20 Dec 2012 22:57:47 -0600 Subject: [PATCH] omfg --- configure.in | 6 +- src/include/switch_core_media.h | 37 +- src/include/switch_types.h | 6 + src/mod/endpoints/mod_sofia/mod_sofia.c | 18 +- src/mod/endpoints/mod_sofia/mod_sofia.h | 51 +- src/mod/endpoints/mod_sofia/rtp.c | 2 +- src/mod/endpoints/mod_sofia/sofia.c | 41 +- src/mod/endpoints/mod_sofia/sofia_glue.c | 205 +- src/mod/endpoints/mod_sofia/sofia_media.c | 553 +---- src/switch_core_media.c | 2236 +++++++++++++++++---- 10 files changed, 2042 insertions(+), 1113 deletions(-) diff --git a/configure.in b/configure.in index b47d725e35..447764d984 100644 --- a/configure.in +++ b/configure.in @@ -155,8 +155,8 @@ fi AX_PATH_LIBGNUTLS() # set defaults for use on all platforms -SWITCH_AM_CFLAGS="-I${switch_srcdir}/src/include -I${switch_builddir}/src/include -I${switch_srcdir}/libs/libteletone/src -I${switch_srcdir}/libs/stfu" -SWITCH_AM_CXXFLAGS="-I${switch_srcdir}/src/include -I${switch_builddir}/src/include -I${switch_srcdir}/libs/libteletone/src -I${switch_srcdir}/libs/stfu" +SWITCH_AM_CFLAGS="-I${switch_srcdir}/src/include -I${switch_builddir}/src/include -I${switch_srcdir}/libs/libteletone/src -I${switch_srcdir}/libs/stfu -I${switch_srcdir}/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip -I${switch_srcdir}/libs/sofia-sip/libsofia-sip-ua/su" +SWITCH_AM_CXXFLAGS="-I${switch_srcdir}/src/include -I${switch_builddir}/src/include -I${switch_srcdir}/libs/libteletone/src -I${switch_srcdir}/libs/stfu -I${switch_srcdir}/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip -I${switch_srcdir}/libs/sofia-sip/libsofia-sip-ua/su" SWITCH_AM_LDFLAGS="-lm" #set SOLINK variable based on compiler and host @@ -220,6 +220,8 @@ AC_MSG_RESULT([using libtool library extension... ${LIBTOOL_LIB_EXTEN}]) AC_ARG_ENABLE(64, [AC_HELP_STRING([--enable-64],[build with 64 bit support])],[enable_64="$enable_64"],[enable_64="no"]) +APR_ADDTO(SWITCH_AM_CFLAGS, -Ilibs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip -Ilibs/sofia-sip/libsofia-sip-ua/su) + # tweak compiler specific flags if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then APR_ADDTO(SWITCH_AM_CFLAGS, -KPIC) diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index c72e453e08..4ee5f1880e 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -32,10 +32,20 @@ #ifndef SWITCH_CORE_MEDIA_H #define SWITCH_CORE_MEDIA_H + +#include #include SWITCH_BEGIN_EXTERN_C +typedef enum { + DTMF_2833, + DTMF_INFO, + DTMF_NONE +} switch_core_media_dtmf_t; + + + typedef enum { SM_NDLB_ALLOW_BAD_IANANAME = (1 << 0), SM_NDLB_ALLOW_NONDUP_SDP = (1 << 1), @@ -44,7 +54,18 @@ typedef enum { } switch_core_media_NDLB_t; typedef enum { - SCMF_DISABLE_TRANSCODING = (1 << 0) + SCMF_RUNNING, + SCMF_DISABLE_TRANSCODING, + SCMF_AUTOFIX_TIMING, + SCMF_CODEC_GREEDY, + SCMF_CODEC_SCROOGE, + SCMF_DISABLE_HOLD, + SCMF_RENEG_ON_HOLD, + SCMF_RENEG_ON_REINVITE, + SCMF_T38_PASSTHRU, + SCMF_LIBERAL_DTMF, + SCMF_SUPPRESS_CNG, + SCMF_MAX } switch_core_media_flag_t; struct switch_media_handle_s; @@ -58,7 +79,8 @@ typedef enum { typedef enum { SCM_INBOUND_CODEC_STRING, SCM_OUTBOUND_CODEC_STRING, - SCM_TEST, + SCM_AUTO_RTP_BUGS, + SCM_MANUAL_RTP_BUGS, SCM_MAX } scm_param_t; @@ -79,6 +101,7 @@ SWITCH_DECLARE(int32_t) switch_media_handle_test_ndlb(switch_media_handle_t *smh SWITCH_DECLARE(void) switch_media_handle_set_media_flag(switch_media_handle_t *smh, switch_core_media_flag_t flag); SWITCH_DECLARE(void) switch_media_handle_clear_media_flag(switch_media_handle_t *smh, switch_core_media_flag_t flag); SWITCH_DECLARE(int32_t) switch_media_handle_test_media_flag(switch_media_handle_t *smh, switch_core_media_flag_t flag); +SWITCH_DECLARE(void) switch_media_handle_set_media_flags(switch_media_handle_t *smh, switch_core_media_flag_t flags[]); SWITCH_DECLARE(void) switch_core_session_check_outgoing_crypto(switch_core_session_t *session, const char *sec_var); SWITCH_DECLARE(const char *) switch_core_session_local_crypto_key(switch_core_session_t *session, switch_media_type_t type); SWITCH_DECLARE(int) switch_core_session_check_incoming_crypto(switch_core_session_t *session, @@ -93,6 +116,16 @@ SWITCH_DECLARE(void) switch_core_media_set_rtp_session(switch_core_session_t *se SWITCH_DECLARE(void) switch_media_set_param(switch_media_handle_t *smh, scm_param_t param, ...); SWITCH_DECLARE(void *) switch_media_get_param(switch_media_handle_t *smh, scm_param_t param); SWITCH_DECLARE(const char *)switch_core_media_get_codec_string(switch_core_session_t *session); +SWITCH_DECLARE(void) switch_core_media_parse_rtp_bugs(switch_rtp_bug_flag_t *flag_pole, const char *str); +SWITCH_DECLARE(switch_t38_options_t *) switch_core_media_process_udptl(switch_core_session_t *session, sdp_session_t *sdp, sdp_media_t *m); +SWITCH_DECLARE(switch_t38_options_t *) switch_core_media_extract_t38_options(switch_core_session_t *session, const char *r_sdp); +SWITCH_DECLARE(void) switch_core_media_pass_zrtp_hash(switch_core_session_t *session); +SWITCH_DECLARE(void) switch_core_media_find_zrtp_hash(switch_core_session_t *session, sdp_session_t *sdp); +SWITCH_DECLARE(const char *) switch_core_media_get_zrtp_hash(switch_core_session_t *session, switch_media_type_t type, switch_bool_t local); +SWITCH_DECLARE(void) switch_core_media_pass_zrtp_hash2(switch_core_session_t *aleg_session, switch_core_session_t *bleg_session); +SWITCH_DECLARE(int) switch_core_media_toggle_hold(switch_core_session_t *session, int sendonly); +SWITCH_DECLARE(void) switch_core_media_copy_t38_options(switch_t38_options_t *t38_options, switch_core_session_t *session); +SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *session, const char *r_sdp, uint8_t *proceed, int reinvite, int codec_flags, switch_payload_t default_te); SWITCH_END_EXTERN_C #endif diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 50e3377671..1a69c4c256 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1282,6 +1282,12 @@ typedef enum { CF_HOLD_ON_BRIDGE, CF_SECURE, CF_CRYPTO_RECOVER, + CF_LIBERAL_DTMF, + CF_SLA_BARGE, + CF_SLA_BARGING, + CF_PROTO_HOLD, //TFLAG_SIP_HOLD + CF_HOLD_LOCK, + CF_VIDEO_POSSIBLE,//TFLAG_VIDEO /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ /* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */ CF_FLAG_MAX diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index b5355612be..93a232b9cd 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1220,7 +1220,7 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f } if ((tech_pvt->read_frame.datalen % 10) == 0 && - sofia_test_pflag(tech_pvt->profile, PFLAG_AUTOFIX_TIMING) && tech_pvt->check_frames < MAX_CODEC_CHECK_FRAMES) { + sofia_test_media_flag(tech_pvt->profile, SCMF_AUTOFIX_TIMING) && tech_pvt->check_frames < MAX_CODEC_CHECK_FRAMES) { tech_pvt->check_frames++; if (!tech_pvt->read_impl.encoded_bytes_per_packet) { @@ -1503,7 +1503,7 @@ static switch_status_t sofia_send_dtmf(switch_core_session_t *session, const swi { private_object_t *tech_pvt; char message[128] = ""; - sofia_dtmf_t dtmf_type; + switch_core_media_dtmf_t dtmf_type; tech_pvt = (private_object_t *) switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); @@ -1865,7 +1865,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi switch_channel_set_flag(tech_pvt->channel, CF_SECURE); } - if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTOFIX_TIMING)) { + if (sofia_test_media_flag(tech_pvt->profile, SCMF_AUTOFIX_TIMING)) { tech_pvt->check_frames = 0; tech_pvt->last_ts = 0; } @@ -1904,7 +1904,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi tech_pvt->num_codecs = 0; tech_pvt->rm_encoding = NULL; tech_pvt->video_rm_encoding = NULL; - sofia_clear_flag_locked(tech_pvt, TFLAG_VIDEO); + switch_channel_clear_flag(tech_pvt->channel, CF_VIDEO_POSSIBLE); sofia_media_tech_prepare_codecs(tech_pvt); sofia_media_check_video_codecs(tech_pvt); sofia_media_set_local_sdp(tech_pvt, NULL, 0, NULL, 1); @@ -5020,7 +5020,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session if (switch_channel_test_flag(o_channel, CF_ZRTP_PASSTHRU_REQ)) { const char *x = NULL; - sofia_glue_pass_zrtp_hash2(session, nsession); + switch_core_media_pass_zrtp_hash2(session, nsession); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "[zrtp_passthru] Setting a-leg inherit_codec=true\n"); switch_channel_set_variable(o_channel, "inherit_codec", "true"); if ((x = switch_channel_get_variable(o_channel, "ep_codec_string"))) { @@ -5047,7 +5047,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session tech_pvt->video_rm_rate = 90000; tech_pvt->video_codec_ms = 0; switch_channel_set_flag(tech_pvt->channel, CF_VIDEO); - sofia_set_flag(tech_pvt, TFLAG_VIDEO); + switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_POSSIBLE); } } } @@ -5649,14 +5649,14 @@ SWITCH_STANDARD_APP(sofia_sla_function) if (switch_core_session_check_interface(bargee_session, sofia_endpoint_interface)) { tech_pvt = switch_core_session_get_private(bargee_session); - sofia_clear_flag(tech_pvt, TFLAG_SLA_BARGING); - sofia_set_flag(tech_pvt, TFLAG_SLA_BARGE); + switch_channel_clear_flag(tech_pvt->channel, CF_SLA_BARGING); + switch_channel_set_flag(tech_pvt->channel, CF_SLA_BARGE); switch_ivr_transfer_variable(bargee_session, session, SWITCH_SIGNAL_BOND_VARIABLE); } if (switch_core_session_check_interface(session, sofia_endpoint_interface)) { tech_pvt = switch_core_session_get_private(session); - sofia_set_flag(tech_pvt, TFLAG_SLA_BARGING); + switch_channel_set_flag(tech_pvt->channel, CF_SLA_BARGING); } channel = switch_core_session_get_channel(session); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 389212a81e..8f6a083316 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -115,9 +115,9 @@ typedef struct private_object private_object_t; #define SOFIA_SECURE_MEDIA_VARIABLE "sip_secure_media" #define SOFIA_SECURE_MEDIA_CONFIRMED_VARIABLE "sip_secure_media_confirmed" #define SOFIA_SECURE_VIDEO_CONFIRMED_VARIABLE "sip_secure_video_confirmed" -#define SOFIA_HAS_CRYPTO_VARIABLE "sip_has_crypto" -#define SOFIA_HAS_VIDEO_CRYPTO_VARIABLE "sip_has_video_crypto" -#define SOFIA_CRYPTO_MANDATORY_VARIABLE "sip_crypto_mandatory" +//#define SOFIA_HAS_CRYPTO_VARIABLE "sip_has_crypto" +//#define SOFIA_HAS_VIDEO_CRYPTO_VARIABLE "sip_has_video_crypto" +//#define SOFIA_CRYPTO_MANDATORY_VARIABLE "sip_crypto_mandatory" #define FREESWITCH_SUPPORT "update_display,send_info" #include @@ -146,12 +146,6 @@ typedef enum { SOFIA_CONFIG_RESPAWN } sofia_config_t; -typedef enum { - DTMF_2833, - DTMF_INFO, - DTMF_NONE -} sofia_dtmf_t; - typedef struct sofia_dispatch_event_s { nua_saved_event_t event[1]; nua_handle_t *nh; @@ -210,7 +204,6 @@ typedef enum { PFLAG_REWRITE_TIMESTAMPS, PFLAG_RUNNING, PFLAG_RESPAWN, - PFLAG_GREEDY, PFLAG_MULTIREG, PFLAG_SUPPRESS_CNG, PFLAG_TLS, @@ -232,7 +225,6 @@ typedef enum { PFLAG_3PCC_PROXY, PFLAG_CALLID_AS_UUID, PFLAG_UUID_AS_CALLID, - PFLAG_SCROOGE, PFLAG_MANAGE_SHARED_APPEARANCE, PFLAG_STANDBY, PFLAG_DISABLE_SRV, @@ -241,15 +233,12 @@ typedef enum { PFLAG_AUTOFLUSH, PFLAG_NAT_OPTIONS_PING, PFLAG_ALL_REG_OPTIONS_PING, - PFLAG_AUTOFIX_TIMING, PFLAG_MESSAGE_QUERY_ON_REGISTER, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE, PFLAG_MANUAL_REDIRECT, - PFLAG_DISABLE_HOLD, PFLAG_AUTO_NAT, PFLAG_SIPCOMPACT, - PFLAG_USE_ME, PFLAG_PRESENCE_PRIVACY, PFLAG_PASS_CALLEE_ID, PFLAG_LOG_AUTH_FAIL, @@ -325,7 +314,6 @@ typedef enum { TFLAG_INB_NOMEDIA, TFLAG_LATE_NEGOTIATION, TFLAG_SDP, - TFLAG_VIDEO, TFLAG_TPORT_LOG, TFLAG_SENT_UPDATE, TFLAG_PROXY_MEDIA, @@ -342,12 +330,9 @@ typedef enum { TFLAG_JB_PAUSED, TFLAG_3PCC_INVITE, TFLAG_NOREPLY, - TFLAG_LIBERAL_DTMF, TFLAG_GOT_ACK, TFLAG_CAPTURE, TFLAG_REINVITED, - TFLAG_SLA_BARGE, - TFLAG_SLA_BARGING, TFLAG_PASS_ACK, TFLAG_DROP_DTMF, /* No new flags below this line */ @@ -596,7 +581,7 @@ struct sofia_profile { char *pnp_prov_url; char *pnp_notify_profile; sofia_cid_type_t cid_type; - sofia_dtmf_t dtmf_type; + switch_core_media_dtmf_t dtmf_type; int auto_restart; switch_port_t sip_port; switch_port_t extsipport; @@ -609,9 +594,9 @@ struct sofia_profile { int dtmf_duration; uint8_t flags[TFLAG_MAX]; uint8_t pflags[PFLAG_MAX]; + switch_core_media_flag_t media_flags[SCMF_MAX]; unsigned int mflags; unsigned int ndlb; - unsigned int media_flags; uint32_t max_calls; uint32_t nonce_ttl; nua_t *nua; @@ -816,7 +801,7 @@ struct private_object { switch_payload_t video_agreed_pt; char *video_fmtp_out; uint32_t video_count; - sofia_dtmf_t dtmf_type; + switch_core_media_dtmf_t dtmf_type; int q850_cause; char *remote_ip; int remote_port; @@ -840,11 +825,6 @@ struct private_object { switch_payload_t ianacodes[SWITCH_MAX_CODECS]; uint32_t session_timeout; enum nua_session_refresher session_refresher; - /** ZRTP **/ - char *local_sdp_audio_zrtp_hash; - char *local_sdp_video_zrtp_hash; - char *remote_sdp_audio_zrtp_hash; - char *remote_sdp_video_zrtp_hash; char *respond_phrase; int respond_code; char *respond_dest; @@ -891,6 +871,18 @@ typedef struct { #define NUTAG_WITH_THIS_MSG(msg) nutag_with, tag_ptr_v(msg) + + +#define sofia_test_media_flag(obj, flag) ((obj)->media_flags[flag] ? 1 : 0) +#define sofia_set_media_flag(obj, flag) (obj)->media_flags[flag] = 1 +#define sofia_set_media_flag_locked(obj, flag) assert(obj->flag_mutex != NULL);\ +switch_mutex_lock(obj->flag_mutex);\ +(obj)->media_flags[flag] = 1;\ +switch_mutex_unlock(obj->flag_mutex); +#define sofia_clear_media_flag_locked(obj, flag) switch_mutex_lock(obj->flag_mutex); (obj)->media_flags[flag] = 0; switch_mutex_unlock(obj->flag_mutex); +#define sofia_clear_media_flag(obj, flag) (obj)->media_flags[flag] = 0 + + #define sofia_test_pflag(obj, flag) ((obj)->pflags[flag] ? 1 : 0) #define sofia_set_pflag(obj, flag) (obj)->pflags[flag] = 1 #define sofia_set_pflag_locked(obj, flag) assert(obj->flag_mutex != NULL);\ @@ -900,6 +892,8 @@ switch_mutex_unlock(obj->flag_mutex); #define sofia_clear_pflag_locked(obj, flag) switch_mutex_lock(obj->flag_mutex); (obj)->pflags[flag] = 0; switch_mutex_unlock(obj->flag_mutex); #define sofia_clear_pflag(obj, flag) (obj)->pflags[flag] = 0 + + #define sofia_set_flag_locked(obj, flag) assert(obj->flag_mutex != NULL);\ switch_mutex_lock(obj->flag_mutex);\ (obj)->flags[flag] = 1;\ @@ -958,8 +952,6 @@ void launch_sofia_profile_thread(sofia_profile_t *profile); switch_status_t sofia_presence_chat_send(switch_event_t *message_event); void sofia_media_tech_absorb_sdp(private_object_t *tech_pvt); -void sofia_glue_pass_zrtp_hash2(switch_core_session_t *aleg_session, switch_core_session_t *bleg_session); -void sofia_glue_pass_zrtp_hash(switch_core_session_t *session); /* * \brief Sets the "ep_codec_string" channel variable, parsing r_sdp and taing codec_string in consideration @@ -1197,7 +1189,6 @@ void sofia_media_proxy_codec(switch_core_session_t *session, const char *r_sdp); switch_status_t sofia_media_sdp_map(const char *r_sdp, switch_event_t **fmtp, switch_event_t **pt); void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl); void sofia_glue_check_dtmf_type(private_object_t *tech_pvt); -void sofia_glue_parse_rtp_bugs(switch_rtp_bug_flag_t *flag_pole, const char *str); char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, nua_handle_t *nh, sofia_dispatch_event_t *de, sofia_nat_parse_t *np); void sofia_glue_pause_jitterbuffer(switch_core_session_t *session, switch_bool_t on); void sofia_process_dispatch_event(sofia_dispatch_event_t **dep); @@ -1213,8 +1204,6 @@ switch_status_t sofia_init(void); void sofia_glue_fire_events(sofia_profile_t *profile); void sofia_event_fire(sofia_profile_t *profile, switch_event_t **event); void sofia_queue_message(sofia_dispatch_event_t *de); -switch_t38_options_t *tech_process_udptl(private_object_t *tech_pvt, sdp_session_t *sdp, sdp_media_t *m); -void find_zrtp_hash(switch_core_session_t *session, sdp_session_t *sdp); void sofia_media_set_sdp_codec_string(switch_core_session_t *session, const char *r_sdp); /* For Emacs: diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 6a087f33ce..46c69df20d 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -74,7 +74,7 @@ typedef struct { switch_port_t local_port; switch_port_t remote_port; switch_payload_t agreed_pt; /*XXX*/ - sofia_dtmf_t dtmf_type; + switch_core_media_dtmf_t dtmf_type; enum { RTP_SENDONLY, RTP_RECVONLY, diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 5e7c02ba03..ea42f7731b 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -599,7 +599,7 @@ void sofia_handle_sip_i_bye(switch_core_session_t *session, int status, status = 200; phrase = "OK"; - if (sofia_test_flag(tech_pvt, TFLAG_SLA_BARGING)) { + if (switch_channel_test_flag(tech_pvt->channel, CF_SLA_BARGING)) { const char *bargee_uuid = switch_channel_get_variable(channel, "sip_barging_uuid"); switch_core_session_t *bargee_session; uint32_t ttl = 0; @@ -608,15 +608,14 @@ void sofia_handle_sip_i_bye(switch_core_session_t *session, int status, //switch_channel_t *bargee_channel = switch_core_session_get_channel(bargee_session); if ((ttl = switch_core_media_bug_count(bargee_session, "eavesdrop")) == 1) { if (switch_core_session_check_interface(bargee_session, sofia_endpoint_interface)) { - private_object_t *bargee_tech_pvt = switch_core_session_get_private(bargee_session); - sofia_clear_flag(bargee_tech_pvt, TFLAG_SLA_BARGE); + switch_channel_clear_flag(switch_core_session_get_channel(bargee_session), CF_SLA_BARGE); } } switch_core_session_rwunlock(bargee_session); } } - if (sofia_test_flag(tech_pvt, TFLAG_SLA_BARGE)) { + if (switch_channel_test_flag(tech_pvt->channel, CF_SLA_BARGE)) { switch_core_session_t *new_session, *other_session; const char *other_uuid = switch_channel_get_partner_uuid(tech_pvt->channel); char *cmd = NULL; @@ -3594,7 +3593,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) sofia_set_pflag(profile, PFLAG_STUN_ENABLED); sofia_set_pflag(profile, PFLAG_DISABLE_100REL); profile->auto_restart = 1; - sofia_set_pflag(profile, PFLAG_AUTOFIX_TIMING); + sofia_set_media_flag(profile, SCMF_AUTOFIX_TIMING); sofia_set_pflag(profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE); profile->contact_user = SOFIA_DEFAULT_CONTACT_USER; sofia_set_pflag(profile, PFLAG_PASS_CALLEE_ID); @@ -3799,9 +3798,9 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else if (!strcasecmp(var, "disable-hold")) { if (switch_true(val)) { - sofia_set_pflag(profile, PFLAG_DISABLE_HOLD); + sofia_set_media_flag(profile, SCMF_DISABLE_HOLD); } else { - sofia_clear_pflag(profile, PFLAG_DISABLE_HOLD); + sofia_clear_media_flag(profile, SCMF_DISABLE_HOLD); } } else if (!strcasecmp(var, "auto-jitterbuffer-msec")) { int msec = atoi(val); @@ -3833,11 +3832,11 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) profile->client_rport_level = 1; } } else if (!strcasecmp(var, "auto-rtp-bugs")) { - sofia_glue_parse_rtp_bugs(&profile->auto_rtp_bugs, val); + switch_core_media_parse_rtp_bugs(&profile->auto_rtp_bugs, val); } else if (!strcasecmp(var, "manual-rtp-bugs")) { - sofia_glue_parse_rtp_bugs(&profile->manual_rtp_bugs, val); + switch_core_media_parse_rtp_bugs(&profile->manual_rtp_bugs, val); } else if (!strcasecmp(var, "manual-video-rtp-bugs")) { - sofia_glue_parse_rtp_bugs(&profile->manual_video_rtp_bugs, val); + switch_core_media_parse_rtp_bugs(&profile->manual_video_rtp_bugs, val); } else if (!strcasecmp(var, "dbname")) { profile->dbname = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "presence-hosts")) { @@ -4221,9 +4220,9 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } } else if (!strcasecmp(var, "rtp-autofix-timing")) { if (switch_true(val)) { - sofia_set_pflag(profile, PFLAG_AUTOFIX_TIMING); + sofia_set_media_flag(profile, SCMF_AUTOFIX_TIMING); } else { - sofia_clear_pflag(profile, PFLAG_AUTOFIX_TIMING); + sofia_clear_media_flag(profile, SCMF_AUTOFIX_TIMING); } } else if (!strcasecmp(var, "contact-user")) { profile->contact_user = switch_core_strdup(profile->pool, val); @@ -4241,19 +4240,19 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } } else if (!strcasecmp(var, "inbound-codec-negotiation")) { if (!strcasecmp(val, "greedy")) { - sofia_set_pflag(profile, PFLAG_GREEDY); + sofia_set_media_flag(profile, SCMF_CODEC_GREEDY); } else if (!strcasecmp(val, "scrooge")) { - sofia_set_pflag(profile, PFLAG_GREEDY); - sofia_set_pflag(profile, PFLAG_SCROOGE); + sofia_set_media_flag(profile, SCMF_CODEC_GREEDY); + sofia_set_media_flag(profile, SCMF_CODEC_SCROOGE); } else { - sofia_clear_pflag(profile, PFLAG_SCROOGE); - sofia_clear_pflag(profile, PFLAG_GREEDY); + sofia_clear_media_flag(profile, SCMF_CODEC_SCROOGE); + sofia_clear_media_flag(profile, SCMF_CODEC_GREEDY); } } else if (!strcasecmp(var, "disable-transcoding")) { if (switch_true(val)) { - profile->media_flags |= SCMF_DISABLE_TRANSCODING; + sofia_set_media_flag(profile, SCMF_DISABLE_TRANSCODING); } else { - profile->media_flags &= ~SCMF_DISABLE_TRANSCODING; + sofia_clear_media_flag(profile, SCMF_DISABLE_TRANSCODING); } } else if (!strcasecmp(var, "rtp-rewrite-timestamps")) { if (switch_true(val)) { @@ -5004,7 +5003,7 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status sofia_update_callee_id(session, profile, sip, SWITCH_FALSE); - if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTOFIX_TIMING)) { + if (sofia_test_media_flag(tech_pvt->profile, SCMF_AUTOFIX_TIMING)) { tech_pvt->check_frames = 0; tech_pvt->last_ts = 0; } @@ -7425,7 +7424,7 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t if (dtmf.digit) { if (tech_pvt->dtmf_type == DTMF_INFO || - sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF)) { + sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || switch_channel_test_flag(tech_pvt->channel, CF_LIBERAL_DTMF)) { /* queue it up */ switch_channel_queue_dtmf(channel, &dtmf); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index f36551a269..f72eee39e2 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -281,7 +281,7 @@ void sofia_glue_attach_private(switch_core_session_t *session, sofia_profile_t * switch_media_handle_create(&tech_pvt->media_handle, session); switch_media_handle_set_ndlb(tech_pvt->media_handle, tech_pvt->profile->ndlb); - switch_media_handle_set_media_flag(tech_pvt->media_handle, tech_pvt->profile->media_flags); + switch_media_handle_set_media_flags(tech_pvt->media_handle, tech_pvt->profile->media_flags); switch_media_set_param(tech_pvt->media_handle, SCM_INBOUND_CODEC_STRING, profile->inbound_codec_string); switch_media_set_param(tech_pvt->media_handle, SCM_OUTBOUND_CODEC_STRING, profile->inbound_codec_string); @@ -918,7 +918,7 @@ switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt, co switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Remote video address:port [%s:%d] has not changed.\n", tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port); } else { - sofia_set_flag_locked(tech_pvt, TFLAG_VIDEO); + switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_POSSIBLE); switch_channel_set_flag(tech_pvt->channel, CF_VIDEO); if (switch_rtp_ready(tech_pvt->video_rtp_session)) { const char *rport = NULL; @@ -940,7 +940,7 @@ switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt, co /* Reactivate the NAT buster flag. */ switch_rtp_set_flag(tech_pvt->video_rtp_session, SWITCH_RTP_FLAG_AUTOADJ); } - if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTOFIX_TIMING)) { + if (sofia_test_media_flag(tech_pvt->profile, SCMF_AUTOFIX_TIMING)) { tech_pvt->check_frames = 0; } } @@ -977,7 +977,7 @@ switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt, co /* Reactivate the NAT buster flag. */ switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTOADJ); } - if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTOFIX_TIMING)) { + if (sofia_test_media_flag(tech_pvt->profile, SCMF_AUTOFIX_TIMING)) { tech_pvt->check_frames = 0; } status = SWITCH_STATUS_SUCCESS; @@ -1859,105 +1859,6 @@ void sofia_glue_deactivate_rtp(private_object_t *tech_pvt) } -void sofia_glue_pass_zrtp_hash2(switch_core_session_t *aleg_session, switch_core_session_t *bleg_session) -{ - switch_channel_t *aleg_channel; - private_object_t *aleg_tech_pvt; - switch_channel_t *bleg_channel; - private_object_t *bleg_tech_pvt; - - if (!switch_core_session_compare(aleg_session, bleg_session)) { - /* since this digs into channel internals its only compatible with sofia sessions*/ - return; - } - - aleg_channel = switch_core_session_get_channel(aleg_session); - aleg_tech_pvt = switch_core_session_get_private(aleg_session); - bleg_channel = switch_core_session_get_channel(bleg_session); - bleg_tech_pvt = switch_core_session_get_private(bleg_session); - - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG1, "Deciding whether to pass zrtp-hash between a-leg and b-leg\n"); - if (!(switch_channel_test_flag(aleg_tech_pvt->channel, CF_ZRTP_PASSTHRU_REQ))) { - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG1, "CF_ZRTP_PASSTHRU_REQ not set on a-leg, so not propagating zrtp-hash\n"); - return; - } - if (aleg_tech_pvt->remote_sdp_audio_zrtp_hash) { - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG, "Passing a-leg remote zrtp-hash (audio) to b-leg\n"); - bleg_tech_pvt->local_sdp_audio_zrtp_hash = switch_core_session_strdup(bleg_tech_pvt->session, aleg_tech_pvt->remote_sdp_audio_zrtp_hash); - switch_channel_set_variable(bleg_channel, "l_sdp_audio_zrtp_hash", bleg_tech_pvt->local_sdp_audio_zrtp_hash); - } - if (aleg_tech_pvt->remote_sdp_video_zrtp_hash) { - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG, "Passing a-leg remote zrtp-hash (video) to b-leg\n"); - bleg_tech_pvt->local_sdp_video_zrtp_hash = switch_core_session_strdup(bleg_tech_pvt->session, aleg_tech_pvt->remote_sdp_video_zrtp_hash); - switch_channel_set_variable(bleg_channel, "l_sdp_video_zrtp_hash", bleg_tech_pvt->local_sdp_video_zrtp_hash); - } - if (bleg_tech_pvt->remote_sdp_audio_zrtp_hash) { - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG, "Passing b-leg remote zrtp-hash (audio) to a-leg\n"); - aleg_tech_pvt->local_sdp_audio_zrtp_hash = switch_core_session_strdup(aleg_tech_pvt->session, bleg_tech_pvt->remote_sdp_audio_zrtp_hash); - switch_channel_set_variable(aleg_channel, "l_sdp_audio_zrtp_hash", aleg_tech_pvt->local_sdp_audio_zrtp_hash); - } - if (bleg_tech_pvt->remote_sdp_video_zrtp_hash) { - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_channel), SWITCH_LOG_DEBUG, "Passing b-leg remote zrtp-hash (video) to a-leg\n"); - aleg_tech_pvt->local_sdp_video_zrtp_hash = switch_core_session_strdup(aleg_tech_pvt->session, bleg_tech_pvt->remote_sdp_video_zrtp_hash); - switch_channel_set_variable(aleg_channel, "l_sdp_video_zrtp_hash", aleg_tech_pvt->local_sdp_video_zrtp_hash); - } -} - -void sofia_glue_pass_zrtp_hash(switch_core_session_t *session) -{ - switch_channel_t *channel = switch_core_session_get_channel(session); - private_object_t *tech_pvt = switch_core_session_get_private(session); - switch_core_session_t *other_session; - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Deciding whether to pass zrtp-hash between legs\n"); - if (!(switch_channel_test_flag(tech_pvt->channel, CF_ZRTP_PASSTHRU_REQ))) { - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "CF_ZRTP_PASSTHRU_REQ not set, so not propagating zrtp-hash\n"); - return; - } else if (!(switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS)) { - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "No partner channel found, so not propagating zrtp-hash\n"); - return; - } else { - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Found peer channel; propagating zrtp-hash if set\n"); - sofia_glue_pass_zrtp_hash2(session, other_session); - switch_core_session_rwunlock(other_session); - } -} - -void find_zrtp_hash(switch_core_session_t *session, sdp_session_t *sdp) -{ - switch_channel_t *channel = switch_core_session_get_channel(session); - private_object_t *tech_pvt = switch_core_session_get_private(session); - sdp_media_t *m; - sdp_attribute_t *attr; - int got_audio = 0, got_video = 0; - - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Looking for zrtp-hash\n"); - for (m = sdp->sdp_media; m; m = m->m_next) { - if (got_audio && got_video) break; - if (m->m_port && ((m->m_type == sdp_media_audio && !got_audio) - || (m->m_type == sdp_media_video && !got_video))) { - for (attr = m->m_attributes; attr; attr = attr->a_next) { - if (zstr(attr->a_name)) continue; - if (strcasecmp(attr->a_name, "zrtp-hash") || !(attr->a_value)) continue; - if (m->m_type == sdp_media_audio) { - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, - "Found audio zrtp-hash; setting r_sdp_audio_zrtp_hash=%s\n", attr->a_value); - switch_channel_set_variable(channel, "r_sdp_audio_zrtp_hash", attr->a_value); - tech_pvt->remote_sdp_audio_zrtp_hash = switch_core_session_strdup(tech_pvt->session, attr->a_value); - got_audio++; - } else if (m->m_type == sdp_media_video) { - switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, - "Found video zrtp-hash; setting r_sdp_video_zrtp_hash=%s\n", attr->a_value); - switch_channel_set_variable(channel, "r_sdp_video_zrtp_hash", attr->a_value); - tech_pvt->remote_sdp_video_zrtp_hash = switch_core_session_strdup(tech_pvt->session, attr->a_value); - got_video++; - } - switch_channel_set_flag(channel, CF_ZRTP_HASH); - break; - } - } - } -} - /* map sip responses to QSIG cause codes ala RFC4497 section 8.4.4 */ switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status) { @@ -2548,7 +2449,7 @@ int sofia_recover_callback(switch_core_session_t *session) r_ip = switch_channel_get_variable(channel, SWITCH_REMOTE_VIDEO_IP_VARIABLE); r_port = switch_channel_get_variable(channel, SWITCH_REMOTE_VIDEO_PORT_VARIABLE); - sofia_set_flag(tech_pvt, TFLAG_VIDEO); + switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_POSSIBLE); if ((tmp = switch_channel_get_variable(channel, "sip_use_video_codec_rate"))) { tech_pvt->video_rm_rate = atoi(tmp); @@ -3476,102 +3377,6 @@ void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const } -void sofia_glue_parse_rtp_bugs(switch_rtp_bug_flag_t *flag_pole, const char *str) -{ - - if (switch_stristr("clear", str)) { - *flag_pole = 0; - } - - if (switch_stristr("CISCO_SKIP_MARK_BIT_2833", str)) { - *flag_pole |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833; - } - - if (switch_stristr("~CISCO_SKIP_MARK_BIT_2833", str)) { - *flag_pole &= ~RTP_BUG_CISCO_SKIP_MARK_BIT_2833; - } - - if (switch_stristr("SONUS_SEND_INVALID_TIMESTAMP_2833", str)) { - *flag_pole |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833; - } - - if (switch_stristr("~SONUS_SEND_INVALID_TIMESTAMP_2833", str)) { - *flag_pole &= ~RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833; - } - - if (switch_stristr("IGNORE_MARK_BIT", str)) { - *flag_pole |= RTP_BUG_IGNORE_MARK_BIT; - } - - if (switch_stristr("~IGNORE_MARK_BIT", str)) { - *flag_pole &= ~RTP_BUG_IGNORE_MARK_BIT; - } - - if (switch_stristr("SEND_LINEAR_TIMESTAMPS", str)) { - *flag_pole |= RTP_BUG_SEND_LINEAR_TIMESTAMPS; - } - - if (switch_stristr("~SEND_LINEAR_TIMESTAMPS", str)) { - *flag_pole &= ~RTP_BUG_SEND_LINEAR_TIMESTAMPS; - } - - if (switch_stristr("START_SEQ_AT_ZERO", str)) { - *flag_pole |= RTP_BUG_START_SEQ_AT_ZERO; - } - - if (switch_stristr("~START_SEQ_AT_ZERO", str)) { - *flag_pole &= ~RTP_BUG_START_SEQ_AT_ZERO; - } - - if (switch_stristr("NEVER_SEND_MARKER", str)) { - *flag_pole |= RTP_BUG_NEVER_SEND_MARKER; - } - - if (switch_stristr("~NEVER_SEND_MARKER", str)) { - *flag_pole &= ~RTP_BUG_NEVER_SEND_MARKER; - } - - if (switch_stristr("IGNORE_DTMF_DURATION", str)) { - *flag_pole |= RTP_BUG_IGNORE_DTMF_DURATION; - } - - if (switch_stristr("~IGNORE_DTMF_DURATION", str)) { - *flag_pole &= ~RTP_BUG_IGNORE_DTMF_DURATION; - } - - if (switch_stristr("ACCEPT_ANY_PACKETS", str)) { - *flag_pole |= RTP_BUG_ACCEPT_ANY_PACKETS; - } - - if (switch_stristr("~ACCEPT_ANY_PACKETS", str)) { - *flag_pole &= ~RTP_BUG_ACCEPT_ANY_PACKETS; - } - - if (switch_stristr("GEN_ONE_GEN_ALL", str)) { - *flag_pole |= RTP_BUG_GEN_ONE_GEN_ALL; - } - - if (switch_stristr("~GEN_ONE_GEN_ALL", str)) { - *flag_pole &= ~RTP_BUG_GEN_ONE_GEN_ALL; - } - - if (switch_stristr("CHANGE_SSRC_ON_MARKER", str)) { - *flag_pole |= RTP_BUG_CHANGE_SSRC_ON_MARKER; - } - - if (switch_stristr("~CHANGE_SSRC_ON_MARKER", str)) { - *flag_pole &= ~RTP_BUG_CHANGE_SSRC_ON_MARKER; - } - - if (switch_stristr("FLUSH_JB_ON_DTMF", str)) { - *flag_pole |= RTP_BUG_FLUSH_JB_ON_DTMF; - } - - if (switch_stristr("~FLUSH_JB_ON_DTMF", str)) { - *flag_pole &= ~RTP_BUG_FLUSH_JB_ON_DTMF; - } -} - char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, nua_handle_t *nh, sofia_dispatch_event_t *de, sofia_nat_parse_t *np) { char *contact_str = NULL; diff --git a/src/mod/endpoints/mod_sofia/sofia_media.c b/src/mod/endpoints/mod_sofia/sofia_media.c index c8618e1b6b..9176315211 100644 --- a/src/mod/endpoints/mod_sofia/sofia_media.c +++ b/src/mod/endpoints/mod_sofia/sofia_media.c @@ -32,22 +32,6 @@ #include "mod_sofia.h" -switch_status_t sofia_media_get_offered_pt(private_object_t *tech_pvt, const switch_codec_implementation_t *mimp, switch_payload_t *pt) -{ - int i = 0; - - for (i = 0; i < tech_pvt->num_codecs; i++) { - const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; - - if (!strcasecmp(imp->iananame, mimp->iananame)) { - *pt = tech_pvt->ianacodes[i]; - - return SWITCH_STATUS_SUCCESS; - } - } - - return SWITCH_STATUS_FALSE; -} void sofia_media_tech_absorb_sdp(private_object_t *tech_pvt) @@ -211,107 +195,25 @@ void sofia_media_proxy_codec(switch_core_session_t *session, const char *r_sdp) } -switch_t38_options_t *tech_process_udptl(private_object_t *tech_pvt, sdp_session_t *sdp, sdp_media_t *m) +uint8_t sofia_media_negotiate_sdp(switch_core_session_t *session, const char *r_sdp) { - switch_t38_options_t *t38_options = switch_channel_get_private(tech_pvt->channel, "t38_options"); - sdp_attribute_t *attr; - - if (!t38_options) { - t38_options = switch_core_session_alloc(tech_pvt->session, sizeof(switch_t38_options_t)); - - // set some default value - t38_options->T38FaxVersion = 0; - t38_options->T38MaxBitRate = 14400; - t38_options->T38FaxRateManagement = switch_core_session_strdup(tech_pvt->session, "transferredTCF"); - t38_options->T38FaxUdpEC = switch_core_session_strdup(tech_pvt->session, "t38UDPRedundancy"); - t38_options->T38FaxMaxBuffer = 500; - t38_options->T38FaxMaxDatagram = 500; - } - - t38_options->remote_port = (switch_port_t)m->m_port; - - if (sdp->sdp_origin) { - t38_options->sdp_o_line = switch_core_session_strdup(tech_pvt->session, sdp->sdp_origin->o_username); - } else { - t38_options->sdp_o_line = "unknown"; - } - - if (m->m_connections && m->m_connections->c_address) { - t38_options->remote_ip = switch_core_session_strdup(tech_pvt->session, m->m_connections->c_address); - } else if (sdp && sdp->sdp_connection && sdp->sdp_connection->c_address) { - t38_options->remote_ip = switch_core_session_strdup(tech_pvt->session, sdp->sdp_connection->c_address); - } - - for (attr = m->m_attributes; attr; attr = attr->a_next) { - if (!strcasecmp(attr->a_name, "T38FaxVersion") && attr->a_value) { - t38_options->T38FaxVersion = (uint16_t) atoi(attr->a_value); - } else if (!strcasecmp(attr->a_name, "T38MaxBitRate") && attr->a_value) { - t38_options->T38MaxBitRate = (uint32_t) atoi(attr->a_value); - } else if (!strcasecmp(attr->a_name, "T38FaxFillBitRemoval")) { - t38_options->T38FaxFillBitRemoval = switch_safe_atoi(attr->a_value, 1); - } else if (!strcasecmp(attr->a_name, "T38FaxTranscodingMMR")) { - t38_options->T38FaxTranscodingMMR = switch_safe_atoi(attr->a_value, 1); - } else if (!strcasecmp(attr->a_name, "T38FaxTranscodingJBIG")) { - t38_options->T38FaxTranscodingJBIG = switch_safe_atoi(attr->a_value, 1); - } else if (!strcasecmp(attr->a_name, "T38FaxRateManagement") && attr->a_value) { - t38_options->T38FaxRateManagement = switch_core_session_strdup(tech_pvt->session, attr->a_value); - } else if (!strcasecmp(attr->a_name, "T38FaxMaxBuffer") && attr->a_value) { - t38_options->T38FaxMaxBuffer = (uint32_t) atoi(attr->a_value); - } else if (!strcasecmp(attr->a_name, "T38FaxMaxDatagram") && attr->a_value) { - t38_options->T38FaxMaxDatagram = (uint32_t) atoi(attr->a_value); - } else if (!strcasecmp(attr->a_name, "T38FaxUdpEC") && attr->a_value) { - t38_options->T38FaxUdpEC = switch_core_session_strdup(tech_pvt->session, attr->a_value); - } else if (!strcasecmp(attr->a_name, "T38VendorInfo") && attr->a_value) { - t38_options->T38VendorInfo = switch_core_session_strdup(tech_pvt->session, attr->a_value); - } - } - - switch_channel_set_variable(tech_pvt->channel, "has_t38", "true"); - switch_channel_set_private(tech_pvt->channel, "t38_options", t38_options); - switch_channel_set_app_flag_key("T38", tech_pvt->channel, CF_APP_T38); - - switch_channel_execute_on(tech_pvt->channel, "sip_execute_on_image"); - switch_channel_api_on(tech_pvt->channel, "sip_api_on_image"); - - return t38_options; -} - - - - -switch_t38_options_t *sofia_media_extract_t38_options(switch_core_session_t *session, const char *r_sdp) -{ - sdp_media_t *m; - sdp_parser_t *parser = NULL; - sdp_session_t *sdp; + uint8_t t, p = 0; private_object_t *tech_pvt = switch_core_session_get_private(session); - switch_t38_options_t *t38_options = NULL; - if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) { - return 0; + if ((t = switch_core_media_negotiate_sdp(session, r_sdp, &p, sofia_test_flag(tech_pvt, TFLAG_REINVITE), + tech_pvt->profile->codec_flags, tech_pvt->profile->te))) { + sofia_set_flag_locked(tech_pvt, TFLAG_SDP); } - if (!(sdp = sdp_session(parser))) { - sdp_parser_free(parser); - return 0; + if (!p) { + sofia_set_flag(tech_pvt, TFLAG_NOREPLY); } - switch_assert(tech_pvt != NULL); - - for (m = sdp->sdp_media; m; m = m->m_next) { - if (m->m_proto == sdp_proto_udptl && m->m_type == sdp_media_image && m->m_port) { - t38_options = tech_process_udptl(tech_pvt, sdp, m); - break; - } - } - - sdp_parser_free(parser); - - return t38_options; - + return t; } +#if 0 uint8_t sofia_media_negotiate_sdp(switch_core_session_t *session, const char *r_sdp) { uint8_t match = 0; @@ -350,8 +252,8 @@ uint8_t sofia_media_negotiate_sdp(switch_core_session_t *session, const char *r_ switch_assert(tech_pvt != NULL); - greedy = !!sofia_test_pflag(tech_pvt->profile, PFLAG_GREEDY); - scrooge = !!sofia_test_pflag(tech_pvt->profile, PFLAG_SCROOGE); + greedy = !!sofia_test_media_flag(tech_pvt->profile, SCMF_CODEC_GREEDY); + scrooge = !!sofia_test_media_flag(tech_pvt->profile, SCMF_CODEC_SCROOGE); if ((val = switch_channel_get_variable(channel, "sip_codec_negotiation"))) { if (!strcasecmp(val, "generous")) { @@ -440,7 +342,7 @@ uint8_t sofia_media_negotiate_sdp(switch_core_session_t *session, const char *r_ } - if (sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_HOLD) || + if (sofia_test_media_flag(tech_pvt->profile, SCMF_DISABLE_HOLD) || ((val = switch_channel_get_variable(tech_pvt->channel, "sip_disable_hold")) && switch_true(val))) { sendonly = 0; } else { @@ -481,8 +383,8 @@ uint8_t sofia_media_negotiate_sdp(switch_core_session_t *session, const char *r_ switch_channel_set_variable(tech_pvt->channel, "t38_broken_boolean", "true"); } - find_zrtp_hash(session, sdp); - sofia_glue_pass_zrtp_hash(session); + switch_core_media_find_zrtp_hash(session, sdp); + switch_core_media_pass_zrtp_hash(session); for (m = sdp->sdp_media; m; m = m->m_next) { sdp_connection_t *connection; @@ -508,7 +410,7 @@ uint8_t sofia_media_negotiate_sdp(switch_core_session_t *session, const char *r_ } if (got_udptl && m->m_type == sdp_media_image && m->m_port) { - switch_t38_options_t *t38_options = tech_process_udptl(tech_pvt, sdp, m); + switch_t38_options_t *t38_options = switch_core_media_process_udptl(tech_pvt->session, sdp, m); if (switch_channel_test_app_flag_key("T38", tech_pvt->channel, CF_APP_T38_NEGOTIATED)) { match = 1; @@ -1064,7 +966,7 @@ uint8_t sofia_media_negotiate_sdp(switch_core_session_t *session, const char *r_ return match; } - +#endif switch_status_t sofia_media_activate_rtp(private_object_t *tech_pvt) { @@ -1103,7 +1005,7 @@ switch_status_t sofia_media_activate_rtp(private_object_t *tech_pvt) if (!sofia_test_flag(tech_pvt, TFLAG_REINVITE)) { if (switch_rtp_ready(tech_pvt->rtp_session)) { - if (sofia_test_flag(tech_pvt, TFLAG_VIDEO) && !switch_rtp_ready(tech_pvt->video_rtp_session)) { + if (switch_channel_test_flag(tech_pvt->channel, CF_VIDEO_POSSIBLE) && !switch_rtp_ready(tech_pvt->video_rtp_session)) { goto video; } @@ -1347,7 +1249,7 @@ switch_status_t sofia_media_activate_rtp(private_object_t *tech_pvt) } if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_manual_rtp_bugs"))) { - sofia_glue_parse_rtp_bugs(&tech_pvt->rtp_bugs, val); + switch_core_media_parse_rtp_bugs(&tech_pvt->rtp_bugs, val); } switch_rtp_intentional_bugs(tech_pvt->rtp_session, tech_pvt->rtp_bugs | tech_pvt->profile->manual_rtp_bugs); @@ -1526,7 +1428,7 @@ switch_status_t sofia_media_activate_rtp(private_object_t *tech_pvt) sofia_media_check_video_codecs(tech_pvt); - if (sofia_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding && tech_pvt->remote_sdp_video_port) { + if (switch_channel_test_flag(tech_pvt->channel, CF_VIDEO_POSSIBLE) && tech_pvt->video_rm_encoding && tech_pvt->remote_sdp_video_port) { /******************************************************************************************/ 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); @@ -1684,7 +1586,7 @@ switch_status_t sofia_media_activate_rtp(private_object_t *tech_pvt) if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_manual_video_rtp_bugs"))) { - sofia_glue_parse_rtp_bugs(&tech_pvt->video_rtp_bugs, val); + switch_core_media_parse_rtp_bugs(&tech_pvt->video_rtp_bugs, val); } switch_rtp_intentional_bugs(tech_pvt->video_rtp_session, tech_pvt->video_rtp_bugs | tech_pvt->profile->manual_video_rtp_bugs); @@ -1776,237 +1678,6 @@ void sofia_media_set_sdp_codec_string(switch_core_session_t *session, const char } -switch_status_t sofia_media_tech_set_video_codec(private_object_t *tech_pvt, int force) -{ - - if (!tech_pvt->video_rm_encoding) { - return SWITCH_STATUS_FALSE; - } - - if (tech_pvt->video_read_codec.implementation && switch_core_codec_ready(&tech_pvt->video_read_codec)) { - if (!force) { - return SWITCH_STATUS_SUCCESS; - } - if (strcasecmp(tech_pvt->video_read_codec.implementation->iananame, tech_pvt->video_rm_encoding) || - tech_pvt->video_read_codec.implementation->samples_per_second != tech_pvt->video_rm_rate) { - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Changing Codec from %s to %s\n", - tech_pvt->video_read_codec.implementation->iananame, tech_pvt->video_rm_encoding); - switch_core_codec_destroy(&tech_pvt->video_read_codec); - switch_core_codec_destroy(&tech_pvt->video_write_codec); - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Already using %s\n", - tech_pvt->video_read_codec.implementation->iananame); - return SWITCH_STATUS_SUCCESS; - } - } - - - - if (switch_core_codec_init(&tech_pvt->video_read_codec, - tech_pvt->video_rm_encoding, - tech_pvt->video_rm_fmtp, - tech_pvt->video_rm_rate, - 0, - 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, - NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); - return SWITCH_STATUS_FALSE; - } else { - if (switch_core_codec_init(&tech_pvt->video_write_codec, - tech_pvt->video_rm_encoding, - tech_pvt->video_rm_fmtp, - tech_pvt->video_rm_rate, - 0, - 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, - NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); - return SWITCH_STATUS_FALSE; - } else { - tech_pvt->video_read_frame.rate = tech_pvt->video_rm_rate; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set VIDEO Codec %s %s/%ld %d ms\n", - switch_channel_get_name(tech_pvt->channel), tech_pvt->video_rm_encoding, tech_pvt->video_rm_rate, tech_pvt->video_codec_ms); - tech_pvt->video_read_frame.codec = &tech_pvt->video_read_codec; - - tech_pvt->video_fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->video_write_codec.fmtp_out); - - tech_pvt->video_write_codec.agreed_pt = tech_pvt->video_agreed_pt; - tech_pvt->video_read_codec.agreed_pt = tech_pvt->video_agreed_pt; - switch_core_session_set_video_read_codec(tech_pvt->session, &tech_pvt->video_read_codec); - switch_core_session_set_video_write_codec(tech_pvt->session, &tech_pvt->video_write_codec); - - - if (switch_rtp_ready(tech_pvt->video_rtp_session)) { - switch_core_session_message_t msg = { 0 }; - - msg.from = __FILE__; - msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ; - - switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt); - - if (tech_pvt->video_recv_pt != tech_pvt->video_agreed_pt) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, - "%s Set video receive payload to %u\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->video_recv_pt); - - switch_rtp_set_recv_pt(tech_pvt->video_rtp_session, tech_pvt->video_recv_pt); - } else { - switch_rtp_set_recv_pt(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt); - } - - switch_core_session_receive_message(tech_pvt->session, &msg); - - - } - - switch_channel_set_variable(tech_pvt->channel, "sip_use_video_codec_name", tech_pvt->video_rm_encoding); - switch_channel_set_variable(tech_pvt->channel, "sip_use_video_codec_fmtp", tech_pvt->video_rm_fmtp); - switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_video_codec_rate", "%d", tech_pvt->video_rm_rate); - switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_video_codec_ptime", "%d", 0); - - } - } - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t sofia_media_tech_set_codec(private_object_t *tech_pvt, int force) -{ - switch_status_t status = SWITCH_STATUS_SUCCESS; - int resetting = 0; - - if (!tech_pvt->iananame) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "No audio codec available\n"); - switch_goto_status(SWITCH_STATUS_FALSE, end); - } - - if (switch_core_codec_ready(&tech_pvt->read_codec)) { - if (!force) { - switch_goto_status(SWITCH_STATUS_SUCCESS, end); - } - if (strcasecmp(tech_pvt->read_impl.iananame, tech_pvt->iananame) || - tech_pvt->read_impl.samples_per_second != tech_pvt->rm_rate || - tech_pvt->codec_ms != (uint32_t) tech_pvt->read_impl.microseconds_per_packet / 1000) { - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, - "Changing Codec from %s@%dms@%dhz to %s@%dms@%luhz\n", - tech_pvt->read_impl.iananame, tech_pvt->read_impl.microseconds_per_packet / 1000, - tech_pvt->read_impl.samples_per_second, - tech_pvt->rm_encoding, - tech_pvt->codec_ms, - tech_pvt->rm_rate); - - switch_yield(tech_pvt->read_impl.microseconds_per_packet); - switch_core_session_lock_codec_write(tech_pvt->session); - switch_core_session_lock_codec_read(tech_pvt->session); - resetting = 1; - switch_yield(tech_pvt->read_impl.microseconds_per_packet); - switch_core_codec_destroy(&tech_pvt->read_codec); - switch_core_codec_destroy(&tech_pvt->write_codec); - switch_channel_audio_sync(tech_pvt->channel); - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Already using %s\n", tech_pvt->read_impl.iananame); - switch_goto_status(SWITCH_STATUS_SUCCESS, end); - } - } - - if (switch_core_codec_init_with_bitrate(&tech_pvt->read_codec, - tech_pvt->iananame, - tech_pvt->rm_fmtp, - tech_pvt->rm_rate, - tech_pvt->codec_ms, - 1, - tech_pvt->bitrate, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags, - NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); - switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); - switch_goto_status(SWITCH_STATUS_FALSE, end); - } - - tech_pvt->read_codec.session = tech_pvt->session; - - - if (switch_core_codec_init_with_bitrate(&tech_pvt->write_codec, - tech_pvt->iananame, - tech_pvt->rm_fmtp, - tech_pvt->rm_rate, - tech_pvt->codec_ms, - 1, - tech_pvt->bitrate, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags, - NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); - switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); - switch_goto_status(SWITCH_STATUS_FALSE, end); - } - - tech_pvt->write_codec.session = tech_pvt->session; - - switch_channel_set_variable(tech_pvt->channel, "sip_use_codec_name", tech_pvt->iananame); - switch_channel_set_variable(tech_pvt->channel, "sip_use_codec_fmtp", tech_pvt->rm_fmtp); - switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_codec_rate", "%d", tech_pvt->rm_rate); - switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_codec_ptime", "%d", tech_pvt->codec_ms); - - - switch_assert(tech_pvt->read_codec.implementation); - switch_assert(tech_pvt->write_codec.implementation); - - tech_pvt->read_impl = *tech_pvt->read_codec.implementation; - tech_pvt->write_impl = *tech_pvt->write_codec.implementation; - - switch_core_session_set_read_impl(tech_pvt->session, tech_pvt->read_codec.implementation); - switch_core_session_set_write_impl(tech_pvt->session, tech_pvt->write_codec.implementation); - - if (switch_rtp_ready(tech_pvt->rtp_session)) { - switch_assert(tech_pvt->read_codec.implementation); - - if (switch_rtp_change_interval(tech_pvt->rtp_session, - tech_pvt->read_impl.microseconds_per_packet, - tech_pvt->read_impl.samples_per_packet) != SWITCH_STATUS_SUCCESS) { - switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - switch_goto_status(SWITCH_STATUS_FALSE, end); - } - } - - tech_pvt->read_frame.rate = tech_pvt->rm_rate; - - if (!switch_core_codec_ready(&tech_pvt->read_codec)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n"); - switch_goto_status(SWITCH_STATUS_FALSE, end); - } - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Codec %s %s/%ld %d ms %d samples %d bits\n", - switch_channel_get_name(tech_pvt->channel), tech_pvt->iananame, tech_pvt->rm_rate, tech_pvt->codec_ms, - tech_pvt->read_impl.samples_per_packet, tech_pvt->read_impl.bits_per_second); - tech_pvt->read_frame.codec = &tech_pvt->read_codec; - - tech_pvt->write_codec.agreed_pt = tech_pvt->agreed_pt; - tech_pvt->read_codec.agreed_pt = tech_pvt->agreed_pt; - - if (force != 2) { - switch_core_session_set_real_read_codec(tech_pvt->session, &tech_pvt->read_codec); - switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec); - } - - tech_pvt->fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->write_codec.fmtp_out); - - if (switch_rtp_ready(tech_pvt->rtp_session)) { - switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->pt); - } - - end: - if (resetting) { - switch_core_session_unlock_codec_write(tech_pvt->session); - switch_core_session_unlock_codec_read(tech_pvt->session); - } - - sofia_media_tech_set_video_codec(tech_pvt, force); - - return status; -} - - static void add_audio_codec(sdp_rtpmap_t *map, int ptime, char *buf, switch_size_t buflen) { @@ -2108,8 +1779,8 @@ void sofia_media_set_r_sdp_codec_string(switch_core_session_t *session, const ch } } - find_zrtp_hash(session, sdp); - sofia_glue_pass_zrtp_hash(session); + switch_core_media_find_zrtp_hash(session, sdp); + switch_core_media_pass_zrtp_hash(session); for (m = sdp->sdp_media; m; m = m->m_next) { ptime = dptime; @@ -2268,125 +1939,6 @@ switch_status_t sofia_media_tech_media(private_object_t *tech_pvt, const char *r return SWITCH_STATUS_FALSE; } -int sofia_media_toggle_hold(private_object_t *tech_pvt, int sendonly) -{ - int changed = 0; - - if (sofia_test_flag(tech_pvt, TFLAG_SLA_BARGE) || sofia_test_flag(tech_pvt, TFLAG_SLA_BARGING)) { - switch_channel_mark_hold(tech_pvt->channel, sendonly); - return 0; - } - - if (sendonly && switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED)) { - if (!sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { - const char *stream; - const char *msg = "hold"; - - if (sofia_test_pflag(tech_pvt->profile, PFLAG_MANAGE_SHARED_APPEARANCE)) { - const char *info = switch_channel_get_variable(tech_pvt->channel, "presence_call_info"); - if (info) { - if (switch_stristr("private", info)) { - msg = "hold-private"; - } - } - } - - sofia_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD); - switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE); - switch_channel_presence(tech_pvt->channel, "unknown", msg, NULL); - changed = 1; - - if (tech_pvt->max_missed_hold_packets) { - switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_hold_packets); - } - - if (!(stream = switch_channel_get_hold_music(tech_pvt->channel))) { - stream = tech_pvt->profile->hold_music; - } - - if (stream && strcasecmp(stream, "silence")) { - if (!strcasecmp(stream, "indicate_hold")) { - switch_channel_set_flag(tech_pvt->channel, CF_SUSPEND); - switch_channel_set_flag(tech_pvt->channel, CF_HOLD); - switch_ivr_hold_uuid(switch_channel_get_partner_uuid(tech_pvt->channel), NULL, 0); - } else { - switch_ivr_broadcast(switch_channel_get_partner_uuid(tech_pvt->channel), stream, - SMF_ECHO_ALEG | SMF_LOOP | SMF_PRIORITY); - switch_yield(250000); - } - } - } - } else { - if (sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) { - sofia_set_flag(tech_pvt, TFLAG_SIP_HOLD); - switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE); - changed = 1; - } - - sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK); - - if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { - const char *uuid; - switch_core_session_t *b_session; - - switch_yield(250000); - - if (tech_pvt->max_missed_packets) { - switch_rtp_reset_media_timer(tech_pvt->rtp_session); - switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets); - } - - if ((uuid = switch_channel_get_partner_uuid(tech_pvt->channel)) && (b_session = switch_core_session_locate(uuid))) { - switch_channel_t *b_channel = switch_core_session_get_channel(b_session); - - if (switch_channel_test_flag(tech_pvt->channel, CF_HOLD)) { - switch_ivr_unhold(b_session); - switch_channel_clear_flag(tech_pvt->channel, CF_SUSPEND); - switch_channel_clear_flag(tech_pvt->channel, CF_HOLD); - } else { - switch_channel_stop_broadcast(b_channel); - switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL); - } - switch_core_session_rwunlock(b_session); - } - - sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); - switch_channel_mark_hold(tech_pvt->channel, SWITCH_FALSE); - switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL); - changed = 1; - } - } - - return changed; -} - -void sofia_media_copy_t38_options(switch_t38_options_t *t38_options, switch_core_session_t *session) -{ - switch_channel_t *channel = switch_core_session_get_channel(session); - switch_t38_options_t *local_t38_options = switch_channel_get_private(channel, "t38_options"); - - switch_assert(t38_options); - - if (!local_t38_options) { - local_t38_options = switch_core_session_alloc(session, sizeof(switch_t38_options_t)); - } - - local_t38_options->T38MaxBitRate = t38_options->T38MaxBitRate; - local_t38_options->T38FaxFillBitRemoval = t38_options->T38FaxFillBitRemoval; - local_t38_options->T38FaxTranscodingMMR = t38_options->T38FaxTranscodingMMR; - local_t38_options->T38FaxTranscodingJBIG = t38_options->T38FaxTranscodingJBIG; - local_t38_options->T38FaxRateManagement = switch_core_session_strdup(session, t38_options->T38FaxRateManagement); - local_t38_options->T38FaxMaxBuffer = t38_options->T38FaxMaxBuffer; - local_t38_options->T38FaxMaxDatagram = t38_options->T38FaxMaxDatagram; - local_t38_options->T38FaxUdpEC = switch_core_session_strdup(session, t38_options->T38FaxUdpEC); - local_t38_options->T38VendorInfo = switch_core_session_strdup(session, t38_options->T38VendorInfo); - local_t38_options->remote_ip = switch_core_session_strdup(session, t38_options->remote_ip); - local_t38_options->remote_port = t38_options->remote_port; - - - switch_channel_set_private(channel, "t38_options", local_t38_options); - -} static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen, switch_port_t port, @@ -2397,7 +1949,7 @@ static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen, int already_did[128] = { 0 }; int ptime = 0, noptime = 0; const char *local_audio_crypto_key = switch_core_session_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO); - + const char *local_sdp_audio_zrtp_hash; switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "m=audio %d RTP/%sAVP", port, secure ? "S" : ""); @@ -2529,8 +2081,8 @@ static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen, } - if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF)) - && tech_pvt->te > 95) { + if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || + switch_channel_test_flag(tech_pvt->channel, CF_LIBERAL_DTMF)) && tech_pvt->te > 95) { switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n", tech_pvt->te, tech_pvt->te); } @@ -2557,11 +2109,11 @@ static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen, switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=ptime:%d\n", cur_ptime); } - if (tech_pvt->local_sdp_audio_zrtp_hash) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Adding audio a=zrtp-hash:%s\n", - tech_pvt->local_sdp_audio_zrtp_hash); - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=zrtp-hash:%s\n", - tech_pvt->local_sdp_audio_zrtp_hash); + local_sdp_audio_zrtp_hash = switch_core_media_get_zrtp_hash(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, SWITCH_TRUE); + + if (local_sdp_audio_zrtp_hash) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Adding audio a=zrtp-hash:%s\n", local_sdp_audio_zrtp_hash); + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=zrtp-hash:%s\n", local_sdp_audio_zrtp_hash); } if (!zstr(sr)) { @@ -2592,6 +2144,8 @@ void sofia_media_set_local_sdp(private_object_t *tech_pvt, const char *ip, switc const char *b_sdp = NULL; int verbose_sdp = 0; const char *local_audio_crypto_key = switch_core_session_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO); + const char *local_sdp_audio_zrtp_hash = switch_core_media_get_zrtp_hash(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, SWITCH_TRUE); + const char *local_sdp_video_zrtp_hash = switch_core_media_get_zrtp_hash(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO, SWITCH_TRUE); switch_zmalloc(buf, SDPBUFLEN); @@ -2714,7 +2268,8 @@ void sofia_media_set_local_sdp(private_object_t *tech_pvt, const char *ip, switc switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", tech_pvt->pt); - if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF)) && tech_pvt->te > 95) { + if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || + switch_channel_test_flag(tech_pvt->channel, CF_LIBERAL_DTMF)) && tech_pvt->te > 95) { switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", tech_pvt->te); } @@ -2735,7 +2290,8 @@ void sofia_media_set_local_sdp(private_object_t *tech_pvt, const char *ip, switc } - if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || sofia_test_flag(tech_pvt, TFLAG_LIBERAL_DTMF)) + if ((tech_pvt->dtmf_type == DTMF_2833 || sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || + switch_channel_test_flag(tech_pvt->channel, CF_LIBERAL_DTMF)) && tech_pvt->te > 95) { switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n", tech_pvt->te, tech_pvt->te); } @@ -2757,11 +2313,11 @@ void sofia_media_set_local_sdp(private_object_t *tech_pvt, const char *ip, switc } - if (tech_pvt->local_sdp_audio_zrtp_hash) { + if (local_sdp_audio_zrtp_hash) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Adding audio a=zrtp-hash:%s\n", - tech_pvt->local_sdp_audio_zrtp_hash); + local_sdp_audio_zrtp_hash); switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=zrtp-hash:%s\n", - tech_pvt->local_sdp_audio_zrtp_hash); + local_sdp_audio_zrtp_hash); } if (!zstr(sr)) { @@ -2848,7 +2404,7 @@ void sofia_media_set_local_sdp(private_object_t *tech_pvt, const char *ip, switc } - if (sofia_test_flag(tech_pvt, TFLAG_VIDEO)) { + if (switch_channel_test_flag(tech_pvt->channel, CF_VIDEO_POSSIBLE)) { const char *local_video_crypto_key = switch_core_session_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO); if (!tech_pvt->local_sdp_video_port) { @@ -2974,11 +2530,10 @@ void sofia_media_set_local_sdp(private_object_t *tech_pvt, const char *ip, switc } - if (tech_pvt->local_sdp_video_zrtp_hash) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Adding video a=zrtp-hash:%s\n", - tech_pvt->local_sdp_video_zrtp_hash); - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=zrtp-hash:%s\n", - tech_pvt->local_sdp_video_zrtp_hash); + + if (local_sdp_video_zrtp_hash) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Adding video a=zrtp-hash:%s\n", local_sdp_video_zrtp_hash); + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=zrtp-hash:%s\n", local_sdp_video_zrtp_hash); } } } @@ -3060,24 +2615,6 @@ void sofia_media_tech_prepare_codecs(private_object_t *tech_pvt) } -void sofia_media_check_video_codecs(private_object_t *tech_pvt) -{ - if (tech_pvt->num_codecs && !sofia_test_flag(tech_pvt, TFLAG_VIDEO)) { - int i; - tech_pvt->video_count = 0; - for (i = 0; i < tech_pvt->num_codecs; i++) { - - if (tech_pvt->codecs[i]->codec_type == SWITCH_CODEC_TYPE_VIDEO) { - tech_pvt->video_count++; - } - } - if (tech_pvt->video_count) { - sofia_set_flag_locked(tech_pvt, TFLAG_VIDEO); - } - } -} - - void sofia_media_tech_patch_sdp(private_object_t *tech_pvt) { switch_size_t len; @@ -3256,7 +2793,7 @@ void sofia_media_tech_patch_sdp(private_object_t *tech_pvt) tech_pvt->video_codec_ms = 0; switch_snprintf(vport_buf, sizeof(vport_buf), "%u", tech_pvt->adv_sdp_video_port); if (switch_channel_media_ready(tech_pvt->channel) && !switch_rtp_ready(tech_pvt->video_rtp_session)) { - sofia_set_flag(tech_pvt, TFLAG_VIDEO); + switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_POSSIBLE); sofia_set_flag(tech_pvt, TFLAG_REINVITE); sofia_media_activate_rtp(tech_pvt); } diff --git a/src/switch_core_media.c b/src/switch_core_media.c index dff04bb2af..18c93e19c5 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -30,7 +30,6 @@ */ - #include #include #include @@ -40,6 +39,11 @@ #include #include + + +#define MAX_CODEC_CHECK_FRAMES 50//x:mod_sofia.h +#define MAX_MISMATCH_FRAMES 5//x:mod_sofia.h + typedef union { int32_t intval; uint32_t uintval; @@ -50,7 +54,8 @@ typedef union { static scm_type_t typemap[SCM_MAX] = { /*SCM_INBOUND_CODEC_STRING*/ STYPE_CHARVAL, /*SCM_OUTBOUND_CODEC_STRING*/ STYPE_CHARVAL, - /*SCM_TEST*/ STYPE_INTVAL + /*SCM_AUTO_RTP_BUGS */ STYPE_INTVAL, + /*SCM_MANUAL_RTP_BUGS*/ STYPE_INTVAL }; typedef enum { @@ -70,11 +75,53 @@ typedef struct secure_settings_s { char *remote_crypto_key; } switch_secure_settings_t; +typedef struct codec_params_s {//x:tmp + char *rm_encoding; + char *iananame; + switch_payload_t pt; + unsigned long rm_rate; + uint32_t codec_ms; + uint32_t bitrate; + char *remote_sdp_ip; + char *rm_fmtp; + switch_port_t remote_sdp_port; + switch_payload_t agreed_pt; + switch_payload_t recv_pt; + char *fmtp_out; +} codec_params_t; + + typedef struct switch_rtp_engine_s { switch_secure_settings_t ssec; - switch_rtp_t *rtp_session;//tp - switch_frame_t read_frame;//tp switch_media_type_t type; + + switch_rtp_t *rtp_session;//x:tp + switch_frame_t read_frame;//x:tp + switch_codec_t read_codec;//x:tp + switch_codec_t write_codec;//x:tp + + switch_codec_implementation_t read_impl;//x:tp + switch_codec_implementation_t write_impl;//x:tp + + uint32_t codec_ms;//x:tp + switch_size_t last_ts;//x:tp + uint32_t check_frames;//x:tp + uint32_t mismatch_count;//x:tp + uint32_t last_codec_ms;//x:tp + uint8_t codec_reinvites;//x:tp + uint32_t max_missed_packets;//x:tp + uint32_t max_missed_hold_packets;//x:tp + + + + /** ZRTP **/ + char *local_sdp_zrtp_hash; + char *remote_sdp_zrtp_hash; + + + codec_params_t codec_params; + + } switch_rtp_engine_t; @@ -82,15 +129,26 @@ struct switch_media_handle_s { switch_core_session_t *session; switch_channel_t *channel; switch_core_media_NDLB_t ndlb; - switch_core_media_flag_t media_flags; + switch_core_media_flag_t media_flags[SCMF_MAX]; smh_flag_t flags; switch_rtp_engine_t engines[SWITCH_MEDIA_TYPE_TOTAL]; scm_multi_t params[SCM_MAX]; - char *codec_order[SWITCH_MAX_CODECS];//tp - int codec_order_last;//tp - const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];//tp - int num_codecs;//tp - int payload_space;//tp + char *codec_order[SWITCH_MAX_CODECS];//x:tp + int codec_order_last;//x:tp + const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];//x:tp + int num_codecs;//x:tp + int payload_space;//x:tp + char *origin;//x:tp + int hold_laps;//x:tp + switch_payload_t te;//x:tp + switch_payload_t recv_te;//x:tp + switch_payload_t cng_pt;//x:tp + switch_core_media_dtmf_t dtmf_type;//x:tp + const switch_codec_implementation_t *negotiated_codecs[SWITCH_MAX_CODECS];//x:tp + int num_negotiated_codecs;//x:tp + switch_payload_t ianacodes[SWITCH_MAX_CODECS];//x:tp + int video_count;//x:tmp + }; SWITCH_DECLARE(void) switch_media_set_param(switch_media_handle_t *smh, scm_param_t param, ...) @@ -143,6 +201,232 @@ SWITCH_DECLARE(void *) switch_media_get_param(switch_media_handle_t *smh, scm_pa #define get_str(_o, _p) _o->params[_p].charval + + +static void _switch_core_media_pass_zrtp_hash2(switch_core_session_t *aleg_session, switch_core_session_t *bleg_session, switch_media_type_t type) +{ + switch_rtp_engine_t *aleg_engine; + switch_rtp_engine_t *bleg_engine; + + if (!aleg_session->media_handle && bleg_session->media_handle) return; + aleg_engine = &aleg_session->media_handle->engines[type]; + bleg_engine = &bleg_session->media_handle->engines[type]; + + + + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_session->channel), SWITCH_LOG_DEBUG1, + "Deciding whether to pass zrtp-hash between a-leg and b-leg\n"); + + if (!(switch_channel_test_flag(aleg_session->channel, CF_ZRTP_PASSTHRU_REQ))) { + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_session->channel), SWITCH_LOG_DEBUG1, + "CF_ZRTP_PASSTHRU_REQ not set on a-leg, so not propagating zrtp-hash\n"); + return; + } + + if (aleg_engine->remote_sdp_zrtp_hash) { + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_session->channel), SWITCH_LOG_DEBUG, "Passing a-leg remote zrtp-hash (audio) to b-leg\n"); + bleg_engine->local_sdp_zrtp_hash = switch_core_session_strdup(bleg_session, aleg_engine->remote_sdp_zrtp_hash); + switch_channel_set_variable(bleg_session->channel, "l_sdp_audio_zrtp_hash", bleg_engine->local_sdp_zrtp_hash); + } + + if (bleg_engine->remote_sdp_zrtp_hash) { + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(aleg_session->channel), SWITCH_LOG_DEBUG, "Passing b-leg remote zrtp-hash (audio) to a-leg\n"); + aleg_engine->local_sdp_zrtp_hash = switch_core_session_strdup(aleg_session, bleg_engine->remote_sdp_zrtp_hash); + switch_channel_set_variable(aleg_session->channel, "l_sdp_audio_zrtp_hash", aleg_engine->local_sdp_zrtp_hash); + } +} + +SWITCH_DECLARE(void) switch_core_media_pass_zrtp_hash2(switch_core_session_t *aleg_session, switch_core_session_t *bleg_session) +{ + _switch_core_media_pass_zrtp_hash2(aleg_session, bleg_session, SWITCH_MEDIA_TYPE_AUDIO); + _switch_core_media_pass_zrtp_hash2(aleg_session, bleg_session, SWITCH_MEDIA_TYPE_VIDEO); +} + + +SWITCH_DECLARE(void) switch_core_media_pass_zrtp_hash(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + + switch_core_session_t *other_session; + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Deciding whether to pass zrtp-hash between legs\n"); + if (!(switch_channel_test_flag(channel, CF_ZRTP_PASSTHRU_REQ))) { + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "CF_ZRTP_PASSTHRU_REQ not set, so not propagating zrtp-hash\n"); + return; + } else if (!(switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS)) { + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "No partner channel found, so not propagating zrtp-hash\n"); + return; + } else { + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Found peer channel; propagating zrtp-hash if set\n"); + switch_core_media_pass_zrtp_hash2(session, other_session); + switch_core_session_rwunlock(other_session); + } +} + +SWITCH_DECLARE(const char *) switch_core_media_get_zrtp_hash(switch_core_session_t *session, switch_media_type_t type, switch_bool_t local) +{ + switch_rtp_engine_t *engine; + if (!session->media_handle) return NULL; + + engine = &session->media_handle->engines[type]; + + if (local) { + return engine->local_sdp_zrtp_hash; + } + + + return engine->remote_sdp_zrtp_hash; + +} + +SWITCH_DECLARE(void) switch_core_media_find_zrtp_hash(switch_core_session_t *session, sdp_session_t *sdp) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_rtp_engine_t *audio_engine; + switch_rtp_engine_t *video_engine; + sdp_media_t *m; + sdp_attribute_t *attr; + int got_audio = 0, got_video = 0; + + if (!session->media_handle) return; + + audio_engine = &session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO]; + video_engine = &session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO]; + + + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1, "Looking for zrtp-hash\n"); + for (m = sdp->sdp_media; m; m = m->m_next) { + if (got_audio && got_video) break; + if (m->m_port && ((m->m_type == sdp_media_audio && !got_audio) + || (m->m_type == sdp_media_video && !got_video))) { + for (attr = m->m_attributes; attr; attr = attr->a_next) { + if (zstr(attr->a_name)) continue; + if (strcasecmp(attr->a_name, "zrtp-hash") || !(attr->a_value)) continue; + if (m->m_type == sdp_media_audio) { + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, + "Found audio zrtp-hash; setting r_sdp_audio_zrtp_hash=%s\n", attr->a_value); + switch_channel_set_variable(channel, "r_sdp_audio_zrtp_hash", attr->a_value); + audio_engine->remote_sdp_zrtp_hash = switch_core_session_strdup(session, attr->a_value); + got_audio++; + } else if (m->m_type == sdp_media_video) { + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, + "Found video zrtp-hash; setting r_sdp_video_zrtp_hash=%s\n", attr->a_value); + switch_channel_set_variable(channel, "r_sdp_video_zrtp_hash", attr->a_value); + video_engine->remote_sdp_zrtp_hash = switch_core_session_strdup(session, attr->a_value); + got_video++; + } + switch_channel_set_flag(channel, CF_ZRTP_HASH); + break; + } + } + } +} + + +SWITCH_DECLARE(switch_t38_options_t *) switch_core_media_process_udptl(switch_core_session_t *session, sdp_session_t *sdp, sdp_media_t *m) +{ + switch_t38_options_t *t38_options = switch_channel_get_private(session->channel, "t38_options"); + sdp_attribute_t *attr; + + if (!t38_options) { + t38_options = switch_core_session_alloc(session, sizeof(switch_t38_options_t)); + + // set some default value + t38_options->T38FaxVersion = 0; + t38_options->T38MaxBitRate = 14400; + t38_options->T38FaxRateManagement = switch_core_session_strdup(session, "transferredTCF"); + t38_options->T38FaxUdpEC = switch_core_session_strdup(session, "t38UDPRedundancy"); + t38_options->T38FaxMaxBuffer = 500; + t38_options->T38FaxMaxDatagram = 500; + } + + t38_options->remote_port = (switch_port_t)m->m_port; + + if (sdp->sdp_origin) { + t38_options->sdp_o_line = switch_core_session_strdup(session, sdp->sdp_origin->o_username); + } else { + t38_options->sdp_o_line = "unknown"; + } + + if (m->m_connections && m->m_connections->c_address) { + t38_options->remote_ip = switch_core_session_strdup(session, m->m_connections->c_address); + } else if (sdp && sdp->sdp_connection && sdp->sdp_connection->c_address) { + t38_options->remote_ip = switch_core_session_strdup(session, sdp->sdp_connection->c_address); + } + + for (attr = m->m_attributes; attr; attr = attr->a_next) { + if (!strcasecmp(attr->a_name, "T38FaxVersion") && attr->a_value) { + t38_options->T38FaxVersion = (uint16_t) atoi(attr->a_value); + } else if (!strcasecmp(attr->a_name, "T38MaxBitRate") && attr->a_value) { + t38_options->T38MaxBitRate = (uint32_t) atoi(attr->a_value); + } else if (!strcasecmp(attr->a_name, "T38FaxFillBitRemoval")) { + t38_options->T38FaxFillBitRemoval = switch_safe_atoi(attr->a_value, 1); + } else if (!strcasecmp(attr->a_name, "T38FaxTranscodingMMR")) { + t38_options->T38FaxTranscodingMMR = switch_safe_atoi(attr->a_value, 1); + } else if (!strcasecmp(attr->a_name, "T38FaxTranscodingJBIG")) { + t38_options->T38FaxTranscodingJBIG = switch_safe_atoi(attr->a_value, 1); + } else if (!strcasecmp(attr->a_name, "T38FaxRateManagement") && attr->a_value) { + t38_options->T38FaxRateManagement = switch_core_session_strdup(session, attr->a_value); + } else if (!strcasecmp(attr->a_name, "T38FaxMaxBuffer") && attr->a_value) { + t38_options->T38FaxMaxBuffer = (uint32_t) atoi(attr->a_value); + } else if (!strcasecmp(attr->a_name, "T38FaxMaxDatagram") && attr->a_value) { + t38_options->T38FaxMaxDatagram = (uint32_t) atoi(attr->a_value); + } else if (!strcasecmp(attr->a_name, "T38FaxUdpEC") && attr->a_value) { + t38_options->T38FaxUdpEC = switch_core_session_strdup(session, attr->a_value); + } else if (!strcasecmp(attr->a_name, "T38VendorInfo") && attr->a_value) { + t38_options->T38VendorInfo = switch_core_session_strdup(session, attr->a_value); + } + } + + switch_channel_set_variable(session->channel, "has_t38", "true"); + switch_channel_set_private(session->channel, "t38_options", t38_options); + switch_channel_set_app_flag_key("T38", session->channel, CF_APP_T38); + + switch_channel_execute_on(session->channel, "sip_execute_on_image"); + switch_channel_api_on(session->channel, "sip_api_on_image"); + + return t38_options; +} + + + + + +SWITCH_DECLARE(switch_t38_options_t *) switch_core_media_extract_t38_options(switch_core_session_t *session, const char *r_sdp) +{ + sdp_media_t *m; + sdp_parser_t *parser = NULL; + sdp_session_t *sdp; + //private_object_t *tech_pvt = switch_core_session_get_private(session); + switch_t38_options_t *t38_options = NULL; + + if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) { + return 0; + } + + if (!(sdp = sdp_session(parser))) { + sdp_parser_free(parser); + return 0; + } + + //switch_assert(tech_pvt != NULL); + + for (m = sdp->sdp_media; m; m = m->m_next) { + if (m->m_proto == sdp_proto_udptl && m->m_type == sdp_media_image && m->m_port) { + t38_options = switch_core_media_process_udptl(session, sdp, m); + break; + } + } + + sdp_parser_free(parser); + + return t38_options; + +} + + + + + SWITCH_DECLARE(const char *)switch_core_media_get_codec_string(switch_core_session_t *session) { const char *preferred = NULL, *fallback = NULL; @@ -184,7 +468,105 @@ SWITCH_DECLARE(const char *) switch_core_session_local_crypto_key(switch_core_se } -switch_status_t switch_core_media_build_crypto(switch_media_handle_t *smh, + +SWITCH_DECLARE(void) switch_core_media_parse_rtp_bugs(switch_rtp_bug_flag_t *flag_pole, const char *str) +{ + + if (switch_stristr("clear", str)) { + *flag_pole = 0; + } + + if (switch_stristr("CISCO_SKIP_MARK_BIT_2833", str)) { + *flag_pole |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833; + } + + if (switch_stristr("~CISCO_SKIP_MARK_BIT_2833", str)) { + *flag_pole &= ~RTP_BUG_CISCO_SKIP_MARK_BIT_2833; + } + + if (switch_stristr("SONUS_SEND_INVALID_TIMESTAMP_2833", str)) { + *flag_pole |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833; + } + + if (switch_stristr("~SONUS_SEND_INVALID_TIMESTAMP_2833", str)) { + *flag_pole &= ~RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833; + } + + if (switch_stristr("IGNORE_MARK_BIT", str)) { + *flag_pole |= RTP_BUG_IGNORE_MARK_BIT; + } + + if (switch_stristr("~IGNORE_MARK_BIT", str)) { + *flag_pole &= ~RTP_BUG_IGNORE_MARK_BIT; + } + + if (switch_stristr("SEND_LINEAR_TIMESTAMPS", str)) { + *flag_pole |= RTP_BUG_SEND_LINEAR_TIMESTAMPS; + } + + if (switch_stristr("~SEND_LINEAR_TIMESTAMPS", str)) { + *flag_pole &= ~RTP_BUG_SEND_LINEAR_TIMESTAMPS; + } + + if (switch_stristr("START_SEQ_AT_ZERO", str)) { + *flag_pole |= RTP_BUG_START_SEQ_AT_ZERO; + } + + if (switch_stristr("~START_SEQ_AT_ZERO", str)) { + *flag_pole &= ~RTP_BUG_START_SEQ_AT_ZERO; + } + + if (switch_stristr("NEVER_SEND_MARKER", str)) { + *flag_pole |= RTP_BUG_NEVER_SEND_MARKER; + } + + if (switch_stristr("~NEVER_SEND_MARKER", str)) { + *flag_pole &= ~RTP_BUG_NEVER_SEND_MARKER; + } + + if (switch_stristr("IGNORE_DTMF_DURATION", str)) { + *flag_pole |= RTP_BUG_IGNORE_DTMF_DURATION; + } + + if (switch_stristr("~IGNORE_DTMF_DURATION", str)) { + *flag_pole &= ~RTP_BUG_IGNORE_DTMF_DURATION; + } + + if (switch_stristr("ACCEPT_ANY_PACKETS", str)) { + *flag_pole |= RTP_BUG_ACCEPT_ANY_PACKETS; + } + + if (switch_stristr("~ACCEPT_ANY_PACKETS", str)) { + *flag_pole &= ~RTP_BUG_ACCEPT_ANY_PACKETS; + } + + if (switch_stristr("GEN_ONE_GEN_ALL", str)) { + *flag_pole |= RTP_BUG_GEN_ONE_GEN_ALL; + } + + if (switch_stristr("~GEN_ONE_GEN_ALL", str)) { + *flag_pole &= ~RTP_BUG_GEN_ONE_GEN_ALL; + } + + if (switch_stristr("CHANGE_SSRC_ON_MARKER", str)) { + *flag_pole |= RTP_BUG_CHANGE_SSRC_ON_MARKER; + } + + if (switch_stristr("~CHANGE_SSRC_ON_MARKER", str)) { + *flag_pole &= ~RTP_BUG_CHANGE_SSRC_ON_MARKER; + } + + if (switch_stristr("FLUSH_JB_ON_DTMF", str)) { + *flag_pole |= RTP_BUG_FLUSH_JB_ON_DTMF; + } + + if (switch_stristr("~FLUSH_JB_ON_DTMF", str)) { + *flag_pole &= ~RTP_BUG_FLUSH_JB_ON_DTMF; + } +} + + +static switch_status_t switch_core_media_build_crypto(switch_media_handle_t *smh, switch_secure_settings_t *ssec, int index, switch_rtp_crypto_key_type_t type, switch_rtp_crypto_direction_t direction) { @@ -448,7 +830,7 @@ SWITCH_DECLARE(switch_status_t) switch_media_handle_create(switch_media_handle_t session->media_handle->session = session; *smhp = session->media_handle; switch_set_flag(session->media_handle, SMH_INIT); - + session->media_handle->media_flags[SCMF_RUNNING] = 1; session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN; session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN; @@ -484,7 +866,18 @@ SWITCH_DECLARE(void) switch_media_handle_set_media_flag(switch_media_handle_t *s { switch_assert(smh); - smh->media_flags |= flag; + smh->media_flags[flag] = 1; + +} + +SWITCH_DECLARE(void) switch_media_handle_set_media_flags(switch_media_handle_t *smh, switch_core_media_flag_t flags[SCMF_MAX]) +{ + int i; + switch_assert(smh); + + for(i = 0; i < SCMF_MAX; i++) { + smh->media_flags[i] = flags[i]; + } } @@ -492,13 +885,13 @@ SWITCH_DECLARE(void) switch_media_handle_clear_media_flag(switch_media_handle_t { switch_assert(smh); - smh->media_flags &= ~flag; + smh->media_flags[flag] = 0; } SWITCH_DECLARE(int32_t) switch_media_handle_test_media_flag(switch_media_handle_t *smh, switch_core_media_flag_t flag) { switch_assert(smh); - return (smh->media_flags & flag); + return smh->media_flags[flag]; } SWITCH_DECLARE(switch_status_t) switch_core_session_media_handle_ready(switch_core_session_t *session) @@ -530,329 +923,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_clear_media_handle(switch_co } - - -#if 0 -SWITCH_DECLARE(switch_status_t) switch_core_session_read_media_frame(switch_core_session_t *session, switch_frame_t **frame, - switch_io_flag_t flags, int stream_id, switch_media_type_t type) -{ - switch_channel_t *channel; - uint32_t sanity = 1000; - switch_rtcp_frame_t rtcp_frame; - switch_rtp_engine_t *engine; - - if (!session->media_handle) return; - - engine = &session->media_handle->engines[type]; - channel = switch_core_session_get_channel(session); - - - switch_assert(tech_pvt != NULL); - - - tech_pvt->read_frame.datalen = 0; - sofia_set_flag_locked(tech_pvt, TFLAG_READING); - - if (sofia_test_flag(tech_pvt, TFLAG_HUP) || sofia_test_flag(tech_pvt, TFLAG_BYE) || !tech_pvt->read_codec.implementation || - !switch_core_codec_ready(&tech_pvt->read_codec)) { - return SWITCH_STATUS_FALSE; - } - - if (sofia_test_flag(tech_pvt, TFLAG_IO)) { - switch_status_t status; - - if (!sofia_test_flag(tech_pvt, TFLAG_RTP)) { - return SWITCH_STATUS_GENERR; - } - - switch_assert(tech_pvt->rtp_session != NULL); - tech_pvt->read_frame.datalen = 0; - - - if (sofia_test_flag(tech_pvt, TFLAG_SIMPLIFY) && sofia_test_flag(tech_pvt, TFLAG_GOT_ACK)) { - if (sofia_glue_tech_simplify(tech_pvt)) { - sofia_clear_flag(tech_pvt, TFLAG_SIMPLIFY); - } - } - - while (sofia_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) { - tech_pvt->read_frame.flags = SFF_NONE; - - status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags); - - if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { - if (status == SWITCH_STATUS_TIMEOUT) { - - if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { - sofia_glue_toggle_hold(tech_pvt, 0); - sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); - switch_channel_clear_flag(channel, CF_LEG_HOLDING); - } - - if (switch_channel_get_variable(tech_pvt->channel, "execute_on_media_timeout")) { - *frame = &tech_pvt->read_frame; - switch_set_flag((*frame), SFF_CNG); - (*frame)->datalen = tech_pvt->read_impl.encoded_bytes_per_packet; - memset((*frame)->data, 0, (*frame)->datalen); - switch_channel_execute_on(tech_pvt->channel, "execute_on_media_timeout"); - return SWITCH_STATUS_SUCCESS; - } - - - switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_MEDIA_TIMEOUT); - } - return status; - } - - /* Try to read an RTCP frame, if successful raise an event */ - if (switch_rtcp_zerocopy_read_frame(tech_pvt->rtp_session, &rtcp_frame) == SWITCH_STATUS_SUCCESS) { - switch_event_t *event; - - if (switch_event_create(&event, SWITCH_EVENT_RECV_RTCP_MESSAGE) == SWITCH_STATUS_SUCCESS) { - char value[30]; - char header[50]; - int i; - - char *uuid = switch_core_session_get_uuid(session); - if (uuid) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(session)); - } - - snprintf(value, sizeof(value), "%.8x", rtcp_frame.ssrc); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SSRC", value); - - snprintf(value, sizeof(value), "%u", rtcp_frame.ntp_msw); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "NTP-Most-Significant-Word", value); - - snprintf(value, sizeof(value), "%u", rtcp_frame.ntp_lsw); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "NTP-Least-Significant-Word", value); - - snprintf(value, sizeof(value), "%u", rtcp_frame.timestamp); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "RTP-Timestamp", value); - - snprintf(value, sizeof(value), "%u", rtcp_frame.packet_count); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Sender-Packet-Count", value); - - snprintf(value, sizeof(value), "%u", rtcp_frame.octect_count); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Octect-Packet-Count", value); - - snprintf(value, sizeof(value), "%" SWITCH_SIZE_T_FMT, tech_pvt->read_frame.timestamp); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Last-RTP-Timestamp", value); - - snprintf(value, sizeof(value), "%u", tech_pvt->read_frame.rate); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "RTP-Rate", value); - - snprintf(value, sizeof(value), "%" SWITCH_TIME_T_FMT, switch_time_now()); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Capture-Time", value); - - // Add sources info - for (i = 0; i < rtcp_frame.report_count; i++) { - snprintf(header, sizeof(header), "Source%u-SSRC", i); - snprintf(value, sizeof(value), "%.8x", rtcp_frame.reports[i].ssrc); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); - snprintf(header, sizeof(header), "Source%u-Fraction", i); - snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].fraction); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); - snprintf(header, sizeof(header), "Source%u-Lost", i); - snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].lost); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); - snprintf(header, sizeof(header), "Source%u-Highest-Sequence-Number-Received", i); - snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].highest_sequence_number_received); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); - snprintf(header, sizeof(header), "Source%u-Jitter", i); - snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].jitter); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); - snprintf(header, sizeof(header), "Source%u-LSR", i); - snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].lsr); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); - snprintf(header, sizeof(header), "Source%u-DLSR", i); - snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].dlsr); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); - } - - switch_event_fire(&event); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG10, "Dispatched RTCP event\n"); - } - } - - /* Fast PASS! */ - if (switch_test_flag((&tech_pvt->read_frame), SFF_PROXY_PACKET)) { - sofia_clear_flag_locked(tech_pvt, TFLAG_READING); - *frame = &tech_pvt->read_frame; - return SWITCH_STATUS_SUCCESS; - } - - if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) { - switch_dtmf_t dtmf = { 0 }; - switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, &dtmf); - switch_channel_queue_dtmf(channel, &dtmf); - } - - if (tech_pvt->read_frame.datalen > 0) { - uint32_t bytes = 0; - int frames = 1; - - if (!switch_test_flag((&tech_pvt->read_frame), SFF_CNG)) { - if (!tech_pvt->read_codec.implementation || !switch_core_codec_ready(&tech_pvt->read_codec)) { - *frame = NULL; - return SWITCH_STATUS_GENERR; - } - - if ((tech_pvt->read_frame.datalen % 10) == 0 && - sofia_test_pflag(tech_pvt->profile, PFLAG_AUTOFIX_TIMING) && tech_pvt->check_frames < MAX_CODEC_CHECK_FRAMES) { - tech_pvt->check_frames++; - - if (!tech_pvt->read_impl.encoded_bytes_per_packet) { - tech_pvt->check_frames = MAX_CODEC_CHECK_FRAMES; - goto skip; - } - - if (tech_pvt->last_ts && tech_pvt->read_frame.datalen != tech_pvt->read_impl.encoded_bytes_per_packet) { - uint32_t codec_ms = (int) (tech_pvt->read_frame.timestamp - - tech_pvt->last_ts) / (tech_pvt->read_impl.samples_per_second / 1000); - - if ((codec_ms % 10) != 0 || codec_ms > tech_pvt->read_impl.samples_per_packet * 10) { - tech_pvt->last_ts = 0; - goto skip; - } - - - if (tech_pvt->last_codec_ms && tech_pvt->last_codec_ms == codec_ms) { - tech_pvt->mismatch_count++; - } - - tech_pvt->last_codec_ms = codec_ms; - - if (tech_pvt->mismatch_count > MAX_MISMATCH_FRAMES) { - if (switch_rtp_ready(tech_pvt->rtp_session) && codec_ms != tech_pvt->codec_ms) { - const char *val; - int rtp_timeout_sec = 0; - int rtp_hold_timeout_sec = 0; - - if (codec_ms > 120) { /* yeah right */ - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, - "Your phone is trying to send timestamps that suggest an increment of %dms per packet\n" - "That seems hard to believe so I am going to go on ahead and um ignore that, mmkay?\n", - (int) codec_ms); - tech_pvt->check_frames = MAX_CODEC_CHECK_FRAMES; - goto skip; - } - - tech_pvt->read_frame.datalen = 0; - - if (codec_ms != tech_pvt->codec_ms) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, - "Asynchronous PTIME not supported, changing our end from %d to %d\n", - (int) tech_pvt->codec_ms, - (int) codec_ms - ); - - switch_channel_set_variable_printf(channel, "sip_h_X-Broken-PTIME", "Adv=%d;Sent=%d", - (int) tech_pvt->codec_ms, (int) codec_ms); - - tech_pvt->codec_ms = codec_ms; - } - - if (sofia_glue_tech_set_codec(tech_pvt, 2) != SWITCH_STATUS_SUCCESS) { - *frame = NULL; - return SWITCH_STATUS_GENERR; - } - - if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_timeout_sec"))) { - int v = atoi(val); - if (v >= 0) { - rtp_timeout_sec = v; - } - } - - if ((val = switch_channel_get_variable(tech_pvt->channel, "rtp_hold_timeout_sec"))) { - int v = atoi(val); - if (v >= 0) { - rtp_hold_timeout_sec = v; - } - } - - if (rtp_timeout_sec) { - tech_pvt->max_missed_packets = (tech_pvt->read_impl.samples_per_second * rtp_timeout_sec) / - tech_pvt->read_impl.samples_per_packet; - - switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_packets); - if (!rtp_hold_timeout_sec) { - rtp_hold_timeout_sec = rtp_timeout_sec * 10; - } - } - - if (rtp_hold_timeout_sec) { - tech_pvt->max_missed_hold_packets = (tech_pvt->read_impl.samples_per_second * rtp_hold_timeout_sec) / - tech_pvt->read_impl.samples_per_packet; - } - - - tech_pvt->check_frames = 0; - tech_pvt->last_ts = 0; - - /* inform them of the codec they are actually sending */ -#if 0 - if (++tech_pvt->codec_reinvites > 2) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, - "Ok, some devices *cough* X-lite *cough*\n" - "seem to continue to lie over and over again so I guess we'll\n" - "leave well-enough alone and let them lie\n"); - } else { - sofia_glue_do_invite(session); - } -#endif - *frame = &tech_pvt->read_frame; - switch_set_flag((*frame), SFF_CNG); - (*frame)->datalen = tech_pvt->read_impl.encoded_bytes_per_packet; - memset((*frame)->data, 0, (*frame)->datalen); - return SWITCH_STATUS_SUCCESS; - } - - } - - } else { - tech_pvt->mismatch_count = 0; - } - - tech_pvt->last_ts = tech_pvt->read_frame.timestamp; - - - } else { - tech_pvt->mismatch_count = 0; - tech_pvt->last_ts = 0; - } - skip: - - if ((bytes = tech_pvt->read_impl.encoded_bytes_per_packet)) { - frames = (tech_pvt->read_frame.datalen / bytes); - } - tech_pvt->read_frame.samples = (int) (frames * tech_pvt->read_impl.samples_per_packet); - - if (tech_pvt->read_frame.datalen == 0) { - continue; - } - } - break; - } - } - } - - sofia_clear_flag_locked(tech_pvt, TFLAG_READING); - - if (tech_pvt->read_frame.datalen == 0) { - *frame = NULL; - return SWITCH_STATUS_GENERR; - } - - *frame = &tech_pvt->read_frame; - - return SWITCH_STATUS_SUCCESS; -} -#endif - - - SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *session, switch_bool_t force) { const char *abs, *codec_string = NULL; @@ -900,7 +970,7 @@ SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *ses if ((ocodec = switch_channel_get_variable(session->channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) { - if (!codec_string || (smh->media_flags & SCMF_DISABLE_TRANSCODING)) { + if (!codec_string || (smh->media_flags[SCMF_DISABLE_TRANSCODING])) { codec_string = ocodec; } else { if (!(codec_string = switch_core_session_sprintf(smh->session, "%s,%s", ocodec, codec_string))) { @@ -922,6 +992,1494 @@ SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *ses +SWITCH_DECLARE(switch_status_t) switch_core_session_read_media_frame(switch_core_session_t *session, switch_frame_t **frame, + switch_io_flag_t flags, int stream_id, switch_media_type_t type) +{ + switch_rtcp_frame_t rtcp_frame; + switch_rtp_engine_t *engine; + switch_status_t status; + switch_media_handle_t *smh; + + if (!(smh = session->media_handle)) { + return SWITCH_STATUS_FALSE; + } + + if (!(smh->flags & SCMF_RUNNING)) { + return SWITCH_STATUS_FALSE; + } + + engine = &smh->engines[type]; + + engine->read_frame.datalen = 0; + + if (!engine->read_codec.implementation || !switch_core_codec_ready(&engine->read_codec)) { + return SWITCH_STATUS_FALSE; + } + + switch_assert(engine->rtp_session != NULL); + engine->read_frame.datalen = 0; + + + while ((smh->flags & SCMF_RUNNING) && engine->read_frame.datalen == 0) { + engine->read_frame.flags = SFF_NONE; + + status = switch_rtp_zerocopy_read_frame(engine->rtp_session, &engine->read_frame, flags); + + if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { + if (status == SWITCH_STATUS_TIMEOUT) { + +#if 0 + if (sofia_test_flag(engine, TFLAG_SIP_HOLD)) { + switch_core_media_toggle_hold(engine, 0); + sofia_clear_flag_locked(engine, TFLAG_SIP_HOLD); + switch_channel_clear_flag(channel, CF_LEG_HOLDING); + } +#endif + + if (switch_channel_get_variable(session->channel, "execute_on_media_timeout")) { + *frame = &engine->read_frame; + switch_set_flag((*frame), SFF_CNG); + (*frame)->datalen = engine->read_impl.encoded_bytes_per_packet; + memset((*frame)->data, 0, (*frame)->datalen); + switch_channel_execute_on(session->channel, "execute_on_media_timeout"); + return SWITCH_STATUS_SUCCESS; + } + + + switch_channel_hangup(session->channel, SWITCH_CAUSE_MEDIA_TIMEOUT); + } + return status; + } + + /* Try to read an RTCP frame, if successful raise an event */ + if (switch_rtcp_zerocopy_read_frame(engine->rtp_session, &rtcp_frame) == SWITCH_STATUS_SUCCESS) { + switch_event_t *event; + + if (switch_event_create(&event, SWITCH_EVENT_RECV_RTCP_MESSAGE) == SWITCH_STATUS_SUCCESS) { + char value[30]; + char header[50]; + int i; + + char *uuid = switch_core_session_get_uuid(session); + if (uuid) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(session)); + } + + snprintf(value, sizeof(value), "%.8x", rtcp_frame.ssrc); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SSRC", value); + + snprintf(value, sizeof(value), "%u", rtcp_frame.ntp_msw); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "NTP-Most-Significant-Word", value); + + snprintf(value, sizeof(value), "%u", rtcp_frame.ntp_lsw); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "NTP-Least-Significant-Word", value); + + snprintf(value, sizeof(value), "%u", rtcp_frame.timestamp); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "RTP-Timestamp", value); + + snprintf(value, sizeof(value), "%u", rtcp_frame.packet_count); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Sender-Packet-Count", value); + + snprintf(value, sizeof(value), "%u", rtcp_frame.octect_count); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Octect-Packet-Count", value); + + snprintf(value, sizeof(value), "%" SWITCH_SIZE_T_FMT, engine->read_frame.timestamp); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Last-RTP-Timestamp", value); + + snprintf(value, sizeof(value), "%u", engine->read_frame.rate); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "RTP-Rate", value); + + snprintf(value, sizeof(value), "%" SWITCH_TIME_T_FMT, switch_time_now()); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Capture-Time", value); + + // Add sources info + for (i = 0; i < rtcp_frame.report_count; i++) { + snprintf(header, sizeof(header), "Source%u-SSRC", i); + snprintf(value, sizeof(value), "%.8x", rtcp_frame.reports[i].ssrc); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); + snprintf(header, sizeof(header), "Source%u-Fraction", i); + snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].fraction); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); + snprintf(header, sizeof(header), "Source%u-Lost", i); + snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].lost); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); + snprintf(header, sizeof(header), "Source%u-Highest-Sequence-Number-Received", i); + snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].highest_sequence_number_received); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); + snprintf(header, sizeof(header), "Source%u-Jitter", i); + snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].jitter); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); + snprintf(header, sizeof(header), "Source%u-LSR", i); + snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].lsr); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); + snprintf(header, sizeof(header), "Source%u-DLSR", i); + snprintf(value, sizeof(value), "%u", rtcp_frame.reports[i].dlsr); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header, value); + } + + switch_event_fire(&event); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG10, "Dispatched RTCP event\n"); + } + } + + /* Fast PASS! */ + if (switch_test_flag((&engine->read_frame), SFF_PROXY_PACKET)) { + *frame = &engine->read_frame; + return SWITCH_STATUS_SUCCESS; + } + + if (switch_rtp_has_dtmf(engine->rtp_session)) { + switch_dtmf_t dtmf = { 0 }; + switch_rtp_dequeue_dtmf(engine->rtp_session, &dtmf); + switch_channel_queue_dtmf(session->channel, &dtmf); + } + + if (engine->read_frame.datalen > 0) { + uint32_t bytes = 0; + int frames = 1; + + if (!switch_test_flag((&engine->read_frame), SFF_CNG)) { + if (!engine->read_codec.implementation || !switch_core_codec_ready(&engine->read_codec)) { + *frame = NULL; + return SWITCH_STATUS_GENERR; + } + + if ((engine->read_frame.datalen % 10) == 0 && + (smh->media_flags[SCMF_AUTOFIX_TIMING]) && engine->check_frames < MAX_CODEC_CHECK_FRAMES) { + engine->check_frames++; + + if (!engine->read_impl.encoded_bytes_per_packet) { + engine->check_frames = MAX_CODEC_CHECK_FRAMES; + goto skip; + } + + if (engine->last_ts && engine->read_frame.datalen != engine->read_impl.encoded_bytes_per_packet) { + uint32_t codec_ms = (int) (engine->read_frame.timestamp - + engine->last_ts) / (engine->read_impl.samples_per_second / 1000); + + if ((codec_ms % 10) != 0 || codec_ms > engine->read_impl.samples_per_packet * 10) { + engine->last_ts = 0; + goto skip; + } + + + if (engine->last_codec_ms && engine->last_codec_ms == codec_ms) { + engine->mismatch_count++; + } + + engine->last_codec_ms = codec_ms; + + if (engine->mismatch_count > MAX_MISMATCH_FRAMES) { + if (switch_rtp_ready(engine->rtp_session) && codec_ms != engine->codec_ms) { + const char *val; + int rtp_timeout_sec = 0; + int rtp_hold_timeout_sec = 0; + + if (codec_ms > 120) { /* yeah right */ + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "Your phone is trying to send timestamps that suggest an increment of %dms per packet\n" + "That seems hard to believe so I am going to go on ahead and um ignore that, mmkay?\n", + (int) codec_ms); + engine->check_frames = MAX_CODEC_CHECK_FRAMES; + goto skip; + } + + engine->read_frame.datalen = 0; + + if (codec_ms != engine->codec_ms) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "Asynchronous PTIME not supported, changing our end from %d to %d\n", + (int) engine->codec_ms, + (int) codec_ms + ); + + switch_channel_set_variable_printf(session->channel, "sip_h_X-Broken-PTIME", "Adv=%d;Sent=%d", + (int) engine->codec_ms, (int) codec_ms); + + engine->codec_ms = codec_ms; + } + +#if fixmeXXXXX + if (switch_core_media_tech_set_codec(engine, 2) != SWITCH_STATUS_SUCCESS) { + *frame = NULL; + return SWITCH_STATUS_GENERR; + } +#endif + if ((val = switch_channel_get_variable(session->channel, "rtp_timeout_sec"))) { + int v = atoi(val); + if (v >= 0) { + rtp_timeout_sec = v; + } + } + + if ((val = switch_channel_get_variable(session->channel, "rtp_hold_timeout_sec"))) { + int v = atoi(val); + if (v >= 0) { + rtp_hold_timeout_sec = v; + } + } + + if (rtp_timeout_sec) { + engine->max_missed_packets = (engine->read_impl.samples_per_second * rtp_timeout_sec) / + engine->read_impl.samples_per_packet; + + switch_rtp_set_max_missed_packets(engine->rtp_session, engine->max_missed_packets); + if (!rtp_hold_timeout_sec) { + rtp_hold_timeout_sec = rtp_timeout_sec * 10; + } + } + + if (rtp_hold_timeout_sec) { + engine->max_missed_hold_packets = (engine->read_impl.samples_per_second * rtp_hold_timeout_sec) / + engine->read_impl.samples_per_packet; + } + + + engine->check_frames = 0; + engine->last_ts = 0; + + *frame = &engine->read_frame; + switch_set_flag((*frame), SFF_CNG); + (*frame)->datalen = engine->read_impl.encoded_bytes_per_packet; + memset((*frame)->data, 0, (*frame)->datalen); + return SWITCH_STATUS_SUCCESS; + } + + } + + } else { + engine->mismatch_count = 0; + } + + engine->last_ts = engine->read_frame.timestamp; + + + } else { + engine->mismatch_count = 0; + engine->last_ts = 0; + } + skip: + + if ((bytes = engine->read_impl.encoded_bytes_per_packet)) { + frames = (engine->read_frame.datalen / bytes); + } + engine->read_frame.samples = (int) (frames * engine->read_impl.samples_per_packet); + + if (engine->read_frame.datalen == 0) { + continue; + } + } + break; + } + } + + if (engine->read_frame.datalen == 0) { + *frame = NULL; + return SWITCH_STATUS_GENERR; + } + + *frame = &engine->read_frame; + + return SWITCH_STATUS_SUCCESS; +} + + +SWITCH_DECLARE(void) switch_core_media_copy_t38_options(switch_t38_options_t *t38_options, switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_t38_options_t *local_t38_options = switch_channel_get_private(channel, "t38_options"); + + switch_assert(t38_options); + + if (!local_t38_options) { + local_t38_options = switch_core_session_alloc(session, sizeof(switch_t38_options_t)); + } + + local_t38_options->T38MaxBitRate = t38_options->T38MaxBitRate; + local_t38_options->T38FaxFillBitRemoval = t38_options->T38FaxFillBitRemoval; + local_t38_options->T38FaxTranscodingMMR = t38_options->T38FaxTranscodingMMR; + local_t38_options->T38FaxTranscodingJBIG = t38_options->T38FaxTranscodingJBIG; + local_t38_options->T38FaxRateManagement = switch_core_session_strdup(session, t38_options->T38FaxRateManagement); + local_t38_options->T38FaxMaxBuffer = t38_options->T38FaxMaxBuffer; + local_t38_options->T38FaxMaxDatagram = t38_options->T38FaxMaxDatagram; + local_t38_options->T38FaxUdpEC = switch_core_session_strdup(session, t38_options->T38FaxUdpEC); + local_t38_options->T38VendorInfo = switch_core_session_strdup(session, t38_options->T38VendorInfo); + local_t38_options->remote_ip = switch_core_session_strdup(session, t38_options->remote_ip); + local_t38_options->remote_port = t38_options->remote_port; + + + switch_channel_set_private(channel, "t38_options", local_t38_options); + +} + + +SWITCH_DECLARE(switch_status_t) switch_core_media_get_offered_pt(switch_core_session_t *session, const switch_codec_implementation_t *mimp, switch_payload_t *pt) +{ + int i = 0; + switch_media_handle_t *smh; + + if (!(smh = session->media_handle)) { + return SWITCH_STATUS_FALSE; + } + + + for (i = 0; i < smh->num_codecs; i++) { + const switch_codec_implementation_t *imp = smh->codecs[i]; + + if (!strcasecmp(imp->iananame, mimp->iananame)) { + *pt = smh->ianacodes[i]; + + return SWITCH_STATUS_SUCCESS; + } + } + + return SWITCH_STATUS_FALSE; +} + +//? +switch_status_t switch_core_media_set_video_codec(switch_core_session_t *session, int force) +{ + switch_media_handle_t *smh; + switch_rtp_engine_t *v_engine; + + if (!(smh = session->media_handle)) { + return SWITCH_STATUS_FALSE; + } + v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO]; + + + if (!v_engine->codec_params.rm_encoding) { + return SWITCH_STATUS_FALSE; + } + + if (v_engine->read_codec.implementation && switch_core_codec_ready(&v_engine->read_codec)) { + if (!force) { + return SWITCH_STATUS_SUCCESS; + } + if (strcasecmp(v_engine->read_codec.implementation->iananame, v_engine->codec_params.rm_encoding) || + v_engine->read_codec.implementation->samples_per_second != v_engine->codec_params.rm_rate) { + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Changing Codec from %s to %s\n", + v_engine->read_codec.implementation->iananame, v_engine->codec_params.rm_encoding); + switch_core_codec_destroy(&v_engine->read_codec); + switch_core_codec_destroy(&v_engine->write_codec); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Already using %s\n", + v_engine->read_codec.implementation->iananame); + return SWITCH_STATUS_SUCCESS; + } + } + + + + if (switch_core_codec_init(&v_engine->read_codec, + v_engine->codec_params.rm_encoding, + v_engine->codec_params.rm_fmtp, + v_engine->codec_params.rm_rate, + 0, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't load codec?\n"); + return SWITCH_STATUS_FALSE; + } else { + if (switch_core_codec_init(&v_engine->write_codec, + v_engine->codec_params.rm_encoding, + v_engine->codec_params.rm_fmtp, + v_engine->codec_params.rm_rate, + 0, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't load codec?\n"); + return SWITCH_STATUS_FALSE; + } else { + v_engine->read_frame.rate = v_engine->codec_params.rm_rate; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set VIDEO Codec %s %s/%ld %d ms\n", + switch_channel_get_name(session->channel), v_engine->codec_params.rm_encoding, + v_engine->codec_params.rm_rate, v_engine->codec_params.codec_ms); + v_engine->read_frame.codec = &v_engine->read_codec; + + v_engine->write_codec.fmtp_out = switch_core_session_strdup(session, v_engine->write_codec.fmtp_out); + + v_engine->write_codec.agreed_pt = v_engine->codec_params.agreed_pt; + v_engine->read_codec.agreed_pt = v_engine->codec_params.agreed_pt; + switch_core_session_set_video_read_codec(session, &v_engine->read_codec); + switch_core_session_set_video_write_codec(session, &v_engine->write_codec); + + + if (switch_rtp_ready(v_engine->rtp_session)) { + switch_core_session_message_t msg = { 0 }; + + msg.from = __FILE__; + msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ; + + switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->codec_params.agreed_pt); + + if (v_engine->codec_params.recv_pt != v_engine->codec_params.agreed_pt) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "%s Set video receive payload to %u\n", switch_channel_get_name(session->channel), v_engine->codec_params.recv_pt); + + switch_rtp_set_recv_pt(v_engine->rtp_session, v_engine->codec_params.recv_pt); + } else { + switch_rtp_set_recv_pt(v_engine->rtp_session, v_engine->codec_params.agreed_pt); + } + + switch_core_session_receive_message(session, &msg); + + + } + + switch_channel_set_variable(session->channel, "sip_use_video_codec_name", v_engine->codec_params.rm_encoding); + switch_channel_set_variable(session->channel, "sip_use_video_codec_fmtp", v_engine->codec_params.rm_fmtp); + switch_channel_set_variable_printf(session->channel, "sip_use_video_codec_rate", "%d", v_engine->codec_params.rm_rate); + switch_channel_set_variable_printf(session->channel, "sip_use_video_codec_ptime", "%d", 0); + + } + } + return SWITCH_STATUS_SUCCESS; +} + + +//? +switch_status_t switch_core_media_set_codec(switch_core_session_t *session, int force, uint32_t codec_flags) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + int resetting = 0; + switch_media_handle_t *smh; + switch_rtp_engine_t *a_engine; + + if (!(smh = session->media_handle)) { + return SWITCH_STATUS_FALSE; + } + a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO]; + + if (!a_engine->codec_params.iananame) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No audio codec available\n"); + switch_goto_status(SWITCH_STATUS_FALSE, end); + } + + if (switch_core_codec_ready(&a_engine->read_codec)) { + if (!force) { + switch_goto_status(SWITCH_STATUS_SUCCESS, end); + } + if (strcasecmp(a_engine->read_impl.iananame, a_engine->codec_params.iananame) || + a_engine->read_impl.samples_per_second != a_engine->codec_params.rm_rate || + a_engine->codec_ms != (uint32_t) a_engine->read_impl.microseconds_per_packet / 1000) { + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "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->codec_params.rm_encoding, + a_engine->codec_params.codec_ms, + a_engine->codec_params.rm_rate); + + switch_yield(a_engine->read_impl.microseconds_per_packet); + switch_core_session_lock_codec_write(session); + switch_core_session_lock_codec_read(session); + resetting = 1; + switch_yield(a_engine->read_impl.microseconds_per_packet); + switch_core_codec_destroy(&a_engine->read_codec); + switch_core_codec_destroy(&a_engine->write_codec); + switch_channel_audio_sync(session->channel); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Already using %s\n", a_engine->read_impl.iananame); + switch_goto_status(SWITCH_STATUS_SUCCESS, end); + } + } + + if (switch_core_codec_init_with_bitrate(&a_engine->read_codec, + a_engine->codec_params.iananame, + a_engine->codec_params.rm_fmtp, + a_engine->codec_params.rm_rate, + a_engine->codec_params.codec_ms, + 1, + a_engine->codec_params.bitrate, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | codec_flags, + NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't load codec?\n"); + switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); + switch_goto_status(SWITCH_STATUS_FALSE, end); + } + + a_engine->read_codec.session = session; + + + if (switch_core_codec_init_with_bitrate(&a_engine->write_codec, + a_engine->codec_params.iananame, + a_engine->codec_params.rm_fmtp, + a_engine->codec_params.rm_rate, + a_engine->codec_params.codec_ms, + 1, + a_engine->codec_params.bitrate, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | codec_flags, + NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't load codec?\n"); + switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); + switch_goto_status(SWITCH_STATUS_FALSE, end); + } + + a_engine->write_codec.session = session; + + switch_channel_set_variable(session->channel, "sip_use_codec_name", a_engine->codec_params.iananame); + switch_channel_set_variable(session->channel, "sip_use_codec_fmtp", a_engine->codec_params.rm_fmtp); + switch_channel_set_variable_printf(session->channel, "sip_use_codec_rate", "%d", a_engine->codec_params.rm_rate); + switch_channel_set_variable_printf(session->channel, "sip_use_codec_ptime", "%d", a_engine->codec_params.codec_ms); + + + switch_assert(a_engine->read_codec.implementation); + switch_assert(a_engine->write_codec.implementation); + + a_engine->read_impl = *a_engine->read_codec.implementation; + a_engine->write_impl = *a_engine->write_codec.implementation; + + switch_core_session_set_read_impl(session, a_engine->read_codec.implementation); + switch_core_session_set_write_impl(session, a_engine->write_codec.implementation); + + if (switch_rtp_ready(a_engine->rtp_session)) { + switch_assert(a_engine->read_codec.implementation); + + if (switch_rtp_change_interval(a_engine->rtp_session, + a_engine->read_impl.microseconds_per_packet, + a_engine->read_impl.samples_per_packet) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(session->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + switch_goto_status(SWITCH_STATUS_FALSE, end); + } + } + + a_engine->read_frame.rate = a_engine->codec_params.rm_rate; + + if (!switch_core_codec_ready(&a_engine->read_codec)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't load codec?\n"); + switch_goto_status(SWITCH_STATUS_FALSE, end); + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set Codec %s %s/%ld %d ms %d samples %d bits\n", + switch_channel_get_name(session->channel), a_engine->codec_params.iananame, a_engine->codec_params.rm_rate, + a_engine->codec_params.codec_ms, + a_engine->read_impl.samples_per_packet, a_engine->read_impl.bits_per_second); + a_engine->read_frame.codec = &a_engine->read_codec; + + a_engine->write_codec.agreed_pt = a_engine->codec_params.agreed_pt; + a_engine->read_codec.agreed_pt = a_engine->codec_params.agreed_pt; + + if (force != 2) { + switch_core_session_set_real_read_codec(session, &a_engine->read_codec); + switch_core_session_set_write_codec(session, &a_engine->write_codec); + } + + a_engine->codec_params.fmtp_out = switch_core_session_strdup(session, a_engine->write_codec.fmtp_out); + + if (switch_rtp_ready(a_engine->rtp_session)) { + switch_rtp_set_default_payload(a_engine->rtp_session, a_engine->codec_params.pt); + } + + end: + if (resetting) { + switch_core_session_unlock_codec_write(session); + switch_core_session_unlock_codec_read(session); + } + + switch_core_media_set_video_codec(session, force); + + return status; +} + +//? +void switch_core_media_check_video_codecs(switch_core_session_t *session) +{ + switch_media_handle_t *smh; + + if (!(smh = session->media_handle)) { + return; + } + + if (smh->num_codecs && !switch_channel_test_flag(session->channel, CF_VIDEO_POSSIBLE)) { + int i; + smh->video_count = 0; + for (i = 0; i < smh->num_codecs; i++) { + + if (smh->codecs[i]->codec_type == SWITCH_CODEC_TYPE_VIDEO) { + smh->video_count++; + } + } + if (smh->video_count) { + switch_channel_set_flag(session->channel, CF_VIDEO_POSSIBLE); + } + } +} + + + +//? +SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *session, const char *r_sdp, uint8_t *proceed, + int reinvite, int codec_flags, switch_payload_t default_te) +{ + uint8_t match = 0; + switch_payload_t best_te = 0, te = 0, cng_pt = 0; + sdp_media_t *m; + sdp_attribute_t *attr; + int first = 0, last = 0; + int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0; + int sendonly = 0, recvonly = 0; + int greedy = 0, x = 0, skip = 0, mine = 0; + switch_channel_t *channel = switch_core_session_get_channel(session); + const char *val; + const char *crypto = NULL; + int got_crypto = 0, got_video_crypto = 0, got_audio = 0, got_avp = 0, got_video_avp = 0, got_video_savp = 0, got_savp = 0, got_udptl = 0; + int scrooge = 0; + sdp_parser_t *parser = NULL; + sdp_session_t *sdp; + int reneg = 1; + const switch_codec_implementation_t **codec_array; + int total_codecs; + switch_rtp_engine_t *a_engine, *v_engine; + switch_media_handle_t *smh; + + if (!(smh = session->media_handle)) { + return 0; + } + + a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO]; + v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO]; + + + codec_array = smh->codecs; + total_codecs = smh->num_codecs; + + + if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) { + return 0; + } + + if (!(sdp = sdp_session(parser))) { + sdp_parser_free(parser); + return 0; + } + + if (proceed) *proceed = 1; + + greedy = !!switch_media_handle_test_media_flag(smh, SCMF_CODEC_GREEDY); + scrooge = !!switch_media_handle_test_media_flag(smh, SCMF_CODEC_SCROOGE); + + if ((val = switch_channel_get_variable(channel, "sip_codec_negotiation"))) { + if (!strcasecmp(val, "generous")) { + greedy = 0; + scrooge = 0; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : generous\n" ); + } else if (!strcasecmp(val, "greedy")) { + greedy = 1; + scrooge = 0; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : greedy\n" ); + } else if (!strcasecmp(val, "scrooge")) { + scrooge = 1; + greedy = 1; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : scrooge\n" ); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation ignored invalid value : '%s' \n", val ); + } + } + + if ((smh->origin = switch_core_session_strdup(session, (char *) sdp->sdp_origin->o_username))) { + + if ((smh->params[SCM_AUTO_RTP_BUGS].intval & RTP_BUG_CISCO_SKIP_MARK_BIT_2833)) { + + if (strstr(smh->origin, "CiscoSystemsSIP-GW-UserAgent")) { + smh->params[SCM_MANUAL_RTP_BUGS].intval |= RTP_BUG_CISCO_SKIP_MARK_BIT_2833; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Activate Buggy RFC2833 Mode!\n"); + } + } + + if ((smh->params[SCM_AUTO_RTP_BUGS].intval & RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833)) { + if (strstr(smh->origin, "Sonus_UAC")) { + smh->params[SCM_MANUAL_RTP_BUGS].intval |= RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "Hello,\nI see you have a Sonus!\n" + "FYI, Sonus cannot follow the RFC on the proper way to send DTMF.\n" + "Sadly, my creator had to spend several hours figuring this out so I thought you'd like to know that!\n" + "Don't worry, DTMF will work but you may want to ask them to fix it......\n"); + } + } + } + + if ((val = switch_channel_get_variable(session->channel, "sip_liberal_dtmf")) && switch_true(val)) { + switch_channel_set_flag(session->channel, CF_LIBERAL_DTMF); + } + + if ((m = sdp->sdp_media) && + (m->m_mode == sdp_sendonly || m->m_mode == sdp_inactive || + (m->m_connections && m->m_connections->c_address && !strcmp(m->m_connections->c_address, "0.0.0.0")))) { + sendonly = 2; /* global sendonly always wins */ + } + + for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) { + if (zstr(attr->a_name)) { + continue; + } + + if (!strcasecmp(attr->a_name, "sendonly")) { + sendonly = 1; + switch_channel_set_variable(session->channel, "media_audio_mode", "recvonly"); + } else if (!strcasecmp(attr->a_name, "inactive")) { + sendonly = 1; + switch_channel_set_variable(session->channel, "media_audio_mode", "inactive"); + } else if (!strcasecmp(attr->a_name, "recvonly")) { + switch_channel_set_variable(session->channel, "media_audio_mode", "sendonly"); + recvonly = 1; + + if (switch_rtp_ready(a_engine->rtp_session)) { + switch_rtp_set_max_missed_packets(a_engine->rtp_session, 0); + a_engine->max_missed_hold_packets = 0; + a_engine->max_missed_packets = 0; + } else { + switch_channel_set_variable(session->channel, "rtp_timeout_sec", "0"); + switch_channel_set_variable(session->channel, "rtp_hold_timeout_sec", "0"); + } + } else if (sendonly < 2 && !strcasecmp(attr->a_name, "sendrecv")) { + sendonly = 0; + } else if (!strcasecmp(attr->a_name, "ptime")) { + dptime = atoi(attr->a_value); + } else if (!strcasecmp(attr->a_name, "maxptime")) { + dmaxptime = atoi(attr->a_value); + } + } + + if (sendonly != 1 && recvonly != 1) { + switch_channel_set_variable(session->channel, "media_audio_mode", NULL); + } + + + if (switch_media_handle_test_media_flag(smh, SCMF_DISABLE_HOLD) || + ((val = switch_channel_get_variable(session->channel, "sip_disable_hold")) && switch_true(val))) { + sendonly = 0; + } else { + + if (!smh->hold_laps) { + smh->hold_laps++; + if (switch_core_media_toggle_hold(session, sendonly)) { + reneg = switch_media_handle_test_media_flag(smh, SCMF_RENEG_ON_HOLD); + + if ((val = switch_channel_get_variable(session->channel, "sip_renegotiate_codec_on_hold"))) { + reneg = switch_true(val); + } + } + + } + } + + if (reneg) { + reneg = switch_media_handle_test_media_flag(smh, SCMF_RENEG_ON_REINVITE); + + if ((val = switch_channel_get_variable(session->channel, "sip_renegotiate_codec_on_reinvite"))) { + reneg = switch_true(val); + } + } + + if (!reneg && smh->num_negotiated_codecs) { + codec_array = smh->negotiated_codecs; + total_codecs = smh->num_negotiated_codecs; + } else if (reneg) { + smh->num_codecs = 0; + switch_core_media_prepare_codecs(session, SWITCH_FALSE); + codec_array = smh->codecs; + total_codecs = smh->num_codecs; + } + + if (switch_stristr("T38FaxFillBitRemoval:", r_sdp) || switch_stristr("T38FaxTranscodingMMR:", r_sdp) || + switch_stristr("T38FaxTranscodingJBIG:", r_sdp)) { + switch_channel_set_variable(session->channel, "t38_broken_boolean", "true"); + } + + switch_core_media_find_zrtp_hash(session, sdp); + switch_core_media_pass_zrtp_hash(session); + + for (m = sdp->sdp_media; m; m = m->m_next) { + sdp_connection_t *connection; + switch_core_session_t *other_session; + + ptime = dptime; + maxptime = dmaxptime; + + if (m->m_proto == sdp_proto_srtp) { + if (m->m_type == sdp_media_audio) { + got_savp++; + } else { + got_video_savp++; + } + } else if (m->m_proto == sdp_proto_rtp) { + if (m->m_type == sdp_media_audio) { + got_avp++; + } else { + got_video_avp++; + } + } else if (m->m_proto == sdp_proto_udptl) { + got_udptl++; + } + + if (got_udptl && m->m_type == sdp_media_image && m->m_port) { + switch_t38_options_t *t38_options = switch_core_media_process_udptl(session, sdp, m); + + if (switch_channel_test_app_flag_key("T38", session->channel, CF_APP_T38_NEGOTIATED)) { + match = 1; + goto done; + } + + if (switch_true(switch_channel_get_variable(channel, "refuse_t38"))) { + switch_channel_clear_app_flag_key("T38", session->channel, CF_APP_T38); + match = 0; + goto done; + } else { + const char *var = switch_channel_get_variable(channel, "t38_passthru"); + int pass = switch_media_handle_test_media_flag(smh, SCMF_T38_PASSTHRU); + + + if (switch_channel_test_app_flag_key("T38", session->channel, CF_APP_T38)) { + if (proceed) *proceed = 0; + } + + if (var) { + if (!(pass = switch_true(var))) { + if (!strcasecmp(var, "once")) { + pass = 2; + } + } + } + + if ((pass == 2 && switch_media_handle_test_media_flag(smh, SCMF_T38_PASSTHRU)) + || !reinvite || + + switch_channel_test_flag(session->channel, CF_PROXY_MODE) || + switch_channel_test_flag(session->channel, CF_PROXY_MEDIA) || + !switch_rtp_ready(a_engine->rtp_session)) { + pass = 0; + } + + if (pass && switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { + switch_channel_t *other_channel = switch_core_session_get_channel(other_session); + switch_core_session_message_t *msg; + char *remote_host = switch_rtp_get_remote_host(a_engine->rtp_session); + switch_port_t remote_port = switch_rtp_get_remote_port(a_engine->rtp_session); + char tmp[32] = ""; + + if (switch_true(switch_channel_get_variable(session->channel, "t38_broken_boolean")) && + switch_true(switch_channel_get_variable(session->channel, "t38_pass_broken_boolean"))) { + switch_channel_set_variable(other_channel, "t38_broken_boolean", "true"); + } + + a_engine->codec_params.remote_sdp_ip = switch_core_session_strdup(session, t38_options->remote_ip); + a_engine->codec_params.remote_sdp_port = t38_options->remote_port; + + if (remote_host && remote_port && !strcmp(remote_host, a_engine->codec_params.remote_sdp_ip) && remote_port == a_engine->codec_params.remote_sdp_port) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n", + switch_channel_get_name(session->channel)); + } else { + const char *err = NULL; + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n", + switch_channel_get_name(session->channel), + remote_host, remote_port, a_engine->codec_params.remote_sdp_ip, a_engine->codec_params.remote_sdp_port); + + switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->codec_params.remote_sdp_port); + switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, a_engine->codec_params.remote_sdp_ip); + switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp); + + if (switch_rtp_set_remote_address(a_engine->rtp_session, a_engine->codec_params.remote_sdp_ip, + a_engine->codec_params.remote_sdp_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err); + switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); + } + + } + + + + switch_core_media_copy_t38_options(t38_options, other_session); + + switch_media_handle_set_media_flag(smh, SCMF_T38_PASSTHRU); + switch_media_handle_set_media_flag(other_session->media_handle, SCMF_T38_PASSTHRU); + + msg = switch_core_session_alloc(other_session, sizeof(*msg)); + msg->message_id = SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA; + msg->from = __FILE__; + msg->string_arg = switch_core_session_strdup(other_session, r_sdp); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Passing T38 req to other leg.\n%s\n", r_sdp); + switch_core_session_queue_message(other_session, msg); + switch_core_session_rwunlock(other_session); + } + } + + + /* do nothing here, mod_fax will trigger a response (if it's listening =/) */ + match = 1; + goto done; + } else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) { + sdp_rtpmap_t *map; + + for (attr = m->m_attributes; attr; attr = attr->a_next) { + + if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) { + switch_channel_set_variable(session->channel, "sip_remote_audio_rtcp_port", attr->a_value); + } else if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) { + ptime = atoi(attr->a_value); + } else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) { + maxptime = atoi(attr->a_value); + } else if (!got_crypto && !strcasecmp(attr->a_name, "crypto") && !zstr(attr->a_value)) { + int crypto_tag; + + if (!(smh->ndlb & SM_NDLB_ALLOW_CRYPTO_IN_AVP) && + !switch_true(switch_channel_get_variable(session->channel, "sip_allow_crypto_in_avp"))) { + if (m->m_proto != sdp_proto_srtp) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "a=crypto in RTP/AVP, refer to rfc3711\n"); + match = 0; + goto done; + } + } + + crypto = attr->a_value; + crypto_tag = atoi(crypto); + + got_crypto = switch_core_session_check_incoming_crypto(session, + "rtp_has_crypto", SWITCH_MEDIA_TYPE_AUDIO, crypto, crypto_tag); + + } + } + + if (got_crypto && !got_avp) { + switch_channel_set_variable(session->channel, "rtp_crypto_mandatory", "true"); + switch_channel_set_variable(session->channel, "rtp_secure_media", "true"); + } + + connection = sdp->sdp_connection; + if (m->m_connections) { + connection = m->m_connections; + } + + if (!connection) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n"); + match = 0; + break; + } + + greed: + x = 0; + + if (a_engine->codec_params.rm_encoding && !(switch_media_handle_test_media_flag(smh, SCMF_LIBERAL_DTMF) || + switch_channel_test_flag(session->channel, CF_LIBERAL_DTMF))) { // && !reinvite) { + char *remote_host = a_engine->codec_params.remote_sdp_ip; + switch_port_t remote_port = a_engine->codec_params.remote_sdp_port; + int same = 0; + + if (switch_rtp_ready(a_engine->rtp_session)) { + remote_host = switch_rtp_get_remote_host(a_engine->rtp_session); + remote_port = switch_rtp_get_remote_port(a_engine->rtp_session); + } + + for (map = m->m_rtpmaps; map; map = map->rm_next) { + if ((zstr(map->rm_encoding) || (smh->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { + match = (map->rm_pt == a_engine->codec_params.pt) ? 1 : 0; + } else { + match = strcasecmp(switch_str_nil(map->rm_encoding), a_engine->codec_params.iananame) ? 0 : 1; + } + + if (match && connection->c_address && remote_host && !strcmp(connection->c_address, remote_host) && m->m_port == remote_port) { + same = 1; + } else { + same = 0; + break; + } + } + + if (same) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "Our existing sdp is still good [%s %s:%d], let's keep it.\n", + a_engine->codec_params.rm_encoding, a_engine->codec_params.remote_sdp_ip, a_engine->codec_params.remote_sdp_port); + got_audio = 1; + } else { + match = 0; + got_audio = 0; + } + } + + for (map = m->m_rtpmaps; map; map = map->rm_next) { + int32_t i; + uint32_t near_rate = 0; + const switch_codec_implementation_t *mimp = NULL, *near_match = NULL; + const char *rm_encoding; + uint32_t map_bit_rate = 0; + int codec_ms = 0; + switch_codec_fmtp_t codec_fmtp = { 0 }; + + if (x++ < skip) { + continue; + } + + if (!(rm_encoding = map->rm_encoding)) { + rm_encoding = ""; + } + + if (!strcasecmp(rm_encoding, "telephone-event")) { + if (!best_te || map->rm_rate == a_engine->codec_params.rm_rate) { + best_te = (switch_payload_t) map->rm_pt; + } + } + + if (!switch_media_handle_test_media_flag(smh, SCMF_SUPPRESS_CNG) && !cng_pt && !strcasecmp(rm_encoding, "CN")) { + cng_pt = (switch_payload_t) map->rm_pt; + if (a_engine->rtp_session) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt); + switch_rtp_set_cng_pt(a_engine->rtp_session, smh->cng_pt); + } + } + + if (match) { + continue; + } + + if (greedy) { + first = mine; + last = first + 1; + } else { + first = 0; + last = smh->num_codecs; + } + + codec_ms = ptime; + + if (maxptime && (!codec_ms || codec_ms > maxptime)) { + codec_ms = maxptime; + } + + if (!codec_ms) { + codec_ms = switch_default_ptime(rm_encoding, map->rm_pt); + } + + map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt); + + if (!ptime && !strcasecmp(map->rm_encoding, "g723")) { + codec_ms = 30; + } + + if (zstr(map->rm_fmtp)) { + if (!strcasecmp(map->rm_encoding, "ilbc")) { + codec_ms = 30; + map_bit_rate = 13330; + } + } else { + if ((switch_core_codec_parse_fmtp(map->rm_encoding, map->rm_fmtp, map->rm_rate, &codec_fmtp)) == SWITCH_STATUS_SUCCESS) { + if (codec_fmtp.bits_per_second) { + map_bit_rate = codec_fmtp.bits_per_second; + } + if (codec_fmtp.microseconds_per_packet) { + codec_ms = (codec_fmtp.microseconds_per_packet / 1000); + } + } + } + + + for (i = first; i < last && i < total_codecs; i++) { + const switch_codec_implementation_t *imp = codec_array[i]; + uint32_t bit_rate = imp->bits_per_second; + uint32_t codec_rate = imp->samples_per_second; + if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) { + continue; + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d:%u:%d:%u]/[%s:%d:%u:%d:%u]\n", + rm_encoding, map->rm_pt, (int) map->rm_rate, codec_ms, map_bit_rate, + imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate); + if ((zstr(map->rm_encoding) || (smh->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { + match = (map->rm_pt == imp->ianacode) ? 1 : 0; + } else { + match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1; + } + + if (match && bit_rate && map_bit_rate && map_bit_rate != bit_rate && strcasecmp(map->rm_encoding, "ilbc")) { + /* if a bit rate is specified and doesn't match, this is not a codec match, except for ILBC */ + match = 0; + } + + if (match && map->rm_rate && codec_rate && map->rm_rate != codec_rate && (!strcasecmp(map->rm_encoding, "pcma") || !strcasecmp(map->rm_encoding, "pcmu"))) { + /* if the sampling rate is specified and doesn't match, this is not a codec match for G.711 */ + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sampling rates have to match for G.711\n"); + match = 0; + } + + if (match) { + if (scrooge) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "Bah HUMBUG! Sticking with %s@%uh@%ui\n", + imp->iananame, imp->samples_per_second, imp->microseconds_per_packet / 1000); + } else { + if ((ptime && codec_ms && codec_ms * 1000 != imp->microseconds_per_packet) || map->rm_rate != codec_rate) { + near_rate = map->rm_rate; + near_match = imp; + match = 0; + continue; + } + } + mimp = imp; + break; + } + } + + if (!match && near_match) { + const switch_codec_implementation_t *search[1]; + char *prefs[1]; + char tmp[80]; + int num; + + switch_snprintf(tmp, sizeof(tmp), "%s@%uh@%ui", near_match->iananame, near_rate ? near_rate : near_match->samples_per_second, + codec_ms); + + prefs[0] = tmp; + num = switch_loadable_module_get_codecs_sorted(search, 1, prefs, 1); + + if (num) { + mimp = search[0]; + } else { + mimp = near_match; + } + + if (!maxptime || mimp->microseconds_per_packet / 1000 <= maxptime) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Substituting codec %s@%ui@%uh\n", + mimp->iananame, mimp->microseconds_per_packet / 1000, mimp->samples_per_second); + match = 1; + } else { + mimp = NULL; + match = 0; + } + + } + + if (!match && greedy) { + skip++; + continue; + } + + if (mimp) { + char tmp[50]; + const char *mirror = switch_channel_get_variable(session->channel, "rtp_mirror_remote_audio_codec_payload"); + + a_engine->codec_params.rm_encoding = switch_core_session_strdup(session, (char *) map->rm_encoding); + a_engine->codec_params.iananame = switch_core_session_strdup(session, (char *) mimp->iananame); + a_engine->codec_params.pt = (switch_payload_t) map->rm_pt; + a_engine->codec_params.rm_rate = mimp->samples_per_second; + a_engine->codec_params.codec_ms = mimp->microseconds_per_packet / 1000; + a_engine->codec_params.bitrate = mimp->bits_per_second; + a_engine->codec_params.remote_sdp_ip = switch_core_session_strdup(session, (char *) connection->c_address); + a_engine->codec_params.rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp); + a_engine->codec_params.remote_sdp_port = (switch_port_t) m->m_port; + a_engine->codec_params.agreed_pt = (switch_payload_t) map->rm_pt; + smh->num_negotiated_codecs = 0; + smh->negotiated_codecs[smh->num_negotiated_codecs++] = mimp; + switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->codec_params.remote_sdp_port); + switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, a_engine->codec_params.remote_sdp_ip); + switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp); + a_engine->codec_params.recv_pt = (switch_payload_t)map->rm_pt; + + if (!switch_true(mirror) && + switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && + (!reinvite || switch_media_handle_test_media_flag(smh, SCMF_RENEG_ON_REINVITE))) { + switch_core_media_get_offered_pt(session, mimp, &a_engine->codec_params.recv_pt); + } + + switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->codec_params.recv_pt); + switch_channel_set_variable(session->channel, "rtp_audio_recv_pt", tmp); + + } + + if (match) { + if (switch_core_media_set_codec(session, 1, codec_flags) == SWITCH_STATUS_SUCCESS) { + got_audio = 1; + } else { + match = 0; + } + } + } + + if (!best_te && (switch_media_handle_test_media_flag(smh, SCMF_LIBERAL_DTMF) || switch_channel_test_flag(session->channel, CF_LIBERAL_DTMF))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "No 2833 in SDP. Liberal DTMF mode adding %d as telephone-event.\n", default_te); + best_te = default_te; + } + + if (best_te) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { + te = smh->te = (switch_payload_t) best_te; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send payload to %u\n", best_te); + if (a_engine->rtp_session) { + switch_rtp_set_telephony_event(a_engine->rtp_session, (switch_payload_t) best_te); + switch_channel_set_variable_printf(session->channel, "sip_2833_send_payload", "%d", best_te); + } + } else { + te = smh->recv_te = smh->te = (switch_payload_t) best_te; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send/recv payload to %u\n", te); + if (a_engine->rtp_session) { + switch_rtp_set_telephony_event(a_engine->rtp_session, te); + switch_channel_set_variable_printf(session->channel, "sip_2833_send_payload", "%d", te); + switch_rtp_set_telephony_recv_event(a_engine->rtp_session, te); + switch_channel_set_variable_printf(session->channel, "sip_2833_recv_payload", "%d", te); + } + } + } else { + /* by default, use SIP INFO if 2833 is not in the SDP */ + if (!switch_false(switch_channel_get_variable(channel, "sip_info_when_no_2833"))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No 2833 in SDP. Disable 2833 dtmf and switch to INFO\n"); + switch_channel_set_variable(session->channel, "dtmf_type", "info"); + smh->dtmf_type = DTMF_INFO; + te = smh->recv_te = smh->te = 0; + } else { + switch_channel_set_variable(session->channel, "dtmf_type", "none"); + smh->dtmf_type = DTMF_NONE; + te = smh->recv_te = smh->te = 0; + } + } + + + if (!match && greedy && mine < total_codecs) { + mine++; + skip = 0; + goto greed; + } + + } else if (m->m_type == sdp_media_video && m->m_port) { + sdp_rtpmap_t *map; + const char *rm_encoding; + const switch_codec_implementation_t *mimp = NULL; + int vmatch = 0, i; + switch_channel_set_variable(session->channel, "video_possible", "true"); + + connection = sdp->sdp_connection; + if (m->m_connections) { + connection = m->m_connections; + } + + if (!connection) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n"); + match = 0; + break; + } + + for (map = m->m_rtpmaps; map; map = map->rm_next) { + + for (attr = m->m_attributes; attr; attr = attr->a_next) { + if (!strcasecmp(attr->a_name, "framerate") && attr->a_value) { + //framerate = atoi(attr->a_value); + } + if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) { + switch_channel_set_variable(session->channel, "sip_remote_video_rtcp_port", attr->a_value); + + } else if (!got_crypto && !strcasecmp(attr->a_name, "crypto") && !zstr(attr->a_value)) { + int crypto_tag; + + if (!(smh->ndlb & SM_NDLB_ALLOW_CRYPTO_IN_AVP) && + !switch_true(switch_channel_get_variable(session->channel, "sip_allow_crypto_in_avp"))) { + if (m->m_proto != sdp_proto_srtp) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "a=crypto in RTP/AVP, refer to rfc3711\n"); + match = 0; + goto done; + } + } + + crypto = attr->a_value; + crypto_tag = atoi(crypto); + + got_video_crypto = switch_core_session_check_incoming_crypto(session, + "rtp_has_video_crypto", + SWITCH_MEDIA_TYPE_VIDEO, crypto, crypto_tag); + + } + } + + if (got_video_crypto && !got_video_avp) { + switch_channel_set_variable(session->channel, "rtp_crypto_mandatory", "true"); + switch_channel_set_variable(session->channel, "rtp_secure_media", "true"); + } + + if (!(rm_encoding = map->rm_encoding)) { + rm_encoding = ""; + } + + for (i = 0; i < total_codecs; i++) { + const switch_codec_implementation_t *imp = codec_array[i]; + + if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) { + continue; + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Video Codec Compare [%s:%d]/[%s:%d]\n", + rm_encoding, map->rm_pt, imp->iananame, imp->ianacode); + if ((zstr(map->rm_encoding) || (smh->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { + vmatch = (map->rm_pt == imp->ianacode) ? 1 : 0; + } else { + vmatch = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1; + } + + + if (vmatch && (map->rm_rate == imp->samples_per_second)) { + mimp = imp; + break; + } else { + vmatch = 0; + } + } + + if (mimp) { + if ((v_engine->codec_params.rm_encoding = switch_core_session_strdup(session, (char *) rm_encoding))) { + char tmp[50]; + const char *mirror = switch_channel_get_variable(session->channel, "sip_mirror_remote_video_codec_payload"); + + v_engine->codec_params.pt = (switch_payload_t) map->rm_pt; + v_engine->codec_params.rm_rate = map->rm_rate; + v_engine->codec_params.codec_ms = mimp->microseconds_per_packet / 1000; + v_engine->codec_params.remote_sdp_ip = switch_core_session_strdup(session, (char *) connection->c_address); + v_engine->codec_params.rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp); + v_engine->codec_params.remote_sdp_port = (switch_port_t) m->m_port; + v_engine->codec_params.agreed_pt = (switch_payload_t) map->rm_pt; + switch_snprintf(tmp, sizeof(tmp), "%d", v_engine->codec_params.remote_sdp_port); + switch_channel_set_variable(session->channel, SWITCH_REMOTE_VIDEO_IP_VARIABLE, v_engine->codec_params.remote_sdp_ip); + switch_channel_set_variable(session->channel, SWITCH_REMOTE_VIDEO_PORT_VARIABLE, tmp); + switch_channel_set_variable(session->channel, "sip_video_fmtp", v_engine->codec_params.rm_fmtp); + switch_snprintf(tmp, sizeof(tmp), "%d", v_engine->codec_params.agreed_pt); + switch_channel_set_variable(session->channel, "sip_video_pt", tmp); + switch_core_media_check_video_codecs(session); + + v_engine->codec_params.recv_pt = (switch_payload_t)map->rm_pt; + + if (!switch_true(mirror) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { + switch_core_media_get_offered_pt(session, mimp, &v_engine->codec_params.recv_pt); + } + + switch_snprintf(tmp, sizeof(tmp), "%d", v_engine->codec_params.recv_pt); + switch_channel_set_variable(session->channel, "sip_video_recv_pt", tmp); + if (!match && vmatch) match = 1; + + break; + } else { + vmatch = 0; + } + } + } + } + } + + done: + + if (parser) { + sdp_parser_free(parser); + } + + smh->cng_pt = cng_pt; + + return match; +} + +//? + +SWITCH_DECLARE(int) switch_core_media_toggle_hold(switch_core_session_t *session, int sendonly) +{ + int changed = 0; + switch_rtp_engine_t *a_engine;//, *v_engine; + switch_media_handle_t *smh; + + if (!(smh = session->media_handle)) { + return 0; + } + + a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO]; + //v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO]; + + if (switch_channel_test_flag(session->channel, CF_SLA_BARGE) || switch_channel_test_flag(session->channel, CF_SLA_BARGING)) { + switch_channel_mark_hold(session->channel, sendonly); + return 0; + } + + if (sendonly && switch_channel_test_flag(session->channel, CF_ANSWERED)) { + if (!switch_channel_test_flag(session->channel, CF_PROTO_HOLD)) { + const char *stream; + const char *msg = "hold"; + const char *info = switch_channel_get_variable(session->channel, "presence_call_info"); + + if (info) { + if (switch_stristr("private", info)) { + msg = "hold-private"; + } + } + + + switch_channel_set_flag(session->channel, CF_PROTO_HOLD); + switch_channel_mark_hold(session->channel, SWITCH_TRUE); + switch_channel_presence(session->channel, "unknown", msg, NULL); + changed = 1; + + if (a_engine->max_missed_hold_packets) { + switch_rtp_set_max_missed_packets(a_engine->rtp_session, a_engine->max_missed_hold_packets); + } + + if (!(stream = switch_channel_get_hold_music(session->channel))) { + stream = "local_stream://moh"; + } + + if (stream && strcasecmp(stream, "silence")) { + if (!strcasecmp(stream, "indicate_hold")) { + switch_channel_set_flag(session->channel, CF_SUSPEND); + switch_channel_set_flag(session->channel, CF_HOLD); + switch_ivr_hold_uuid(switch_channel_get_partner_uuid(session->channel), NULL, 0); + } else { + switch_ivr_broadcast(switch_channel_get_partner_uuid(session->channel), stream, + SMF_ECHO_ALEG | SMF_LOOP | SMF_PRIORITY); + switch_yield(250000); + } + } + } + } else { + if (switch_channel_test_flag(session->channel, CF_HOLD_LOCK)) { + switch_channel_set_flag(session->channel, CF_PROTO_HOLD); + switch_channel_mark_hold(session->channel, SWITCH_TRUE); + changed = 1; + } + + switch_channel_clear_flag(session->channel, CF_HOLD_LOCK); + + if (switch_channel_test_flag(session->channel, CF_PROTO_HOLD)) { + const char *uuid; + switch_core_session_t *b_session; + + switch_yield(250000); + + if (a_engine->max_missed_packets) { + switch_rtp_reset_media_timer(a_engine->rtp_session); + switch_rtp_set_max_missed_packets(a_engine->rtp_session, a_engine->max_missed_packets); + } + + if ((uuid = switch_channel_get_partner_uuid(session->channel)) && (b_session = switch_core_session_locate(uuid))) { + switch_channel_t *b_channel = switch_core_session_get_channel(b_session); + + if (switch_channel_test_flag(session->channel, CF_HOLD)) { + switch_ivr_unhold(b_session); + switch_channel_clear_flag(session->channel, CF_SUSPEND); + switch_channel_clear_flag(session->channel, CF_HOLD); + } else { + switch_channel_stop_broadcast(b_channel); + switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL); + } + switch_core_session_rwunlock(b_session); + } + + switch_channel_clear_flag(session->channel, CF_PROTO_HOLD); + switch_channel_mark_hold(session->channel, SWITCH_FALSE); + switch_channel_presence(session->channel, "unknown", "unhold", NULL); + changed = 1; + } + } + + return changed; +} + + + + /* For Emacs: * Local Variables: * mode:c