]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
some refactoring and plumbing for 1.4
authorAnthony Minessale <anthm@freeswitch.org>
Tue, 15 Oct 2013 21:24:32 +0000 (02:24 +0500)
committerAnthony Minessale <anthm@freeswitch.org>
Tue, 15 Oct 2013 21:24:32 +0000 (02:24 +0500)
37 files changed:
src/include/private/switch_core_pvt.h
src/include/switch_channel.h
src/include/switch_core.h
src/include/switch_core_media.h
src/include/switch_event.h
src/include/switch_json.h
src/include/switch_loadable_module.h
src/include/switch_module_interfaces.h
src/include/switch_rtp.h
src/include/switch_types.h
src/mod/endpoints/mod_alsa/mod_alsa.c
src/mod/endpoints/mod_dingaling/mod_dingaling.c
src/mod/endpoints/mod_gsmopen/alsa_nogsmlib_nocplusplus/mod_gsmopen/mod_gsmopen.c
src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp
src/mod/endpoints/mod_h323/mod_h323.cpp
src/mod/endpoints/mod_loopback/mod_loopback.c
src/mod/endpoints/mod_opal/mod_opal.cpp
src/mod/endpoints/mod_portaudio/mod_portaudio.c
src/mod/endpoints/mod_reference/mod_reference.c
src/mod/endpoints/mod_rtmp/mod_rtmp.c
src/mod/endpoints/mod_skinny/mod_skinny.c
src/mod/endpoints/mod_skypopen/mod_skypopen.c
src/mod/endpoints/mod_sofia/mod_sofia.c
src/mod/endpoints/mod_sofia/rtp.c
src/mod/endpoints/mod_sofia/sofia_glue.c
src/mod/endpoints/mod_unicall/mod_unicall.c
src/switch_channel.c
src/switch_core_codec.c
src/switch_core_io.c
src/switch_core_media.c
src/switch_core_session.c
src/switch_core_sqldb.c
src/switch_core_state_machine.c
src/switch_event.c
src/switch_json.c
src/switch_loadable_module.c
src/switch_rtp.c

index f6d3474386e513394f5ee982bbd47c81da741c7a..bff9b72a78af4caacc91e3496212d666e7040ae7 100644 (file)
@@ -144,7 +144,7 @@ struct switch_core_session {
        int stream_count;
 
        char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
-       void *private_info;
+       void *private_info[SWITCH_CORE_SESSION_MAX_PRIVATES];
        switch_queue_t *event_queue;
        switch_queue_t *message_queue;
        switch_queue_t *signal_data_queue;
index 2e53ef6107dfcbc650561d796a7beec9b5626c8e..234b692114f2158187cd8c9dbe6567512ac5fdb1 100644 (file)
@@ -633,6 +633,8 @@ SWITCH_DECLARE(int) switch_channel_test_app_flag_key(const char *app, switch_cha
 SWITCH_DECLARE(void) switch_channel_set_bridge_time(switch_channel_t *channel);
 SWITCH_DECLARE(void) switch_channel_set_hangup_time(switch_channel_t *channel);
 SWITCH_DECLARE(switch_call_direction_t) switch_channel_direction(switch_channel_t *channel);
+SWITCH_DECLARE(void) switch_channel_set_direction(switch_channel_t *channel, switch_call_direction_t direction);
+
 SWITCH_DECLARE(switch_core_session_t *) switch_channel_get_session(switch_channel_t *channel);
 SWITCH_DECLARE(char *) switch_channel_get_flag_string(switch_channel_t *channel);
 SWITCH_DECLARE(char *) switch_channel_get_cap_string(switch_channel_t *channel);
index 064ab563245f36a0c3d7ec881fd52a1dd60af033..11340c211c2e972ff762b9b8c54abe30576faf38 100644 (file)
@@ -1070,7 +1070,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_receive_event(_In_ switch_co
   \param session the session to retrieve from
   \return a pointer to the private data
 */
-SWITCH_DECLARE(void *) switch_core_session_get_private(_In_ switch_core_session_t *session);
+SWITCH_DECLARE(void *) switch_core_session_get_private_class(_In_ switch_core_session_t *session, _In_ switch_pvt_class_t index);
+#define switch_core_session_get_private(_s) switch_core_session_get_private_class(_s, SWITCH_PVT_PRIMARY)
 
 /*! 
   \brief Add private user data to a session
@@ -1078,7 +1079,8 @@ SWITCH_DECLARE(void *) switch_core_session_get_private(_In_ switch_core_session_
   \param private_info the used data to add
   \return SWITCH_STATUS_SUCCESS if data is added
 */
-SWITCH_DECLARE(switch_status_t) switch_core_session_set_private(_In_ switch_core_session_t *session, _In_ void *private_info);
+SWITCH_DECLARE(switch_status_t) switch_core_session_set_private_class(_In_ switch_core_session_t *session, _In_ void *private_info, _In_ switch_pvt_class_t index);
+#define switch_core_session_set_private(_s, _p) switch_core_session_set_private_class(_s, _p, SWITCH_PVT_PRIMARY)
 
 /*!
   \brief Add a logical stream to a session
@@ -2575,6 +2577,7 @@ SWITCH_DECLARE(int) switch_system(const char *cmd, switch_bool_t wait);
 SWITCH_DECLARE(int) switch_stream_system_fork(const char *cmd, switch_stream_handle_t *stream);
 SWITCH_DECLARE(int) switch_stream_system(const char *cmd, switch_stream_handle_t *stream);
 
+SWITCH_DECLARE(switch_call_direction_t) switch_ice_direction(switch_core_session_t *session);
 
 SWITCH_END_EXTERN_C
 #endif
index 122f9f2b65e381906e1654d379c35eb953bce644..9641718f073523b4f9282f98baa1f3e479513de9 100644 (file)
@@ -207,6 +207,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_write_frame(switch_core_sessio
 SWITCH_DECLARE(int) switch_core_media_check_nat(switch_media_handle_t *smh, const char *network_ip);
 
 SWITCH_DECLARE(switch_status_t) switch_core_media_choose_port(switch_core_session_t *session, switch_media_type_t type, int force);
+SWITCH_DECLARE(switch_status_t) switch_core_media_choose_ports(switch_core_session_t *session, switch_bool_t audio, switch_bool_t video);
 SWITCH_DECLARE(void) switch_core_media_check_dtmf_type(switch_core_session_t *session);
 SWITCH_DECLARE(void) switch_core_media_absorb_sdp(switch_core_session_t *session);
 SWITCH_DECLARE(switch_status_t) switch_core_media_proxy_remote_addr(switch_core_session_t *session, const char *sdp_str);
@@ -219,6 +220,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
 SWITCH_DECLARE(void)switch_core_media_set_local_sdp(switch_core_session_t *session, const char *sdp_str, switch_bool_t dup);
 SWITCH_DECLARE(void) switch_core_media_patch_sdp(switch_core_session_t *session);
 SWITCH_DECLARE(void) switch_core_media_set_udptl_image_sdp(switch_core_session_t *session, switch_t38_options_t *t38_options, int insist);
+SWITCH_DECLARE(switch_core_media_params_t *) switch_core_media_get_mparams(switch_media_handle_t *smh);
 SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *session, switch_bool_t force);
 SWITCH_DECLARE(void) switch_core_media_start_udptl(switch_core_session_t *session, switch_t38_options_t *t38_options);
 SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg);
@@ -254,6 +256,7 @@ SWITCH_DECLARE(void) switch_core_media_init(void);
 SWITCH_DECLARE(void) switch_core_media_deinit(void);
 SWITCH_DECLARE(void) switch_core_media_set_stats(switch_core_session_t *session);
 SWITCH_DECLARE(void) switch_core_session_wake_video_thread(switch_core_session_t *session);
+SWITCH_DECLARE(void) switch_core_session_clear_crypto(switch_core_session_t *session);
 
 SWITCH_END_EXTERN_C
 #endif
index 48c942dfaa05af72db999baa9badbeb0b4e5fb70..be60c17cd908766d04dd0e2f63c001df7965fbaf 100644 (file)
@@ -309,10 +309,11 @@ SWITCH_DECLARE(switch_status_t) switch_event_free_subclass_detailed(const char *
   \return SWITCH_STATUS_SUCCESS if the operation was successful
   \note you must free the resulting string when you are finished with it
 */
-SWITCH_DECLARE(switch_status_t) switch_event_binary_deserialize(switch_event_t **eventp, void **data, switch_size_t len, switch_bool_t destroy);
+SWITCH_DECLARE(switch_status_t) switch_event_binary_deserialize(switch_event_t **eventp, void **data, switch_size_t len, switch_bool_t duplicate);
 SWITCH_DECLARE(switch_status_t) switch_event_binary_serialize(switch_event_t *event, void **data, switch_size_t *len);
 SWITCH_DECLARE(switch_status_t) switch_event_serialize(switch_event_t *event, char **str, switch_bool_t encode);
 SWITCH_DECLARE(switch_status_t) switch_event_serialize_json(switch_event_t *event, char **str);
+SWITCH_DECLARE(switch_status_t) switch_event_serialize_json_obj(switch_event_t *event, cJSON **json);
 SWITCH_DECLARE(switch_status_t) switch_event_create_json(switch_event_t **event, const char *json);
 SWITCH_DECLARE(switch_status_t) switch_event_create_brackets(char *data, char a, char b, char c, switch_event_t **event, char **new_data, switch_bool_t dup);
 SWITCH_DECLARE(switch_status_t) switch_event_create_array_pair(switch_event_t **event, char **names, char **vals, int len);
@@ -420,8 +421,38 @@ SWITCH_DECLARE(void) switch_event_deliver(switch_event_t **event);
 SWITCH_DECLARE(char *) switch_event_build_param_string(switch_event_t *event, const char *prefix, switch_hash_t *vars_map);
 SWITCH_DECLARE(int) switch_event_check_permission_list(switch_event_t *list, const char *name);
 SWITCH_DECLARE(void) switch_event_add_presence_data_cols(switch_channel_t *channel, switch_event_t *event, const char *prefix);
+SWITCH_DECLARE(void) switch_json_add_presence_data_cols(switch_event_t *event, cJSON *json, const char *prefix);
+
 SWITCH_DECLARE(void) switch_event_launch_dispatch_threads(uint32_t max);
 
+SWITCH_DECLARE(uint32_t) switch_event_channel_broadcast(const char *event_channel, cJSON **json, const char *key, switch_event_channel_id_t id);
+SWITCH_DECLARE(uint32_t) switch_event_channel_unbind(const char *event_channel, switch_event_channel_func_t func);
+SWITCH_DECLARE(switch_status_t) switch_event_channel_bind(const char *event_channel, switch_event_channel_func_t func, switch_event_channel_id_t *id);
+                                                                                                                 
+
+typedef void (*switch_live_array_command_handler_t)(switch_live_array_t *la, const char *cmd, const char *sessid, cJSON *jla, void *user_data);
+
+#define NO_EVENT_CHANNEL_ID 0
+#define SWITCH_EVENT_CHANNEL_GLOBAL "__global__"
+
+SWITCH_DECLARE(switch_status_t) switch_live_array_clear(switch_live_array_t *la);
+SWITCH_DECLARE(switch_status_t) switch_live_array_bootstrap(switch_live_array_t *la, const char *sessid, switch_event_channel_id_t channel_id);
+SWITCH_DECLARE(switch_status_t) switch_live_array_destroy(switch_live_array_t **live_arrayP);
+SWITCH_DECLARE(switch_status_t) switch_live_array_create(const char *event_channel, const char *name,
+                                                                                                                switch_event_channel_id_t channel_id, switch_live_array_t **live_arrayP);
+SWITCH_DECLARE(cJSON *) switch_live_array_get(switch_live_array_t *la, const char *name);
+SWITCH_DECLARE(cJSON *) switch_live_array_get_idx(switch_live_array_t *la, int idx);
+SWITCH_DECLARE(switch_status_t) switch_live_array_del(switch_live_array_t *la, const char *name);
+SWITCH_DECLARE(switch_status_t) switch_live_array_add(switch_live_array_t *la, const char *name, int index, cJSON **obj, switch_bool_t destroy);
+SWITCH_DECLARE(switch_status_t) switch_live_array_visible(switch_live_array_t *la, switch_bool_t visible, switch_bool_t force);
+SWITCH_DECLARE(switch_bool_t) switch_live_array_isnew(switch_live_array_t *la);
+SWITCH_DECLARE(void) switch_live_array_lock(switch_live_array_t *la);
+SWITCH_DECLARE(void) switch_live_array_unlock(switch_live_array_t *la);
+SWITCH_DECLARE(void) switch_live_array_set_user_data(switch_live_array_t *la, void *user_data);
+SWITCH_DECLARE(void) switch_live_array_set_command_handler(switch_live_array_t *la, switch_live_array_command_handler_t command_handler);
+SWITCH_DECLARE(void) switch_live_array_parse_json(cJSON *json, switch_event_channel_id_t channel_id);
+
+
 ///\}
 
 SWITCH_END_EXTERN_C
index 00f4e23df4be034d9bb29f7b6e43dc5e067ce4e4..e1d7f1e51b2371d3db9eade1f12339098d9f9d4b 100755 (executable)
@@ -76,7 +76,8 @@ SWITCH_DECLARE(int)     cJSON_GetArraySize(cJSON *array);
 /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
 SWITCH_DECLARE(cJSON *)cJSON_GetArrayItem(cJSON *array,int item);
 /* Get item "string" from object. Case insensitive. */
-SWITCH_DECLARE(cJSON *)cJSON_GetObjectItem(cJSON *object,const char *string);
+SWITCH_DECLARE(cJSON *)cJSON_GetObjectItem(const cJSON *object,const char *string);
+SWITCH_DECLARE(const char *)cJSON_GetObjectCstr(const cJSON *object, const char *string);
 
 /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
 SWITCH_DECLARE(const char *)cJSON_GetErrorPtr(void);
@@ -127,6 +128,55 @@ SWITCH_DECLARE(cJSON *) cJSON_Duplicate(cJSON *item,int recurse);
 #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
 #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
 
+SWITCH_DECLARE(cJSON *) cJSON_CreateStringPrintf(const char *fmt, ...);
+
+static inline cJSON *json_add_child_obj(cJSON *json, const char *name, cJSON *obj)
+{
+       cJSON *new_json = NULL;
+
+       switch_assert(json);
+
+       if (obj) {
+               new_json = obj;
+       } else {
+               new_json = cJSON_CreateObject();
+       }
+
+       switch_assert(new_json);
+
+       cJSON_AddItemToObject(json, name, new_json);
+
+       return new_json;
+}
+
+static inline cJSON *json_add_child_array(cJSON *json, const char *name)
+{
+       cJSON *new_json = NULL;
+
+       switch_assert(json);
+
+       new_json = cJSON_CreateArray();
+       switch_assert(new_json);
+
+       cJSON_AddItemToObject(json, name, new_json);
+
+       return new_json;
+}
+
+static inline cJSON *json_add_child_string(cJSON *json, const char *name, const char *val)
+{
+       cJSON *new_json = NULL;
+
+       switch_assert(json);
+
+       new_json = cJSON_CreateString(val);
+       switch_assert(new_json);
+
+       cJSON_AddItemToObject(json, name, new_json);
+
+       return new_json;
+}
+
 #ifdef __cplusplus
 }
 #endif
index 43e692c05b1c32b57f55d90e68292a0ba69d5b33..e76e0e5ab1c08deb2326ec341793d7a2f6625a63 100644 (file)
@@ -69,6 +69,8 @@ SWITCH_BEGIN_EXTERN_C
        switch_chat_application_interface_t *chat_application_interface;
        /*! the table of api functions the module has implemented */
        switch_api_interface_t *api_interface;
+       /*! the table of json api functions the module has implemented */
+       switch_json_api_interface_t *json_api_interface;
        /*! the table of file formats the module has implemented */
        switch_file_interface_t *file_interface;
        /*! the table of speech interfaces the module has implemented */
@@ -189,6 +191,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_execute_chat_app(switch_event_t *mes
  */
 SWITCH_DECLARE(switch_api_interface_t *) switch_loadable_module_get_api_interface(const char *name);
 
+/*!
+  \brief Retrieve the JSON API interface by it's registered name
+  \param name the name of the API
+  \return the desired API interface
+ */
+SWITCH_DECLARE(switch_json_api_interface_t *) switch_loadable_module_get_json_api_interface(const char *name);
+
 /*!
   \brief Retrieve the file format interface by it's registered name
   \param name the name of the file format
@@ -275,6 +284,16 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_
 */
 SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char *arg, switch_core_session_t *session, switch_stream_handle_t *stream);
 
+/*!
+  \brief Execute a registered JSON API command
+  \param json the name of the JSON API command to execute
+  \param arg the optional arguement to the command
+  \param session an optional session
+  \param stream stream for output
+  \return the status returned by the API call
+*/
+SWITCH_DECLARE(switch_status_t) switch_json_api_execute(cJSON *json, switch_core_session_t *session, cJSON **retval);
+
 /*!
   \brief Load a module
   \param dir the directory where the module resides
@@ -328,6 +347,16 @@ SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void);
        break; \
        }
 
+#define SWITCH_ADD_JSON_API(json_api_int, int_name, descript, funcptr, syntax_string) \
+       for (;;) { \
+       json_api_int = (switch_json_api_interface_t *)switch_loadable_module_create_interface(*module_interface, SWITCH_JSON_API_INTERFACE); \
+       json_api_int->interface_name = int_name; \
+       json_api_int->desc = descript; \
+       json_api_int->function = funcptr; \
+       json_api_int->syntax = syntax_string; \
+       break; \
+       }
+
 #define SWITCH_ADD_CHAT(chat_int, int_name, funcptr) \
        for (;;) { \
        chat_int = (switch_chat_interface_t *)switch_loadable_module_create_interface(*module_interface, SWITCH_CHAT_INTERFACE); \
@@ -510,8 +539,9 @@ static inline switch_bool_t switch_core_codec_ready(switch_codec_t *codec)
 }
 
 
-
-
+SWITCH_DECLARE(switch_core_recover_callback_t) switch_core_get_secondary_recover_callback(const char *key);
+SWITCH_DECLARE(switch_status_t) switch_core_register_secondary_recover_callback(const char *key, switch_core_recover_callback_t cb);
+SWITCH_DECLARE(void) switch_core_unregister_secondary_recover_callback(const char *key);
 
 SWITCH_END_EXTERN_C
 #endif
index b6f4f1155421a95e0549120a13acf5f88a6311fb..ad6b4aefd49551f1bd595d2655fcf0ff776a12d3 100644 (file)
@@ -743,6 +743,24 @@ struct switch_api_interface {
        struct switch_api_interface *next;
 };
 
+
+/*! \brief A module interface to implement a json api function */
+struct switch_json_api_interface {
+       /*! the name of the interface */
+       const char *interface_name;
+       /*! a description of the api function */
+       const char *desc;
+       /*! function the api call uses */
+       switch_json_api_function_t function;
+       /*! an example of the api syntax */
+       const char *syntax;
+       switch_thread_rwlock_t *rwlock;
+       int refs;
+       switch_mutex_t *reflock;
+       switch_loadable_module_interface_t *parent;
+       struct switch_json_api_interface *next;
+};
+
 #define PROTECT_INTERFACE(_it) if (_it) {switch_mutex_lock(_it->reflock); switch_thread_rwlock_rdlock(_it->parent->rwlock); switch_thread_rwlock_rdlock(_it->rwlock); _it->refs++; _it->parent->refs++; switch_mutex_unlock(_it->reflock);}    //if (!strcmp(_it->interface_name, "user")) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "+++++++++++LOCK %s %d/%d\n", _it->interface_name, _it->refs, _it->parent->refs);
 #define UNPROTECT_INTERFACE(_it) if (_it) {switch_mutex_lock(_it->reflock); switch_thread_rwlock_unlock(_it->rwlock); switch_thread_rwlock_unlock(_it->parent->rwlock); _it->refs--; _it->parent->refs--; switch_mutex_unlock(_it->reflock);}  //if (!strcmp(_it->interface_name, "user")) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "---------UNLOCK %s %d/%d\n", _it->interface_name, _it->refs, _it->parent->refs);
 
index f704d943d18590af3ae2a7bbf483f0eaf399a300..bd509cc29ab2a2ed1a58862432fe41af16fba37d 100644 (file)
@@ -508,6 +508,7 @@ SWITCH_DECLARE(switch_byte_t) switch_rtp_check_auto_adj(switch_rtp_t *rtp_sessio
 SWITCH_DECLARE(void) switch_rtp_set_interdigit_delay(switch_rtp_t *rtp_session, uint32_t delay);
 
 SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, dtls_fingerprint_t *local_fp, dtls_fingerprint_t *remote_fp, dtls_type_t type);
+SWITCH_DECLARE(switch_status_t) switch_rtp_del_dtls(switch_rtp_t *rtp_session, dtls_type_t type);
 
 SWITCH_DECLARE(int) switch_rtp_has_dtls(void);
 SWITCH_DECLARE(void) switch_rtp_video_refresh(switch_rtp_t *rtp_session);
index 27a88dcc73683ae7b2e1d5f3149a39250dc62a45..ee42de2eee8dffd5df3b9f852b50822ddeb59180 100644 (file)
@@ -38,6 +38,7 @@
 #define SWITCH_TYPES_H
 
 #include <switch.h>
+#include <switch_json.h>
 
 SWITCH_BEGIN_EXTERN_C
 #define SWITCH_ENT_ORIGINATE_DELIM ":_:"
@@ -223,8 +224,16 @@ SWITCH_BEGIN_EXTERN_C
 #define SWITCH_DEFAULT_FILE_BUFFER_LEN 65536
 #define SWITCH_DTMF_LOG_LEN 1000
 #define SWITCH_MAX_TRANS 2000
+#define SWITCH_CORE_SESSION_MAX_PRIVATES 2
+
 typedef uint8_t switch_byte_t;
 
+typedef enum {
+       SWITCH_PVT_PRIMARY = 0,
+       SWITCH_PVT_SECONDARY
+} switch_pvt_class_t;
+
+
 /*!
   \enum switch_dtmf_source_t
   \brief DTMF sources
@@ -357,7 +366,8 @@ typedef enum {
        SWITCH_ASR_INTERFACE,
        SWITCH_MANAGEMENT_INTERFACE,
        SWITCH_LIMIT_INTERFACE,
-       SWITCH_CHAT_APPLICATION_INTERFACE
+       SWITCH_CHAT_APPLICATION_INTERFACE,
+       SWITCH_JSON_API_INTERFACE,
 } switch_module_interface_name_t;
 
 typedef enum {
@@ -653,6 +663,7 @@ typedef enum {
        SWITCH_RTP_FLAG_ENABLE_RTCP,
        SWITCH_RTP_FLAG_RTCP_MUX,
        SWITCH_RTP_FLAG_KILL_JB,
+       SWITCH_RTP_FLAG_VIDEO_BREAK,
        SWITCH_RTP_FLAG_INVALID
 } switch_rtp_flag_t;
 
@@ -2000,6 +2011,7 @@ typedef struct switch_codec_interface switch_codec_interface_t;
 typedef struct switch_application_interface switch_application_interface_t;
 typedef struct switch_chat_application_interface switch_chat_application_interface_t;
 typedef struct switch_api_interface switch_api_interface_t;
+typedef struct switch_json_api_interface switch_json_api_interface_t;
 typedef struct switch_file_interface switch_file_interface_t;
 typedef struct switch_speech_interface switch_speech_interface_t;
 typedef struct switch_asr_interface switch_asr_interface_t;
@@ -2083,6 +2095,12 @@ typedef switch_status_t (*switch_api_function_t) (_In_opt_z_ const char *cmd, _I
 
 #define SWITCH_STANDARD_API(name) static switch_status_t name (_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream)
 
+
+typedef switch_status_t (*switch_json_api_function_t) (const cJSON *json, _In_opt_ switch_core_session_t *session, cJSON **json_reply);
+
+
+#define SWITCH_STANDARD_JSON_API(name) static switch_status_t name (const cJSON *json, _In_opt_ switch_core_session_t *session, cJSON **json_reply)
+
 typedef switch_status_t (*switch_input_callback_function_t) (switch_core_session_t *session, void *input,
                                                                                                                         switch_input_type_t input_type, void *buf, unsigned int buflen);
 typedef switch_status_t (*switch_read_frame_callback_function_t) (switch_core_session_t *session, switch_frame_t *frame, void *user_data);
@@ -2236,6 +2254,13 @@ struct sql_queue_manager;
 struct switch_media_handle_s;
 typedef struct switch_media_handle_s switch_media_handle_t;
 
+typedef uint32_t switch_event_channel_id_t;
+typedef void (*switch_event_channel_func_t)(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id);
+
+struct switch_live_array_s;
+typedef struct switch_live_array_s switch_live_array_t;
+
+
 
 SWITCH_END_EXTERN_C
 #endif
index dcdf215fe4f5f6d13c8d5bcc454bedb3060c8137..55f4ca4ba3294df451a47714e7dd45b3d0fb6177 100644 (file)
@@ -297,9 +297,6 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
 
        switch_set_flag_locked(tech_pvt, TFLAG_IO);
 
-       /* Move channel's state machine to ROUTING */
-       switch_channel_set_state(channel, CS_ROUTING);
-
        return SWITCH_STATUS_SUCCESS;
 
 }
index 5fe5d890001b3ed0bb99cf211e64ab653e947727..e7ecaaf949813752f9ecd5504c81ba4c69201c6f 100644 (file)
@@ -1916,6 +1916,7 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
 {
        switch_channel_t *channel = switch_core_session_get_channel(session);
        struct private_object *tech_pvt = NULL;
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
 
        tech_pvt = switch_core_session_get_private(session);
        switch_assert(tech_pvt != NULL);
@@ -1928,11 +1929,10 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
                if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
                        switch_channel_mark_answered(channel);
                }
-               /* Move channel's state machine to ROUTING */
-               switch_channel_set_state(channel, CS_ROUTING);
+               status = SWITCH_STATUS_SUCCESS;
        }
 
-       return SWITCH_STATUS_SUCCESS;
+       return status;
 }
 
 static switch_status_t channel_on_routing(switch_core_session_t *session)
index 9f25ee1d964759665aa3cea72e4f930ef84be352..f6c9605cb277b038a1f17417a71840ec415531ec 100644 (file)
@@ -586,11 +586,6 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
        //ERRORA("%s CHANNEL INIT\n", GSMOPEN_P_LOG, tech_pvt->name);
        switch_set_flag(tech_pvt, TFLAG_IO);
 
-       /* Move channel's state machine to ROUTING. This means the call is trying
-          to get from the initial start where the call because, to the point
-          where a destination has been identified. If the channel is simply
-          left in the initial state, nothing will happen. */
-       switch_channel_set_state(channel, CS_ROUTING);
        switch_mutex_lock(globals.mutex);
        globals.calls++;
 
index 9e78b8f55bae8bcbb6c4ab2c9203bf6766897aea..b3b3c1546c8d17b860143d1c2715a73004ee2e17 100644 (file)
@@ -416,11 +416,6 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
        switch_set_flag(tech_pvt, TFLAG_IO);
        switch_mutex_unlock(tech_pvt->flag_mutex);
 
-       /* Move channel's state machine to ROUTING. This means the call is trying
-          to get from the initial start where the call because, to the point
-          where a destination has been identified. If the channel is simply
-          left in the initial state, nothing will happen. */
-       switch_channel_set_state(channel, CS_ROUTING);
        switch_mutex_lock(globals.mutex);
        globals.calls++;
 
index 17619129cfe0c943181698344ef7bdb5d48ad1c2..adaf38deb1e8e28057ed14e502a14dc2418fcdff 100644 (file)
@@ -1655,7 +1655,6 @@ switch_status_t FSH323Connection::on_init()
        }
 
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"Started routing for connection [%p]\n",this);
-       switch_channel_set_state(channel, CS_ROUTING);
 
        return SWITCH_STATUS_SUCCESS;
 }
index c6cbfc89944062d1217f26466b81d49b63e76b09..ee354ad90b8e564e81a9427857385061e06e68d7 100644 (file)
@@ -231,6 +231,7 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
        switch_caller_profile_t *caller_profile;
        switch_event_t *vars = NULL;
        const char *var;
+       switch_status_t status = SWITCH_STATUS_FALSE;
 
        tech_pvt = switch_core_session_get_private(session);
        switch_assert(tech_pvt != NULL);
@@ -354,11 +355,12 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
        }
 
        switch_channel_set_variable(channel, "loopback_leg", switch_test_flag(tech_pvt, TFLAG_BLEG) ? "B" : "A");
+       status = SWITCH_STATUS_SUCCESS;
        switch_channel_set_state(channel, CS_ROUTING);
 
   end:
 
-       return SWITCH_STATUS_SUCCESS;
+       return status;
 }
 
 static void do_reset(loopback_private_t *tech_pvt)
index 633bcdbd3ad2ee2df4db62ea6183a564a5699547..6f0fb3addd4ea37aca66408fca16fbb83ce7dab1 100644 (file)
@@ -853,7 +853,7 @@ switch_status_t FSConnection::on_init()
         return SWITCH_STATUS_FALSE;\r
 \r
     PTRACE(4, "mod_opal\tStarted routing for connection " << *this);\r
-    switch_channel_set_state(m_fsChannel, CS_ROUTING);\r
+\r
     return SWITCH_STATUS_SUCCESS;\r
 }\r
 \r
index 9ce6730d9eba7587a52d0554f9d846e675f28265..7f66558c616e88e708348d926778237544d27a4a 100644 (file)
@@ -282,11 +282,6 @@ SWITCH_STANDARD_API(pa_cmd);
 */
 static switch_status_t channel_on_init(switch_core_session_t *session)
 {
-       switch_channel_t *channel = switch_core_session_get_channel(session);
-
-       /* Move channel's state machine to ROUTING */
-       switch_channel_set_state(channel, CS_ROUTING);
-
        return SWITCH_STATUS_SUCCESS;
 }
 
index 08c27da0ebab44ff5301cdcde94620fd5abd469c..ece46f8d63d623daa329e4be6a8b98a7b856704c 100644 (file)
@@ -141,11 +141,6 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
        assert(channel != NULL);
        switch_set_flag_locked(tech_pvt, TFLAG_IO);
 
-       /* Move channel's state machine to ROUTING. This means the call is trying
-          to get from the initial start where the call because, to the point
-          where a destination has been identified. If the channel is simply
-          left in the initial state, nothing will happen. */
-       switch_channel_set_state(channel, CS_ROUTING);
        switch_mutex_lock(globals.mutex);
        globals.calls++;
        switch_mutex_unlock(globals.mutex);
index 339ce818730a2f6859faa2049ea7214b105df601..e25f38b861803945ce31ea41868e7bd508862387 100644 (file)
@@ -163,13 +163,6 @@ switch_status_t rtmp_on_init(switch_core_session_t *session)
        
        switch_set_flag_locked(tech_pvt, TFLAG_IO);
        
-       /* Move channel's state machine to ROUTING. This means the call is trying
-          to get from the initial start where the call because, to the point
-          where a destination has been identified. If the channel is simply
-          left in the initial state, nothing will happen. */
-       switch_channel_set_state(channel, CS_ROUTING);
-
-       
        switch_mutex_lock(rsession->profile->mutex);
        rsession->profile->calls++;
        switch_mutex_unlock(rsession->profile->mutex);
index cc94f1129ffec3e72eeb65a74f9c29ad319df4c7..0e1e700264295d447c0b80f909773011e17df353 100644 (file)
@@ -648,7 +648,8 @@ switch_status_t channel_on_init(switch_core_session_t *session)
 
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL INIT\n", switch_channel_get_name(channel));
 
-       return SWITCH_STATUS_SUCCESS;
+       /* This does not set the state to routing like most modules do, this now happens in the default state handeler so return FALSE TO BLOCK IT*/
+       return SWITCH_STATUS_FALSE;
 }
 
 struct channel_on_routing_helper {
index 024942e00e4e6f7704782ac842b44cff8650d782..b586bd048958dd0195da4ca7b0d9123346c73c38 100644 (file)
@@ -457,11 +457,6 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
        switch_set_flag(tech_pvt, TFLAG_IO);
        switch_mutex_unlock(tech_pvt->flag_mutex);
 
-       /* Move channel's state machine to ROUTING. This means the call is trying
-          to get from the initial start where the call because, to the point
-          where a destination has been identified. If the channel is simply
-          left in the initial state, nothing will happen. */
-       switch_channel_set_state(channel, CS_ROUTING);
        DEBUGA_SKYPE("%s CHANNEL INIT %s\n", SKYPOPEN_P_LOG, tech_pvt->name, switch_core_session_get_uuid(session));
        switch_copy_string(tech_pvt->session_uuid_str, switch_core_session_get_uuid(session), sizeof(tech_pvt->session_uuid_str));
 
@@ -670,11 +665,11 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
 
 static switch_status_t channel_on_routing(switch_core_session_t *session)
 {
-       switch_channel_t *channel = NULL;
+       //switch_channel_t *channel = NULL;
        private_t *tech_pvt = NULL;
 
-       channel = switch_core_session_get_channel(session);
-       switch_assert(channel != NULL);
+       //channel = switch_core_session_get_channel(session);
+       //switch_assert(channel != NULL);
 
        tech_pvt = switch_core_session_get_private(session);
        switch_assert(tech_pvt != NULL);
index a4c8913ee57c0ceab6b515b70bc63bfc773e5107..b99c7aae9632689156c591bd93132fae1784e447 100644 (file)
@@ -102,20 +102,6 @@ static switch_status_t sofia_on_init(switch_core_session_t *session)
                }
        }
 
-
-
-       if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING_BRIDGE)) {
-               switch_channel_set_state(channel, CS_RESET);
-       } else {
-               if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) {
-                       switch_channel_set_state(channel, CS_EXECUTE);
-               } else {
-                       /* Move channel's state machine to ROUTING */
-                       switch_channel_set_state(channel, CS_ROUTING);
-                       assert(switch_channel_get_state(channel) != CS_INIT);
-               }
-       }
-
   end:
 
        switch_mutex_unlock(tech_pvt->sofia_mutex);
@@ -156,43 +142,6 @@ static switch_status_t sofia_on_reset(switch_core_session_t *session)
                                          switch_channel_get_name(switch_core_session_get_channel(session)));
 
 
-       if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING_BRIDGE)) {
-               switch_core_session_t *other_session = NULL;
-               const char *uuid = switch_core_session_get_uuid(session);
-
-               if (switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) {
-                       const char *other_uuid = switch_channel_get_partner_uuid(channel);
-                       int x = 0;
-
-                       if (other_uuid) {
-                               for (x = 0; other_session == NULL && x < 20; x++) {
-                                       if (!switch_channel_up(channel)) {
-                                               break;
-                                       }
-                                       other_session = switch_core_session_locate(other_uuid);
-                                       switch_yield(100000);
-                               }
-                       }
-
-                       if (other_session) {
-                               switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
-                               switch_channel_clear_flag(channel, CF_BRIDGE_ORIGINATOR);
-                               switch_channel_wait_for_state_timeout(other_channel, CS_RESET, 5000);
-                               switch_channel_wait_for_flag(other_channel, CF_MEDIA_ACK, SWITCH_TRUE, 2000, NULL);
-
-                               if (switch_channel_test_flag(channel, CF_PROXY_MODE) && switch_channel_test_flag(other_channel, CF_PROXY_MODE)) {
-                                       switch_ivr_signal_bridge(session, other_session);
-                               } else {
-                                       switch_ivr_uuid_bridge(uuid, other_uuid);
-                               }
-                               switch_core_session_rwunlock(other_session);
-                       }
-               }
-
-               switch_channel_clear_flag(tech_pvt->channel, CF_RECOVERING_BRIDGE);
-       }
-
-
        return SWITCH_STATUS_SUCCESS;
 }
 
@@ -221,12 +170,11 @@ static switch_status_t sofia_on_execute(switch_core_session_t *session)
        switch_channel_t *channel = switch_core_session_get_channel(session);
        switch_assert(tech_pvt != NULL);
 
-       switch_channel_clear_flag(tech_pvt->channel, CF_RECOVERING);
-
        if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
                sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
                switch_channel_clear_flag(channel, CF_LEG_HOLDING);
        }
+
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SOFIA EXECUTE\n",
                                          switch_channel_get_name(switch_core_session_get_channel(session)));
 
@@ -873,8 +821,6 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
                        tech_pvt->session_refresher = nua_no_refresher;
                }
 
-
-
                if (sofia_use_soa(tech_pvt)) {
                        nua_respond(tech_pvt->nh, SIP_200_OK,
                                                NUTAG_AUTOANSWER(0),
index ea4921052e47565d7f536f08afd2515b00e4f487..953ea6d8f0f057f72f430a557c146cfe9fa3597e 100644 (file)
@@ -300,7 +300,7 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
     
     switch_channel_set_state(channel, CS_CONSUME_MEDIA);
     
-    return SWITCH_STATUS_SUCCESS;
+    return SWITCH_STATUS_FALSE;
 }
 
 static switch_status_t channel_on_destroy(switch_core_session_t *session)
index f569a12dd22aa4598afd98bfff3de852fbe05ab5..833a725d44c4c7477c6c7d9cc144e1094b9583ce 100644 (file)
@@ -1907,9 +1907,6 @@ int sofia_recover_callback(switch_core_session_t *session)
                                                                  switch_channel_get_name(channel), use_uuid);
                        }
                }
-       
-               switch_core_media_recover_session(session);
-       
        }
 
        r++;
index 18cd5d11d55cab36fa129a5d78009658830157cf..35c3cde286b1cd1b1a17e6d83780e78ca02ba785 100644 (file)
@@ -850,11 +850,6 @@ static switch_status_t unicall_on_init(switch_core_session_t *session)
 
        switch_set_flag_locked(tech_pvt, TFLAG_IO);
 
-       /* Move channel's state machine to ROUTING. This means the call is trying
-          to get from the initial state to the point where a destination has been
-          identified. If the channel is simply left in the initial state, nothing
-          will happen. */
-       switch_channel_set_state(channel, CS_ROUTING);
        switch_mutex_lock(globals.mutex);
        globals.calls++;
        switch_mutex_unlock(globals.mutex);
index ae94061c260600810a0c55a995bfd3c7922bff1e..76d3d49f973741f2b4db79579c746db7175bdac3 100644 (file)
@@ -385,6 +385,13 @@ SWITCH_DECLARE(switch_channel_timetable_t *) switch_channel_get_timetable(switch
        return times;
 }
 
+SWITCH_DECLARE(void) switch_channel_set_direction(switch_channel_t *channel, switch_call_direction_t direction)
+{
+       if (!switch_core_session_in_thread(channel->session)) {
+               channel->direction = direction;
+       }
+}
+
 SWITCH_DECLARE(switch_call_direction_t) switch_channel_direction(switch_channel_t *channel)
 {
        return channel->direction;
@@ -491,6 +498,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_queue_dtmf(switch_channel_t *chan
                switch_zmalloc(dt, sizeof(*dt));
                *dt = new_dtmf;
 
+
                while (switch_queue_trypush(channel->dtmf_queue, dt) != SWITCH_STATUS_SUCCESS) {
                        if (switch_queue_trypop(channel->dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) {
                                free(pop);
@@ -509,6 +517,8 @@ SWITCH_DECLARE(switch_status_t) switch_channel_queue_dtmf(switch_channel_t *chan
 
        switch_mutex_unlock(channel->dtmf_mutex);
 
+       switch_core_media_break(channel->session, SWITCH_MEDIA_TYPE_AUDIO);
+
        return status;
 }
 
@@ -2951,19 +2961,33 @@ SWITCH_DECLARE(void) switch_channel_invert_cid(switch_channel_t *channel)
 SWITCH_DECLARE(void) switch_channel_flip_cid(switch_channel_t *channel)
 {
        switch_event_t *event;
+       const char *tmp = NULL;
 
        switch_mutex_lock(channel->profile_mutex);
        if (channel->caller_profile->callee_id_name) {
+               tmp = channel->caller_profile->caller_id_name;
                switch_channel_set_variable(channel, "pre_transfer_caller_id_name", channel->caller_profile->caller_id_name);
                channel->caller_profile->caller_id_name = switch_core_strdup(channel->caller_profile->pool, channel->caller_profile->callee_id_name);
        }
-       channel->caller_profile->callee_id_name = SWITCH_BLANK_STRING;
+
+       if (switch_channel_test_flag(channel, CF_BRIDGED)) {
+               channel->caller_profile->callee_id_name = SWITCH_BLANK_STRING;
+       } else if (tmp) {
+               channel->caller_profile->callee_id_name = tmp;
+       }
        
        if (channel->caller_profile->callee_id_number) {
+               tmp = channel->caller_profile->caller_id_number;
                switch_channel_set_variable(channel, "pre_transfer_caller_id_number", channel->caller_profile->caller_id_number);
                channel->caller_profile->caller_id_number = switch_core_strdup(channel->caller_profile->pool, channel->caller_profile->callee_id_number);
        }
-       channel->caller_profile->callee_id_number = SWITCH_BLANK_STRING;
+
+       if (switch_channel_test_flag(channel, CF_BRIDGED)) {
+               channel->caller_profile->callee_id_number = SWITCH_BLANK_STRING;
+       } else if (tmp) {
+               channel->caller_profile->callee_id_number = tmp;
+       }
+
        switch_mutex_unlock(channel->profile_mutex);
 
 
@@ -3260,7 +3284,7 @@ static void check_secure(switch_channel_t *channel)
 {
        const char *var, *sec;
 
-       if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
+       if (!switch_channel_media_ready(channel) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
                if ((sec = switch_channel_get_variable(channel, "rtp_secure_media")) && switch_true(sec)) {
                        if (!(var = switch_channel_get_variable(channel, "rtp_has_crypto"))) {
                                switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_WARNING, "rtp_secure_media invalid in this context.\n");
index 0c27fdcb46f40eec319968aea1cc1fa5517e28a0..bd3b521a9800e991fceea1d88fc4e39945e9f3e3 100644 (file)
@@ -171,8 +171,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_set_real_read_codec(switch_c
                }
 
                switch_channel_set_variable(channel, "read_codec", session->read_impl.iananame);
+               switch_channel_set_variable(channel, "original_read_codec", session->read_impl.iananame);
                switch_snprintf(tmp, sizeof(tmp), "%d", session->read_impl.actual_samples_per_second);
                switch_channel_set_variable(channel, "read_rate", tmp);
+               switch_channel_set_variable(channel, "original_read_rate", tmp);
 
                session->raw_read_frame.codec = session->read_codec;
                session->raw_write_frame.codec = session->read_codec;
index aad6192eceb3da53b63c91fc54ca26d5985a03a8..47f6289a7314f87bf25abe75701b520918e15813 100644 (file)
@@ -638,8 +638,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
                                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec init error!\n");
                                goto done;
                        default:
-                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s decoder error!\n",
-                                                                 session->read_codec->codec_interface->interface_name);
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s decoder error! [%d]\n",
+                                                                 session->read_codec->codec_interface->interface_name, status);
                                goto done;
                        }
                }
index d8553d07661c908195d0b6e3319e7ad1cc46f8f9..b412a518f5e3395a0df6b2c8934430ddcc287f71 100644 (file)
@@ -509,6 +509,31 @@ SWITCH_DECLARE(const char *)switch_core_media_get_codec_string(switch_core_sessi
        return !zstr(preferred) ? preferred : fallback;
 }
 
+SWITCH_DECLARE(void) switch_core_session_clear_crypto(switch_core_session_t *session)
+{
+       int i;
+       switch_media_handle_t *smh;
+
+       const char *vars[] = { "rtp_last_audio_local_crypto_key",
+                                                  "srtp_remote_audio_crypto_key",
+                                                  "srtp_remote_audio_crypto_tag",
+                                                  "srtp_remote_video_crypto_key",
+                                                  "srtp_remote_video_crypto_tag",
+                                                  "rtp_secure_media",
+                                                  NULL};
+
+       for(i = 0; vars[i] ;i++) {
+               switch_channel_set_variable(session->channel, vars[i], NULL);
+       }
+
+       if (!(smh = session->media_handle)) {
+               return;
+       }
+
+       memset(&smh->engines[SWITCH_MEDIA_TYPE_AUDIO].ssec, 0, sizeof(smh->engines[SWITCH_MEDIA_TYPE_AUDIO].ssec));
+       memset(&smh->engines[SWITCH_MEDIA_TYPE_VIDEO].ssec, 0, sizeof(smh->engines[SWITCH_MEDIA_TYPE_VIDEO].ssec));
+
+}
 
 SWITCH_DECLARE(const char *) switch_core_session_local_crypto_key(switch_core_session_t *session, switch_media_type_t type)
 {
@@ -1036,15 +1061,23 @@ SWITCH_DECLARE(switch_status_t) switch_media_handle_create(switch_media_handle_t
 
        *smhp = NULL;
 
+       if (zstr(params->sdp_username)) {
+               params->sdp_username = "FreeSWITCH";
+       }
+
+
        if ((session->media_handle = switch_core_session_alloc(session, (sizeof(*smh))))) {
                session->media_handle->session = session;
                *smhp = session->media_handle;
                switch_set_flag(session->media_handle, SMF_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_AUDIO].type = SWITCH_MEDIA_TYPE_AUDIO;
                session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
+               session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].type = SWITCH_MEDIA_TYPE_VIDEO;
                session->media_handle->mparams = params;
 
+
                switch_mutex_init(&session->media_handle->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
 
                session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].ssrc = 
@@ -1098,18 +1131,18 @@ SWITCH_DECLARE(int32_t) switch_media_handle_test_media_flag(switch_media_handle_
 
 SWITCH_DECLARE(switch_status_t) switch_core_session_media_handle_ready(switch_core_session_t *session)
 {
-
        if (session->media_handle && switch_test_flag(session->media_handle, SMF_INIT)) {
                return SWITCH_STATUS_SUCCESS;
        }
-       
+
        return SWITCH_STATUS_FALSE;
 }
 
 
+
 SWITCH_DECLARE(switch_media_handle_t *) switch_core_session_get_media_handle(switch_core_session_t *session)
 {
-       if (switch_core_session_media_handle_ready(session)) {
+       if (switch_core_session_media_handle_ready(session) == SWITCH_STATUS_SUCCESS) {
                return session->media_handle;
        }
 
@@ -1125,6 +1158,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_clear_media_handle(switch_co
        return SWITCH_STATUS_SUCCESS;
 }
 
+SWITCH_DECLARE(switch_core_media_params_t *) switch_core_media_get_mparams(switch_media_handle_t *smh)
+{
+       switch_assert(smh);
+       return smh->mparams;
+}
 
 SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *session, switch_bool_t force)
 {
@@ -1753,8 +1791,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_codec(switch_core_se
                        switch_core_session_set_video_write_codec(session, &v_engine->write_codec);
 
 
-                       switch_channel_set_variable_printf(session->channel, "rtp_last_video_codec_string", "%s@%dh@%di", 
-                                                                                          v_engine->codec_params.iananame, v_engine->codec_params.rm_rate, v_engine->codec_params.codec_ms);
+                       switch_channel_set_variable_printf(session->channel, "rtp_last_video_codec_string", "%s@%dh", 
+                                                                                          v_engine->codec_params.rm_encoding, v_engine->codec_params.rm_rate);
 
 
                        if (switch_rtp_ready(v_engine->rtp_session)) {
@@ -2018,12 +2056,26 @@ static int dtls_ok(switch_core_session_t *session)
 #pragma warning(disable:4702)
 #endif
 
+//?
+SWITCH_DECLARE(switch_call_direction_t) switch_ice_direction(switch_core_session_t *session)
+{
+       switch_call_direction_t r = switch_channel_direction(session->channel);
+
+       if ((switch_channel_test_flag(session->channel, CF_REINVITE) || switch_channel_test_flag(session->channel, CF_RECOVERING)) 
+               && switch_channel_test_flag(session->channel, CF_WEBRTC)) {
+               r = SWITCH_CALL_DIRECTION_OUTBOUND;
+       }
+
+       return r;
+}
+
 //?
 static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_session_t *sdp, sdp_media_t *m)
 {
        switch_rtp_engine_t *engine = &smh->engines[type];
        sdp_attribute_t *attr;
        int i = 0, got_rtcp_mux = 0;
+       const char *val;
 
        if (engine->ice_in.chosen[0] && engine->ice_in.chosen[1] && !switch_channel_test_flag(smh->session->channel, CF_REINVITE)) {
                return;
@@ -2078,6 +2130,12 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
 
                } else if (!engine->remote_ssrc && !strcasecmp(attr->a_name, "ssrc") && attr->a_value) {
                        engine->remote_ssrc = (uint32_t) atol(attr->a_value);
+
+                       if (engine->rtp_session && engine->remote_ssrc) {
+                               switch_rtp_set_remote_ssrc(engine->rtp_session, engine->remote_ssrc);
+                       }
+       
+
 #ifdef RTCP_MUX
                } else if (!strcasecmp(attr->a_name, "rtcp-mux")) {
                        engine->rtcp_mux = SWITCH_TRUE;
@@ -2139,7 +2197,8 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
                                engine->ice_in.cands[engine->ice_in.cand_idx][cid].priority = atol(fields[3]);
                                engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_addr = switch_core_session_strdup(smh->session, fields[4]);
                                engine->ice_in.cands[engine->ice_in.cand_idx][cid].con_port = (switch_port_t)atoi(fields[5]);
-                                               
+
+
                                j = 6;
 
                                while(j < argc && fields[j+1]) {
@@ -2155,6 +2214,7 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
                                        
                                        j += 2;
                                } 
+                               
 
                                if (engine->ice_in.chosen[cid]) {
                                        engine->ice_in.cands[engine->ice_in.chosen[cid]][cid].ready++;
@@ -2206,6 +2266,19 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
                }
        }
 
+       /* Got RTP but not RTCP, probably mux */
+       if (engine->ice_in.chosen[0] && !engine->ice_in.chosen[1] && got_rtcp_mux) {
+               engine->ice_in.chosen[1] = engine->ice_in.chosen[0];
+
+               memcpy(&engine->ice_in.cands[engine->ice_in.chosen[1]][1], &engine->ice_in.cands[engine->ice_in.chosen[0]][0], 
+                          sizeof(engine->ice_in.cands[engine->ice_in.chosen[0]][0]));
+               engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready++;
+               
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_NOTICE,
+                                                 "No %s RTCP candidate found; defaulting to the same as RTP [%s:%d]\n", type2str(type),
+                                                 engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr, engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port);
+       }
+
        /* look for any candidates and hope for auto-adjust */
        if (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]) {
                for (i = 0; i <= engine->ice_in.cand_idx && (!engine->ice_in.chosen[0] || !engine->ice_in.chosen[1]); i++) {
@@ -2246,7 +2319,9 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
 
                engine->codec_params.remote_sdp_ip = switch_core_session_strdup(smh->session, (char *) engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr);
                engine->codec_params.remote_sdp_port = (switch_port_t) engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port;
-
+               if (engine->remote_rtcp_port) {
+                       engine->remote_rtcp_port = engine->codec_params.remote_sdp_port;
+               }
                                                                                                                                 
                switch_snprintf(tmp, sizeof(tmp), "%d", engine->codec_params.remote_sdp_port);
                switch_channel_set_variable(smh->session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, engine->codec_params.remote_sdp_ip);
@@ -2271,6 +2346,7 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
 
        
        if (switch_channel_test_flag(smh->session->channel, CF_REINVITE)) {
+
                if (switch_rtp_ready(engine->rtp_session) && engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready) {
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_INFO, "RE-Activating %s ICE\n", type2str(type));
 
@@ -2284,7 +2360,7 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
                                                                        ICE_GOOGLE_JINGLE,
                                                                        NULL
 #else
-                                                                       switch_channel_direction(smh->session->channel) == 
+                                                                       switch_ice_direction(smh->session) == 
                                                                        SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED),
                                                                        &engine->ice_in
 #endif
@@ -2295,7 +2371,37 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
                }
                
 
+               if (engine->rtp_session && ((val = switch_channel_get_variable(smh->session->channel,
+                                                                                                                                          type == SWITCH_MEDIA_TYPE_VIDEO ? 
+                                                                                                                                          "rtcp_video_interval_msec" : "rtcp_audio_interval_msec")) 
+                                                                       || (val = type == SWITCH_MEDIA_TYPE_VIDEO ? 
+                                                                               smh->mparams->rtcp_video_interval_msec : smh->mparams->rtcp_audio_interval_msec))) {
+                                                                                          
+                       const char *rport = switch_channel_get_variable(smh->session->channel, 
+                                                                                                                       type == SWITCH_MEDIA_TYPE_VIDEO ? "rtp_remote_video_rtcp_port" : "rtp_remote_audio_rtcp_port");
+                       switch_port_t remote_rtcp_port = engine->remote_rtcp_port;
+
+                       if (!remote_rtcp_port && rport) {
+                               remote_rtcp_port = (switch_port_t)atoi(rport);
+                       }
+                       
+                       if (!strcasecmp(val, "passthru")) {
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_INFO, "Activating %s RTCP PASSTHRU PORT %d\n", 
+                                                                 type2str(type), remote_rtcp_port);
+                               switch_rtp_activate_rtcp(engine->rtp_session, -1, remote_rtcp_port, engine->rtcp_mux > 0);
+                       } else {
+                               int interval = atoi(val);
+                               if (interval < 100 || interval > 500000) {
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_ERROR,
+                                                                         "Invalid rtcp interval spec [%d] must be between 100 and 500000\n", interval);
+                                       interval = 10000;
+                               }
 
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_INFO, "Activating %s RTCP PORT %d\n", type2str(type), remote_rtcp_port);
+                               switch_rtp_activate_rtcp(engine->rtp_session, interval, remote_rtcp_port, engine->rtcp_mux > 0);
+                       }
+               }
+                       
                if (engine->ice_in.cands[engine->ice_in.chosen[1]][1].ready) {
                        if (!strcmp(engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_addr, engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_addr)
                                && engine->ice_in.cands[engine->ice_in.chosen[1]][1].con_port == engine->ice_in.cands[engine->ice_in.chosen[0]][0].con_port) {
@@ -2313,7 +2419,7 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_
                                                                                ICE_GOOGLE_JINGLE,
                                                                                NULL
 #else
-                                                                               switch_channel_direction(smh->session->channel) == 
+                                                                               switch_ice_direction(smh->session) == 
                                                                                SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED),
                                                                                &engine->ice_in
 #endif
@@ -3350,6 +3456,116 @@ SWITCH_DECLARE(int) switch_core_media_toggle_hold(switch_core_session_t *session
        return changed;
 }
 
+static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, void *obj)
+{
+       struct media_helper *mh = obj;
+       switch_core_session_t *session = mh->session;
+       switch_channel_t *channel = switch_core_session_get_channel(session);
+       switch_status_t status;
+       switch_frame_t *read_frame;
+       switch_media_handle_t *smh;
+
+       if (!(smh = session->media_handle)) {
+               return NULL;
+       }
+
+       switch_core_session_read_lock(session);
+
+       mh->up = 1;
+       switch_mutex_lock(mh->cond_mutex);
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread started. Echo is %s\n", 
+                                         switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
+       switch_core_session_refresh_video(session);
+
+       while (switch_channel_up_nosig(channel)) {
+
+               if (switch_channel_test_flag(channel, CF_VIDEO_PASSIVE)) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread paused. Echo is %s\n", 
+                                                         switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
+                       switch_thread_cond_wait(mh->cond, mh->cond_mutex);
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread resumed  Echo is %s\n", 
+                                                         switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
+                       switch_core_session_refresh_video(session);
+               }
+
+               if (switch_channel_test_flag(channel, CF_VIDEO_PASSIVE)) {
+                       continue;
+               }
+
+               if (!switch_channel_media_up(session->channel)) {
+                       switch_yield(10000);
+                       continue;
+               }
+
+               
+               status = switch_core_session_read_video_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
+               
+               if (!SWITCH_READ_ACCEPTABLE(status)) {
+                       switch_cond_next();
+                       continue;
+               }
+               
+
+               if (switch_channel_test_flag(channel, CF_VIDEO_REFRESH_REQ)) {
+                       switch_core_session_refresh_video(session);
+                       switch_channel_clear_flag(channel, CF_VIDEO_REFRESH_REQ);
+               }
+
+               if (switch_test_flag(read_frame, SFF_CNG)) {
+                       continue;
+               }
+
+               if (switch_channel_test_flag(channel, CF_VIDEO_ECHO)) {
+                       switch_core_session_write_video_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0);
+               }
+
+       }
+
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread ended\n", switch_channel_get_name(session->channel));
+
+       switch_mutex_unlock(mh->cond_mutex);
+       switch_core_session_rwunlock(session);
+
+       mh->up = 0;
+       return NULL;
+}
+
+
+static switch_status_t start_video_thread(switch_core_session_t *session)
+{
+       switch_threadattr_t *thd_attr = NULL;
+       switch_memory_pool_t *pool = switch_core_session_get_pool(session);
+       switch_rtp_engine_t *v_engine = NULL;
+       switch_media_handle_t *smh;
+
+       if (!(smh = session->media_handle)) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+
+       if (v_engine->media_thread) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "%s Starting Video thread\n", switch_core_session_get_name(session));
+
+       switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->codec_params.agreed_pt);
+       v_engine->mh.session = session;
+       switch_threadattr_create(&thd_attr, pool);
+       switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+       
+       switch_thread_cond_create(&v_engine->mh.cond, pool);
+       switch_mutex_init(&v_engine->mh.cond_mutex, SWITCH_MUTEX_NESTED, pool);
+       switch_mutex_init(&v_engine->read_mutex, SWITCH_MUTEX_NESTED, pool);
+       switch_thread_create(&v_engine->media_thread, thd_attr, video_helper_thread, &v_engine->mh, switch_core_session_get_pool(session));
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+
 
 //?
 #define RA_PTR_LEN 512
@@ -3470,7 +3686,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_proxy_remote_addr(switch_core_
                                        }
                                }
 
-
+                               
                                if (switch_rtp_set_remote_address(v_engine->rtp_session, v_engine->codec_params.remote_sdp_ip,
                                                                                                  v_engine->codec_params.remote_sdp_port, remote_rtcp_port, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
                                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", err);
@@ -3482,6 +3698,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_proxy_remote_addr(switch_core_
                                                !switch_channel_test_flag(session->channel, CF_WEBRTC)) {
                                                /* Reactivate the NAT buster flag. */
                                                switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
+                                               start_video_thread(session);
+                               
                                        }
                                        if (switch_media_handle_test_media_flag(smh, SCMF_AUTOFIX_TIMING) || switch_media_handle_test_media_flag(smh, SCMF_AUTOFIX_PT)) {
                                                v_engine->check_frames = 0;
@@ -3735,6 +3953,24 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_choose_port(switch_core_sessio
        return SWITCH_STATUS_SUCCESS;
 }
 
+SWITCH_DECLARE(switch_status_t) switch_core_media_choose_ports(switch_core_session_t *session, switch_bool_t audio, switch_bool_t video)
+{
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+       if (audio && (status = switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_AUDIO, 0)) == SWITCH_STATUS_SUCCESS) {
+               if (video) {
+                       switch_core_media_check_video_codecs(session);
+                       if (switch_channel_test_flag(session->channel, CF_VIDEO_POSSIBLE)) {
+                               switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_VIDEO, 0);
+                       }
+               }
+       }
+
+       return status;
+}
+
+
+
 //?
 SWITCH_DECLARE(void) switch_core_media_deactivate_rtp(switch_core_session_t *session)
 {
@@ -3882,85 +4118,28 @@ SWITCH_DECLARE(void) switch_core_session_wake_video_thread(switch_core_session_t
        }
 }
 
-static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, void *obj)
+static void check_dtls_reinvite(switch_core_session_t *session, switch_rtp_engine_t *engine)
 {
-       struct media_helper *mh = obj;
-       switch_core_session_t *session = mh->session;
-       switch_channel_t *channel = switch_core_session_get_channel(session);
-       switch_status_t status;
-       switch_frame_t *read_frame;
-       switch_media_handle_t *smh;
-
-       if (!(smh = session->media_handle)) {
-               return NULL;
-       }
-
-       switch_core_session_read_lock(session);
-
-       mh->up = 1;
-       switch_mutex_lock(mh->cond_mutex);
-
-       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread started. Echo is %s\n", 
-                                         switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
-       switch_core_session_refresh_video(session);
-
-       while (switch_channel_up_nosig(channel)) {
-
-               if (switch_channel_test_flag(channel, CF_VIDEO_PASSIVE)) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread paused. Echo is %s\n", 
-                                                         switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
-                       switch_thread_cond_wait(mh->cond, mh->cond_mutex);
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread resumed  Echo is %s\n", 
-                                                         switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
-                       switch_core_session_refresh_video(session);
-               }
-
-               if (switch_channel_test_flag(channel, CF_VIDEO_PASSIVE)) {
-                       continue;
-               }
-
-               if (!switch_channel_media_up(session->channel)) {
-                       switch_yield(10000);
-                       continue;
-               }
+       if (switch_channel_test_flag(session->channel, CF_REINVITE)) {
 
+               if (!zstr(engine->local_dtls_fingerprint.str) && switch_rtp_has_dtls() && dtls_ok(session)) {
+                       dtls_type_t xtype, dtype = switch_ice_direction(session) == SWITCH_CALL_DIRECTION_INBOUND ? DTLS_TYPE_CLIENT : DTLS_TYPE_SERVER;
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "RE-SETTING %s DTLS\n", type2str(engine->type));
                
-               status = switch_core_session_read_video_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
+                       xtype = DTLS_TYPE_RTP;
+                       if (engine->rtcp_mux > 0) xtype |= DTLS_TYPE_RTCP;
+                       
+                       switch_rtp_add_dtls(engine->rtp_session, &engine->local_dtls_fingerprint, &engine->remote_dtls_fingerprint, dtype | xtype);
                
-               if (!SWITCH_READ_ACCEPTABLE(status)) {
-                       switch_cond_next();
-                       continue;
-               }
+                       if (engine->rtcp_mux < 1) {
+                               xtype = DTLS_TYPE_RTCP;
+                               switch_rtp_add_dtls(engine->rtp_session, &engine->local_dtls_fingerprint, &engine->remote_dtls_fingerprint, dtype | xtype);
+                       }
                
-
-               if (switch_channel_test_flag(channel, CF_VIDEO_REFRESH_REQ)) {
-                       switch_core_session_refresh_video(session);
-                       switch_channel_clear_flag(channel, CF_VIDEO_REFRESH_REQ);
-               }
-
-               if (switch_test_flag(read_frame, SFF_CNG)) {
-                       continue;
                }
-
-               if (switch_channel_test_flag(channel, CF_VIDEO_ECHO)) {
-                       switch_core_session_write_video_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0);
-               }
-
        }
-
-
-       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread ended\n", switch_channel_get_name(session->channel));
-
-       switch_mutex_unlock(mh->cond_mutex);
-       switch_core_session_rwunlock(session);
-
-       mh->up = 0;
-       return NULL;
 }
 
-
-
-
 //?
 SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_session_t *session)
 
@@ -4151,6 +4330,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
                                switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
                        }
                }
+
+               if (session && a_engine) {
+                       check_dtls_reinvite(session, a_engine);
+               }
+
                goto video;
        }
 
@@ -4278,7 +4462,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
                                                                        ICE_GOOGLE_JINGLE,
                                                                        NULL
 #else
-                                                                       switch_channel_direction(session->channel) == 
+                                                                       switch_ice_direction(session) == 
                                                                        SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED),
                                                                        &a_engine->ice_in
 #endif
@@ -4331,7 +4515,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
                                                                                        ICE_GOOGLE_JINGLE,
                                                                                        NULL
 #else
-                                                                                       switch_channel_direction(session->channel) == 
+                                                                                       switch_ice_direction(session) == 
                                                                                        SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED),
                                                                                        &a_engine->ice_in
 #endif
@@ -4373,6 +4557,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
                                }
                        }
 
+                       if (jb_msec < 0 && jb_msec > -10) {
+                               jb_msec = (a_engine->read_codec.implementation->microseconds_per_packet / 1000) * abs(jb_msec);
+                       }
+
                        if (jb_msec < 20 || jb_msec > 10000) {
                                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR,
                                                                  "Invalid Jitterbuffer spec [%d] must be between 20 and 10000\n", jb_msec);
@@ -4535,7 +4723,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
                                                                          v_engine->codec_params.remote_sdp_port, v_engine->codec_params.agreed_pt, 
                                                                          a_engine->read_impl.microseconds_per_packet / 1000);
 
-                               
+                                       start_video_thread(session);
                                        switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->codec_params.agreed_pt);
                                }
                        }
@@ -4549,7 +4737,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
                                const char *rport = NULL;
                                switch_port_t remote_rtcp_port = v_engine->remote_rtcp_port;
 
-                               switch_channel_clear_flag(session->channel, CF_REINVITE);
+                               //switch_channel_clear_flag(session->channel, CF_REINVITE);
 
                                if (!remote_rtcp_port) {
                                        if ((rport = switch_channel_get_variable(session->channel, "rtp_remote_video_rtcp_port"))) {
@@ -4568,6 +4756,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
                                                !((val = switch_channel_get_variable(session->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
                                                /* Reactivate the NAT buster flag. */
                                                switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
+                                               start_video_thread(session);
                                        }
 
                                }
@@ -4655,18 +4844,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
 
 
                        if (switch_rtp_ready(v_engine->rtp_session)) {
-                               switch_threadattr_t *thd_attr = NULL;
-                               switch_memory_pool_t *pool = switch_core_session_get_pool(session);
-
-                               switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->codec_params.agreed_pt);
-                               v_engine->mh.session = session;
-                               switch_threadattr_create(&thd_attr, pool);
-                               switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
-
-                               switch_thread_cond_create(&v_engine->mh.cond, pool);
-                               switch_mutex_init(&v_engine->mh.cond_mutex, SWITCH_MUTEX_NESTED, pool);
-                               switch_mutex_init(&v_engine->read_mutex, SWITCH_MUTEX_NESTED, pool);
-                               switch_thread_create(&v_engine->media_thread, thd_attr, video_helper_thread, &v_engine->mh, switch_core_session_get_pool(session));
+                               start_video_thread(session);
                        }
 
                        if (switch_rtp_ready(v_engine->rtp_session)) {
@@ -4700,7 +4878,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
                                                                                        ICE_GOOGLE_JINGLE,
                                                                                        NULL
 #else
-                                                                                       switch_channel_direction(session->channel) == 
+                                                                                       switch_ice_direction(session) == 
                                                                                        SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED),
                                                                                        &v_engine->ice_in
 #endif
@@ -4750,7 +4928,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
                                                                                                        ICE_GOOGLE_JINGLE,
                                                                                                        NULL
 #else
-                                                                                                       switch_channel_direction(session->channel) == 
+                                                                                                       switch_ice_direction(session) == 
                                                                                                        SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED),
                                                                                                        
                                                                                                        &v_engine->ice_in
@@ -4819,6 +4997,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
 
  video_up:
 
+       if (session && v_engine) {
+               check_dtls_reinvite(session, v_engine);
+       }
+
        status = SWITCH_STATUS_SUCCESS;
 
  end:
@@ -5275,7 +5457,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
                switch_channel_clear_flag(smh->session->channel, CF_DTLS);
        }
 
-       if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+       if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND || switch_channel_test_flag(session->channel, CF_RECOVERING)) {
                if (!switch_channel_test_flag(session->channel, CF_WEBRTC) && 
                        switch_true(switch_channel_get_variable(session->channel, "media_webrtc"))) {
                        switch_channel_set_flag(session->channel, CF_WEBRTC);
@@ -5460,6 +5642,10 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
 
                rate = a_engine->codec_params.rm_rate;
 
+               if (!strcasecmp(a_engine->codec_params.rm_encoding, "opus")) {
+                       a_engine->codec_params.adv_channels = 2;
+               }
+
                if (a_engine->codec_params.adv_channels > 1) {
                        switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d/%d\n", 
                                                        a_engine->codec_params.agreed_pt, a_engine->codec_params.rm_encoding, rate, a_engine->codec_params.adv_channels);
@@ -5577,7 +5763,8 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
                        }
 
 
-                       if (a_engine->rtcp_mux < 1 || switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+                       if (a_engine->rtcp_mux < 1 || switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND || 
+                               switch_channel_test_flag(session->channel, CF_RECOVERING)) {
 
                                switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=candidate:%s 2 %s %u %s %d typ host generation 0\n", 
                                                                tmp1, ice_out->cands[0][0].transport, c2,
@@ -5765,7 +5952,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
                        
                        if (v_engine->codec_params.rm_encoding) {
                                const char *of;
-                               
+
                                if (!strcasecmp(v_engine->codec_params.rm_encoding, "VP8")) {
                                        vp8 = v_engine->codec_params.pt;
                                }
@@ -5866,7 +6053,8 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
                                
                        }
 
-                       if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND && switch_channel_test_flag(smh->session->channel, CF_DTLS)) {
+                       if ((switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND || switch_channel_test_flag(session->channel, CF_RECOVERING))
+                               && switch_channel_test_flag(smh->session->channel, CF_DTLS)) {
                                generate_local_fingerprint(smh, SWITCH_MEDIA_TYPE_VIDEO);
                        }
 
@@ -5949,7 +6137,8 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
                                }
 
 
-                               if (v_engine->rtcp_mux < 1 || switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+                               if (v_engine->rtcp_mux < 1 || switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND || 
+                                       switch_channel_test_flag(session->channel, CF_RECOVERING)) {
 
                                        switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=candidate:%s 2 %s %u %s %d typ host generation 0\n", 
                                                                        tmp1, ice_out->cands[0][0].transport, c2,
@@ -7607,8 +7796,6 @@ SWITCH_DECLARE (void) switch_core_media_recover_session(switch_core_session_t *s
        ip = switch_channel_get_variable(session->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
        port = switch_channel_get_variable(session->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
 
-       switch_channel_set_flag(session->channel, CF_RECOVERING);
-
        if (switch_channel_test_flag(session->channel, CF_PROXY_MODE)  || !(ip && port)) {
                return;
        } else {
@@ -7728,7 +7915,7 @@ SWITCH_DECLARE (void) switch_core_media_recover_session(switch_core_session_t *s
        switch_core_session_get_recovery_crypto_key(session, SWITCH_MEDIA_TYPE_VIDEO);
 
 
-       if ((tmp = switch_channel_get_variable(session->channel, "rtp_last_audio_local_crypto_key"))) {
+       if ((tmp = switch_channel_get_variable(session->channel, "rtp_last_audio_local_crypto_key")) && a_engine->ssec.remote_crypto_key) {
                int idx = atoi(tmp);
 
                a_engine->ssec.local_crypto_key = switch_core_session_strdup(session, tmp);
index 430b20d013dd2891dc1564f22718dc2742772d77..52cb871aa900633e85670ee029b63e149052b54d 100644 (file)
@@ -445,17 +445,26 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_event_send(const char *uuid_
 }
 
 
-SWITCH_DECLARE(void *) switch_core_session_get_private(switch_core_session_t *session)
+SWITCH_DECLARE(void *) switch_core_session_get_private_class(switch_core_session_t *session, switch_pvt_class_t index)
 {
+       if (index >= SWITCH_CORE_SESSION_MAX_PRIVATES) {
+               return NULL;
+       }
+
        switch_assert(session != NULL);
-       return session->private_info;
+       return session->private_info[index];
 }
 
 
-SWITCH_DECLARE(switch_status_t) switch_core_session_set_private(switch_core_session_t *session, void *private_info)
+SWITCH_DECLARE(switch_status_t) switch_core_session_set_private_class(switch_core_session_t *session, void *private_info, switch_pvt_class_t index)
 {
        switch_assert(session != NULL);
-       session->private_info = private_info;
+
+       if (index >= SWITCH_CORE_SESSION_MAX_PRIVATES) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       session->private_info[index] = private_info;
        return SWITCH_STATUS_SUCCESS;
 }
 
index a9c8d22fbc3ba695c28722a354432d82d885e452..7dd02df818fadf0a91b5b7fb6f7b598b55327d9f 100644 (file)
@@ -2717,14 +2717,35 @@ static int recover_callback(void *pArg, int argc, char **argv, char **columnName
 
        if (ep->recover_callback) {
                switch_caller_extension_t *extension = NULL;
+               switch_channel_t *channel = switch_core_session_get_channel(session);
+               int r = 0;
 
+               if ((r = ep->recover_callback(session)) > 0) {
+                       const char *cbname;
 
-               if (ep->recover_callback(session) > 0) {
-                       switch_channel_t *channel = switch_core_session_get_channel(session);
+                       switch_channel_set_flag(session->channel, CF_RECOVERING);
+                       
 
                        if (switch_channel_get_partner_uuid(channel)) {
                                switch_channel_set_flag(channel, CF_RECOVERING_BRIDGE);
-                       } else {
+                       }
+
+                       switch_core_media_recover_session(session);
+
+                       if ((cbname = switch_channel_get_variable(channel, "secondary_recovery_module"))) {
+                               switch_core_recover_callback_t recover_callback;
+                               
+                               if ((recover_callback = switch_core_get_secondary_recover_callback(cbname))) {
+                                       r = recover_callback(session);
+                               }
+                       }
+                       
+                       
+               }
+               
+               if (r > 0) {
+
+                       if (!switch_channel_test_flag(channel, CF_RECOVERING_BRIDGE)) {
                                switch_xml_t callflow, param, x_extension;
                                if ((extension = switch_caller_extension_new(session, "recovery", "recovery")) == 0) {
                                        abort();
index 5926e52586a08bdd6f2307b5915fe4a1aed5590a..6de6b9798e82da2135989e470d68f858bb1011be 100644 (file)
 static void switch_core_standard_on_init(switch_core_session_t *session)
 {
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Standard INIT\n", switch_channel_get_name(session->channel));
+
+       if (switch_channel_test_flag(session->channel, CF_RECOVERING_BRIDGE)) {
+               switch_channel_set_state(session->channel, CS_RESET);
+       } else {
+               if (switch_channel_test_flag(session->channel, CF_RECOVERING)) {
+                       switch_channel_set_state(session->channel, CS_EXECUTE);
+               } else {
+                       switch_channel_set_state(session->channel, CS_ROUTING);
+               }
+       }
 }
 
 static void switch_core_standard_on_hangup(switch_core_session_t *session)
@@ -104,6 +114,43 @@ static void switch_core_standard_on_reset(switch_core_session_t *session)
        switch_channel_set_variable(session->channel, "call_uuid", switch_core_session_get_uuid(session));
 
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Standard RESET\n", switch_channel_get_name(session->channel));
+
+       if (switch_channel_test_flag(session->channel, CF_RECOVERING_BRIDGE)) {
+               switch_core_session_t *other_session = NULL;
+               const char *uuid = switch_core_session_get_uuid(session);
+
+               if (switch_channel_test_flag(session->channel, CF_BRIDGE_ORIGINATOR)) {
+                       const char *other_uuid = switch_channel_get_partner_uuid(session->channel);
+                       int x = 0;
+
+                       if (other_uuid) {
+                               for (x = 0; other_session == NULL && x < 20; x++) {
+                                       if (!switch_channel_up(session->channel)) {
+                                               break;
+                                       }
+                                       other_session = switch_core_session_locate(other_uuid);
+                                       switch_yield(100000);
+                               }
+                       }
+
+                       if (other_session) {
+                               switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
+                               switch_channel_clear_flag(session->channel, CF_BRIDGE_ORIGINATOR);
+                               switch_channel_wait_for_state_timeout(other_channel, CS_RESET, 5000);
+                               switch_channel_wait_for_flag(other_channel, CF_MEDIA_ACK, SWITCH_TRUE, 2000, NULL);
+
+                               if (switch_channel_test_flag(session->channel, CF_PROXY_MODE) && switch_channel_test_flag(other_channel, CF_PROXY_MODE)) {
+                                       switch_ivr_signal_bridge(session, other_session);
+                               } else {
+                                       switch_ivr_uuid_bridge(uuid, other_uuid);
+                               }
+                               switch_core_session_rwunlock(other_session);
+                       }
+               }
+
+               switch_channel_clear_flag(session->channel, CF_RECOVERING_BRIDGE);
+       }
+
 }
 
 static void switch_core_standard_on_routing(switch_core_session_t *session)
@@ -208,6 +255,8 @@ static void switch_core_standard_on_execute(switch_core_session_t *session)
 
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Standard EXECUTE\n", switch_channel_get_name(session->channel));
 
+       switch_channel_clear_flag(session->channel, CF_RECOVERING);
+
        switch_channel_set_variable(session->channel, "call_uuid", switch_core_session_get_uuid(session));
 
        if (switch_channel_get_variable(session->channel, "recovered") && !switch_channel_test_flag(session->channel, CF_RECOVERED)) {
index 080a331dcd9f3cfab841b7b4f346063646b273f6..926b3d85f60163a1ee3b24ba4a143598eddbb2ba 100644 (file)
@@ -67,6 +67,15 @@ struct switch_event_subclass {
        int bind;
 };
 
+
+static struct {
+       switch_event_channel_id_t ID;
+       switch_thread_rwlock_t *rwlock;
+       switch_hash_t *hash;
+       switch_hash_t *lahash;
+       switch_mutex_t *lamutex;
+} event_channel_manager;
+
 #define MAX_DISPATCH_VAL 64
 static unsigned int MAX_DISPATCH = MAX_DISPATCH_VAL;
 static unsigned int SOFT_MAX_DISPATCH = 0;
@@ -81,10 +90,12 @@ static switch_memory_pool_t *THRUNTIME_POOL = NULL;
 static switch_thread_t *EVENT_DISPATCH_QUEUE_THREADS[MAX_DISPATCH_VAL] = { 0 };
 static uint8_t EVENT_DISPATCH_QUEUE_RUNNING[MAX_DISPATCH_VAL] = { 0 };
 static switch_queue_t *EVENT_DISPATCH_QUEUE = NULL;
+static switch_queue_t *EVENT_CHANNEL_DISPATCH_QUEUE = NULL;
 static switch_mutex_t *EVENT_QUEUE_MUTEX = NULL;
 static switch_hash_t *CUSTOM_HASH = NULL;
 static int THREAD_COUNT = 0;
 static int DISPATCH_THREAD_COUNT = 0;
+static int EVENT_CHANNEL_DISPATCH_THREAD_COUNT = 0;
 static int SYSTEM_RUNNING = 0;
 static uint64_t EVENT_SEQUENCE_NR = 0;
 #ifdef SWITCH_EVENT_RECYCLE
@@ -92,6 +103,8 @@ static switch_queue_t *EVENT_RECYCLE_QUEUE = NULL;
 static switch_queue_t *EVENT_HEADER_RECYCLE_QUEUE = NULL;
 #endif
 
+static void unsub_all_switch_event_channel(void);
+
 static char *my_dup(const char *s)
 {
        size_t len = strlen(s) + 1;
@@ -518,6 +531,13 @@ SWITCH_DECLARE(switch_status_t) switch_event_shutdown(void)
        SYSTEM_RUNNING = 0;
        switch_mutex_unlock(EVENT_QUEUE_MUTEX);
 
+       unsub_all_switch_event_channel();
+
+       if (EVENT_CHANNEL_DISPATCH_QUEUE) {
+               switch_queue_trypush(EVENT_CHANNEL_DISPATCH_QUEUE, NULL);
+               switch_queue_interrupt_all(EVENT_CHANNEL_DISPATCH_QUEUE);
+       }
+
        if (runtime.events_use_dispatch) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Stopping dispatch queues\n");
 
@@ -565,6 +585,8 @@ SWITCH_DECLARE(switch_status_t) switch_event_shutdown(void)
                }
        }
 
+       switch_core_hash_destroy(&event_channel_manager.lahash);
+
        switch_core_hash_destroy(&CUSTOM_HASH);
        switch_core_memory_reclaim_events();
 
@@ -633,14 +655,6 @@ SWITCH_DECLARE(void) switch_event_launch_dispatch_threads(uint32_t max)
 
 SWITCH_DECLARE(switch_status_t) switch_event_init(switch_memory_pool_t *pool)
 {
-       //switch_threadattr_t *thd_attr;
-
-       /*
-          This statement doesn't do anything commenting it out for now.
-
-          switch_assert(switch_arraylen(EVENT_NAMES)  == SWITCH_EVENT_ALL + 1);
-        */
-
        /* don't need any more dispatch threads than we have CPU's*/
        MAX_DISPATCH = (switch_core_cpu_count() / 2) + 1;
        if (MAX_DISPATCH < 2) {
@@ -656,6 +670,13 @@ SWITCH_DECLARE(switch_status_t) switch_event_init(switch_memory_pool_t *pool)
        switch_mutex_init(&EVENT_QUEUE_MUTEX, SWITCH_MUTEX_NESTED, RUNTIME_POOL);
        switch_core_hash_init(&CUSTOM_HASH, RUNTIME_POOL);
 
+       switch_core_hash_init(&event_channel_manager.lahash, RUNTIME_POOL);
+       switch_mutex_init(&event_channel_manager.lamutex, SWITCH_MUTEX_NESTED, RUNTIME_POOL);
+
+       switch_thread_rwlock_create(&event_channel_manager.rwlock, RUNTIME_POOL);
+       switch_core_hash_init(&event_channel_manager.hash, RUNTIME_POOL);
+       event_channel_manager.ID = 1;
+
        switch_mutex_lock(EVENT_QUEUE_MUTEX);
        SYSTEM_RUNNING = -1;
        switch_mutex_unlock(EVENT_QUEUE_MUTEX);
@@ -1733,13 +1754,11 @@ SWITCH_DECLARE(switch_status_t) switch_event_create_json(switch_event_t **event,
        return SWITCH_STATUS_SUCCESS;
 }
 
-SWITCH_DECLARE(switch_status_t) switch_event_serialize_json(switch_event_t *event, char **str)
+SWITCH_DECLARE(switch_status_t) switch_event_serialize_json_obj(switch_event_t *event, cJSON **json)
 {
        switch_event_header_t *hp;
        cJSON *cj;
 
-       *str = NULL;
-
        cj = cJSON_CreateObject();
 
        for (hp = event->headers; hp; hp = hp->next) {
@@ -1768,12 +1787,27 @@ SWITCH_DECLARE(switch_status_t) switch_event_serialize_json(switch_event_t *even
                cJSON_AddItemToObject(cj, "_body", cJSON_CreateString(event->body));
        }
 
-       *str = cJSON_Print(cj);
-       cJSON_Delete(cj);
+       *json = cj;
 
        return SWITCH_STATUS_SUCCESS;
 }
 
+SWITCH_DECLARE(switch_status_t) switch_event_serialize_json(switch_event_t *event, char **str)
+{
+
+       cJSON *cj;
+       *str = NULL;
+
+       if (switch_event_serialize_json_obj(event, &cj) == SWITCH_STATUS_SUCCESS) {
+               *str = cJSON_PrintUnformatted(cj);
+               cJSON_Delete(cj);
+               
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       return SWITCH_STATUS_FALSE;
+}
+
 static switch_xml_t add_xml_header(switch_xml_t xml, char *name, char *value, int offset)
 {
        switch_xml_t header = switch_xml_add_child_d(xml, name, offset);
@@ -2528,6 +2562,36 @@ SWITCH_DECLARE(int) switch_event_check_permission_list(switch_event_t *list, con
        return r;
 }
 
+SWITCH_DECLARE(void) switch_json_add_presence_data_cols(switch_event_t *event, cJSON *json, const char *prefix)
+{
+       const char *data;
+
+       if (!prefix) prefix = "";
+
+       if ((data = switch_event_get_header(event, "presence_data_cols"))) {
+               char *cols[128] = { 0 };
+               char header_name[128] = "";
+               int col_count = 0, i = 0;
+               char *data_copy = NULL;
+
+               data_copy = strdup(data);
+
+               col_count = switch_split(data_copy, ':', cols);
+
+               for (i = 0; i < col_count; i++) {
+                       const char *val = NULL;
+                       switch_snprintf(header_name, sizeof(header_name), "%s%s", prefix, cols[i]);
+
+                       val = switch_event_get_header(event, cols[i]);
+                       json_add_child_string(json, header_name, val);
+               }
+
+               switch_safe_free(data_copy);
+       }
+
+}
+
+
 SWITCH_DECLARE(void) switch_event_add_presence_data_cols(switch_channel_t *channel, switch_event_t *event, const char *prefix)
 {
        const char *data;
@@ -2557,6 +2621,792 @@ SWITCH_DECLARE(void) switch_event_add_presence_data_cols(switch_channel_t *chann
 
 }
 
+struct switch_event_channel_sub_node_head_s;
+
+typedef struct switch_event_channel_sub_node_s {
+       switch_event_channel_func_t func;
+       switch_event_channel_id_t id;
+       struct switch_event_channel_sub_node_head_s *head;
+       struct switch_event_channel_sub_node_s *next;
+} switch_event_channel_sub_node_t;
+
+typedef struct switch_event_channel_sub_node_head_s {
+       switch_event_channel_sub_node_t *node;
+       switch_event_channel_sub_node_t *tail;
+       char *event_channel;
+} switch_event_channel_sub_node_head_t;
+
+static uint32_t switch_event_channel_unsub_head(switch_event_channel_func_t func, switch_event_channel_sub_node_head_t *head)
+{
+       uint32_t x = 0;
+
+       switch_event_channel_sub_node_t *thisnp = NULL, *np, *last = NULL;
+
+       np = head->tail = head->node;
+
+       while (np) {
+
+               thisnp = np;
+               np = np->next;
+
+               if (!func || thisnp->func == func) {
+                       x++;
+                       
+                       if (last) {
+                               last->next = np;
+                       } else {
+                               head->node = np;
+                       }
+
+
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "UNSUBBING %p [%s]\n", (void *)(intptr_t)thisnp->func, thisnp->head->event_channel);
+
+
+                       thisnp->func = NULL;
+                       free(thisnp);
+               } else {
+                       last = thisnp;
+                       head->tail = last;
+               }
+       }
+
+       return x;
+}
+
+static void unsub_all_switch_event_channel(void)
+{
+       switch_hash_index_t *hi;
+       void *val;
+       switch_event_channel_sub_node_head_t *head;
+
+       switch_thread_rwlock_wrlock(event_channel_manager.rwlock);
+ top:
+       head = NULL;
+
+       for (hi = switch_hash_first(NULL, event_channel_manager.hash); hi; hi = switch_hash_next(hi)) {
+               switch_hash_this(hi, NULL, NULL, &val);
+               head = (switch_event_channel_sub_node_head_t *) val;
+               switch_event_channel_unsub_head(NULL, head);
+               switch_core_hash_delete(event_channel_manager.hash, head->event_channel);
+               free(head->event_channel);
+               free(head);
+               goto top;
+       }
+
+       switch_thread_rwlock_unlock(event_channel_manager.rwlock);
+}
+
+static uint32_t switch_event_channel_unsub_channel(switch_event_channel_func_t func, const char *event_channel)
+{
+       switch_event_channel_sub_node_head_t *head;
+       uint32_t x = 0;
+
+       switch_thread_rwlock_wrlock(event_channel_manager.rwlock);
+
+       if (!event_channel) {
+               switch_hash_index_t *hi;
+               void *val;
+
+               for (hi = switch_hash_first(NULL, event_channel_manager.hash); hi; hi = switch_hash_next(hi)) {
+                       switch_hash_this(hi, NULL, NULL, &val);
+
+                       if (val) {
+                               head = (switch_event_channel_sub_node_head_t *) val;
+                               x += switch_event_channel_unsub_head(func, head);
+                       }
+               }
+
+       } else {
+               if ((head = switch_core_hash_find(event_channel_manager.hash, event_channel))) {
+                       x += switch_event_channel_unsub_head(func, head);
+               }
+       }
+
+       switch_thread_rwlock_unlock(event_channel_manager.rwlock);
+
+       return x;
+}
+
+static switch_status_t switch_event_channel_sub_channel(const char *event_channel, switch_event_channel_func_t func, switch_event_channel_id_t id)
+                                                                                                               
+{
+       switch_event_channel_sub_node_t *node, *np;
+       switch_event_channel_sub_node_head_t *head;
+       switch_status_t status = SWITCH_STATUS_FALSE;
+
+       switch_thread_rwlock_wrlock(event_channel_manager.rwlock);
+
+       if (!(head = switch_core_hash_find(event_channel_manager.hash, event_channel))) {
+               switch_zmalloc(head, sizeof(*head));
+               head->event_channel = strdup(event_channel);
+               switch_core_hash_insert(event_channel_manager.hash, event_channel, head);
+
+               switch_zmalloc(node, sizeof(*node));
+               node->func = func;
+               node->id = id;
+
+               node->head = head;
+               head->node = node;
+               head->tail = node;
+               status = SWITCH_STATUS_SUCCESS;
+       } else {
+               int exist = 0;
+
+               for (np = head->node; np; np = np->next) {
+                       if (np->func == func) {
+                               exist = 1;
+                               break;
+                       }
+               }
+
+               if (!exist) {
+                       switch_zmalloc(node, sizeof(*node));
+
+                       node->func = func;
+                       node->id = id;
+                       node->head = head;
+
+
+                       if (!head->node) {
+                               head->node = node;
+                               head->tail = node;
+                       } else {
+                               head->tail->next = node;
+                               head->tail = head->tail->next;
+                       }
+                       status = SWITCH_STATUS_SUCCESS;
+               }
+       }
+
+       switch_thread_rwlock_unlock(event_channel_manager.rwlock);
+
+       return status;
+}
+
+typedef struct {
+       char *event_channel;
+       cJSON *json;
+       char *key;
+       switch_event_channel_id_t id;
+} event_channel_data_t;
+
+
+
+static uint32_t _switch_event_channel_broadcast(const char *event_channel, const char *broadcast_channel, 
+                                                                                               cJSON *json, const char *key, switch_event_channel_id_t id)
+{
+       switch_event_channel_sub_node_t *np;
+       switch_event_channel_sub_node_head_t *head;
+       uint32_t x = 0;
+
+       switch_thread_rwlock_rdlock(event_channel_manager.rwlock);
+       if ((head = switch_core_hash_find(event_channel_manager.hash, event_channel))) {
+               for (np = head->node; np; np = np->next) {
+                       if (np->id == id) {
+                               continue;
+                       }
+                       np->func(broadcast_channel, json, key, id);
+                       x++;
+               }
+       }
+       switch_thread_rwlock_unlock(event_channel_manager.rwlock);
+
+       return x;
+}
+
+static void destroy_ecd(event_channel_data_t **ecdP)
+{
+       event_channel_data_t *ecd = *ecdP;
+       *ecdP = NULL;
+
+       switch_safe_free(ecd->event_channel);
+       switch_safe_free(ecd->key);
+       if (ecd->json) {
+               cJSON_Delete(ecd->json);
+               ecd->json = NULL;
+       }
+
+       free(ecd);
+}
+
+static void ecd_deliver(event_channel_data_t **ecdP)
+{
+       event_channel_data_t *ecd = *ecdP;
+       char *p;
+
+       *ecdP = NULL;
+
+       _switch_event_channel_broadcast(ecd->event_channel, ecd->event_channel, ecd->json, ecd->key, ecd->id);
+       
+       if ((p = strchr(ecd->event_channel, '.'))) {
+               char *main_channel = strdup(ecd->event_channel);
+               p = strchr(main_channel, '.');
+               *p = '\0';
+               _switch_event_channel_broadcast(main_channel, ecd->event_channel, ecd->json, ecd->key, ecd->id);
+               free(main_channel);
+       }
+       _switch_event_channel_broadcast(SWITCH_EVENT_CHANNEL_GLOBAL, ecd->event_channel, ecd->json, ecd->key, ecd->id);
+
+       destroy_ecd(&ecd);
+}
+
+static void *SWITCH_THREAD_FUNC switch_event_channel_deliver_thread(switch_thread_t *thread, void *obj)
+{
+       switch_queue_t *queue = (switch_queue_t *) obj;
+       void *pop = NULL;
+       event_channel_data_t *ecd = NULL;
+
+       switch_mutex_lock(EVENT_QUEUE_MUTEX);
+       THREAD_COUNT++;
+       EVENT_CHANNEL_DISPATCH_THREAD_COUNT++;
+       switch_mutex_unlock(EVENT_QUEUE_MUTEX);
+
+       while(SYSTEM_RUNNING) {
+               
+               if (switch_queue_pop(queue, &pop) != SWITCH_STATUS_SUCCESS) {
+                       continue;
+               }
+
+               if (!pop) {
+                       break;
+               }
+
+               ecd = (event_channel_data_t *) pop;
+               ecd_deliver(&ecd);
+               switch_os_yield();
+       }
+
+       while (switch_queue_trypop(queue, &pop) == SWITCH_STATUS_SUCCESS) {
+               ecd = (event_channel_data_t *) pop;
+               destroy_ecd(&ecd);
+       }
+
+       switch_mutex_lock(EVENT_QUEUE_MUTEX);
+       THREAD_COUNT--;
+       EVENT_CHANNEL_DISPATCH_THREAD_COUNT--;
+       switch_mutex_unlock(EVENT_QUEUE_MUTEX);
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Event Channel Dispatch Thread Ended.\n");
+       return NULL;    
+}
+
+SWITCH_DECLARE(switch_status_t) switch_event_channel_broadcast(const char *event_channel, cJSON **json, const char *key, switch_event_channel_id_t id)
+{
+       event_channel_data_t *ecd = NULL;
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+       if (!SYSTEM_RUNNING) {
+               cJSON_Delete(*json);
+               *json = NULL;
+               return SWITCH_STATUS_FALSE;
+       }
+
+       switch_zmalloc(ecd, sizeof(*ecd));
+
+       ecd->event_channel = strdup(event_channel);
+       ecd->json = *json;
+       ecd->key = strdup(key);
+       ecd->id = id;
+
+       *json = NULL;
+
+       if (!EVENT_CHANNEL_DISPATCH_THREAD_COUNT && SYSTEM_RUNNING) {
+               switch_thread_data_t *td;
+       
+               if (!EVENT_CHANNEL_DISPATCH_QUEUE) {
+                       switch_queue_create(&EVENT_CHANNEL_DISPATCH_QUEUE, DISPATCH_QUEUE_LEN * MAX_DISPATCH, THRUNTIME_POOL);
+               }
+
+               td = malloc(sizeof(*td));
+               switch_assert(td);
+               
+               td->alloc = 1;
+               td->func = switch_event_channel_deliver_thread;
+               td->obj = EVENT_CHANNEL_DISPATCH_QUEUE;
+               td->pool = NULL;
+               
+               switch_thread_pool_launch_thread(&td);
+       }
+
+       if ((status = switch_queue_trypush(EVENT_CHANNEL_DISPATCH_QUEUE, ecd) != SWITCH_STATUS_SUCCESS)) {
+               cJSON_Delete(ecd->json);
+               ecd->json = NULL;
+               destroy_ecd(&ecd);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Event Channel Queue failure for channel %s\n", event_channel);
+       } else {
+               ecd = NULL;
+       }
+       
+       return status;
+}
+
+SWITCH_DECLARE(uint32_t) switch_event_channel_unbind(const char *event_channel, switch_event_channel_func_t func)
+{
+       return switch_event_channel_unsub_channel(func, event_channel);
+}
+
+SWITCH_DECLARE(switch_status_t) switch_event_channel_bind(const char *event_channel, switch_event_channel_func_t func, switch_event_channel_id_t *id)
+                                                                                                                 
+{
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+       switch_assert(id);
+
+       if (!*id) {
+               switch_thread_rwlock_wrlock(event_channel_manager.rwlock);
+               *id = event_channel_manager.ID++;
+               switch_thread_rwlock_unlock(event_channel_manager.rwlock);
+       }
+
+       status = switch_event_channel_sub_channel(event_channel, func, *id);
+
+       return status;
+}
+
+typedef struct la_node_s {
+       char *name;
+       cJSON *obj;
+       struct la_node_s *next;
+       int pos;
+} la_node_t;
+
+struct switch_live_array_s {
+       char *event_channel;
+       char *name;
+       char *key;
+       la_node_t *head;
+       la_node_t *tail;
+       switch_memory_pool_t *pool;
+       switch_hash_t *hash;
+       switch_mutex_t *mutex;
+       uint32_t serno;
+       int pos;
+       switch_bool_t visible;
+       switch_bool_t new;
+       switch_event_channel_id_t channel_id;
+       switch_live_array_command_handler_t command_handler;
+       void *user_data;
+};
+
+
+SWITCH_DECLARE(switch_status_t) switch_live_array_visible(switch_live_array_t *la, switch_bool_t visible, switch_bool_t force)
+{
+       switch_status_t status = SWITCH_STATUS_FALSE;
+
+       switch_mutex_lock(la->mutex);
+       if (la->visible != visible || force) {
+               cJSON *msg, *data;
+               
+               msg = cJSON_CreateObject();
+               data = json_add_child_obj(msg, "data", NULL);
+
+               cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(la->event_channel));
+               cJSON_AddItemToObject(data, "action", cJSON_CreateString(visible ? "hide" : "show"));
+               cJSON_AddItemToObject(data, "wireSerno", cJSON_CreateNumber(la->serno++));
+               
+               switch_event_channel_broadcast(la->event_channel, &msg, __FILE__, la->channel_id);
+
+               la->visible = visible;
+       }
+       switch_mutex_unlock(la->mutex);
+
+       return status;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_live_array_clear(switch_live_array_t *la)
+{
+       la_node_t *cur, *np;
+       cJSON *msg, *data;
+
+       switch_mutex_lock(la->mutex);
+       np = la->head;
+
+       msg = cJSON_CreateObject();
+       data = json_add_child_obj(msg, "data", NULL);
+
+       cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(la->event_channel));
+       cJSON_AddItemToObject(data, "action", cJSON_CreateString("clear"));
+       cJSON_AddItemToObject(data, "name", cJSON_CreateString(la->name));
+       cJSON_AddItemToObject(data, "wireSerno", cJSON_CreateNumber(-1));
+       cJSON_AddItemToObject(data, "data", cJSON_CreateObject());
+       
+       switch_event_channel_broadcast(la->event_channel, &msg, __FILE__, la->channel_id);
+
+       while(np) {
+               cur = np;
+               cJSON_Delete(cur->obj);
+               free(cur->name);
+               free(cur);
+               np = np->next;
+       }
+
+       la->head = la->tail = NULL;
+       
+       switch_mutex_unlock(la->mutex);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_live_array_bootstrap(switch_live_array_t *la, const char *sessid, switch_event_channel_id_t channel_id)
+{
+       la_node_t *np;
+       cJSON *msg, *data;
+
+       switch_mutex_lock(la->mutex);
+
+#if OLD_WAY
+       msg = cJSON_CreateObject();
+       data = json_add_child_obj(msg, "data", NULL);
+
+       cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(la->event_channel));
+       cJSON_AddItemToObject(data, "action", cJSON_CreateString("clear"));
+       cJSON_AddItemToObject(data, "name", cJSON_CreateString(la->name));
+       cJSON_AddItemToObject(data, "wireSerno", cJSON_CreateNumber(-1));
+       cJSON_AddItemToObject(data, "data", cJSON_CreateObject());
+       
+       switch_event_channel_broadcast(la->event_channel, &msg, __FILE__, channel_id);
+
+       for (np = la->head; np; np = np->next) {
+               msg = cJSON_CreateObject();
+               data = json_add_child_obj(msg, "data", NULL);
+
+               cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(la->event_channel));
+               cJSON_AddItemToObject(data, "action", cJSON_CreateString("add"));
+               cJSON_AddItemToObject(data, "name", cJSON_CreateString(la->name));
+               cJSON_AddItemToObject(data, "hashKey", cJSON_CreateString(np->name));
+               cJSON_AddItemToObject(data, "wireSerno", cJSON_CreateNumber(la->serno++));
+               cJSON_AddItemToObject(data, "data", cJSON_Duplicate(np->obj, 1));
+               if (sessid) {
+                       cJSON_AddItemToObject(msg, "sessid", cJSON_CreateString(sessid));
+               }
+               switch_event_channel_broadcast(la->event_channel, &msg, __FILE__, channel_id);
+       }
+#else
+
+
+       msg = cJSON_CreateObject();
+       data = json_add_child_obj(msg, "data", NULL);
+       
+       cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(la->event_channel));
+       cJSON_AddItemToObject(data, "action", cJSON_CreateString("bootObj"));
+       cJSON_AddItemToObject(data, "name", cJSON_CreateString(la->name));
+       cJSON_AddItemToObject(data, "wireSerno", cJSON_CreateNumber(la->serno++));
+
+       if (sessid) {
+               cJSON_AddItemToObject(msg, "sessid", cJSON_CreateString(sessid));
+       }
+
+       data = json_add_child_array(data, "data");
+
+       for (np = la->head; np; np = np->next) {
+               cJSON *row = cJSON_CreateArray();
+               cJSON_AddItemToArray(row, cJSON_CreateString(np->name));
+               cJSON_AddItemToArray(row, cJSON_Duplicate(np->obj, 1));
+               cJSON_AddItemToArray(data, row);
+       }
+       
+       switch_event_channel_broadcast(la->event_channel, &msg, __FILE__, channel_id);
+
+
+#endif
+
+       if (!la->visible) {
+               switch_live_array_visible(la, SWITCH_FALSE, SWITCH_TRUE);
+       }
+
+       switch_mutex_unlock(la->mutex);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_live_array_destroy(switch_live_array_t **live_arrayP)
+{
+       switch_live_array_t *la = *live_arrayP;
+       switch_memory_pool_t *pool;
+
+       *live_arrayP = NULL;
+
+       pool = la->pool;
+
+       switch_live_array_clear(la);
+       
+       switch_core_hash_destroy(&la->hash);
+
+       switch_mutex_lock(event_channel_manager.lamutex);
+       switch_core_hash_delete(event_channel_manager.lahash, la->key);
+       switch_mutex_unlock(event_channel_manager.lamutex);
+
+       switch_core_destroy_memory_pool(&pool);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_DECLARE(switch_bool_t) switch_live_array_isnew(switch_live_array_t *la)
+{
+       return la->new;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_live_array_create(const char *event_channel, const char *name, 
+                                                                                                                switch_event_channel_id_t channel_id, switch_live_array_t **live_arrayP)
+{
+       switch_live_array_t *la = NULL;
+       switch_memory_pool_t *pool;
+       char *key = NULL;
+
+       switch_core_new_memory_pool(&pool);
+       key = switch_core_sprintf(pool, "%s.%s", event_channel, name);
+
+       switch_mutex_lock(event_channel_manager.lamutex); 
+       la = switch_core_hash_find(event_channel_manager.lahash, key);
+       switch_mutex_unlock(event_channel_manager.lamutex);
+       
+       if (la) {
+               la->new = SWITCH_FALSE;
+       } else {
+               la = switch_core_alloc(pool, sizeof(*la));
+               la->pool = pool;
+               la->serno = 1;
+               la->visible = SWITCH_TRUE;
+               la->event_channel = switch_core_strdup(la->pool, event_channel);
+               la->name = switch_core_strdup(la->pool, name);
+               la->key = key;
+               la->new = SWITCH_TRUE;
+               la->channel_id = channel_id;
+               switch_core_hash_init(&la->hash, la->pool);
+               switch_mutex_init(&la->mutex, SWITCH_MUTEX_NESTED, la->pool);
+               
+               switch_mutex_lock(event_channel_manager.lamutex);
+               switch_core_hash_insert(event_channel_manager.lahash, la->key, la);
+               switch_mutex_unlock(event_channel_manager.lamutex);
+       }
+
+       *live_arrayP = la;
+       
+       return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_DECLARE(cJSON *) switch_live_array_get(switch_live_array_t *la, const char *name)
+{
+       la_node_t *node;
+       cJSON *dup = NULL;
+
+       switch_mutex_lock(la->mutex);
+       if ((node = switch_core_hash_find(la->hash, name))) {
+               dup = cJSON_Duplicate(node->obj, 1); 
+       }
+       switch_mutex_unlock(la->mutex);
+
+       return dup;
+}
+
+SWITCH_DECLARE(cJSON *) switch_live_array_get_idx(switch_live_array_t *la, int idx)
+{
+       la_node_t *node;
+       cJSON *dup = NULL;
+
+       switch_mutex_lock(la->mutex);
+       for (node = la->head; node; node = node->next) {
+               if (node->pos == idx) {
+                       dup = cJSON_Duplicate(node->obj, 1); 
+                       break;
+               }
+       }
+       switch_mutex_unlock(la->mutex);
+       
+       return dup;
+}
+
+SWITCH_DECLARE(void) switch_live_array_lock(switch_live_array_t *la)
+{
+       switch_mutex_lock(la->mutex);
+}
+
+SWITCH_DECLARE(void) switch_live_array_unlock(switch_live_array_t *la)
+{
+       switch_mutex_unlock(la->mutex);
+}
+
+SWITCH_DECLARE(switch_status_t) switch_live_array_del(switch_live_array_t *la, const char *name)
+{
+       switch_status_t status = SWITCH_STATUS_FALSE;
+       la_node_t *node, *cur, *np, *last = NULL;
+       cJSON *msg, *data = NULL;
+
+       switch_mutex_lock(la->mutex);
+       if ((node = switch_core_hash_find(la->hash, name))) {
+               np = la->head;
+               
+               while(np) {
+                       cur = np;
+                       np = np->next;
+
+                       if (cur == node) {
+                               if (last) {
+                                       last->next = cur->next;
+                               } else {
+                                       la->head = cur->next;
+                               }
+                               switch_core_hash_delete(la->hash, name);
+
+                               msg = cJSON_CreateObject();
+                               data = json_add_child_obj(msg, "data", NULL);
+
+                               cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(la->event_channel));
+                               cJSON_AddItemToObject(data, "name", cJSON_CreateString(la->name));
+                               cJSON_AddItemToObject(data, "action", cJSON_CreateString("del"));
+                               cJSON_AddItemToObject(data, "hashKey", cJSON_CreateString(cur->name));
+                               cJSON_AddItemToObject(data, "wireSerno", cJSON_CreateNumber(la->serno++));
+                               cJSON_AddItemToObject(data, "data", cur->obj);
+                               cur->obj = NULL;
+
+                               switch_event_channel_broadcast(la->event_channel, &msg, __FILE__, la->channel_id);
+                               free(cur->name);
+                               free(cur);
+                       } else {
+                               cur->pos = la->pos++;
+                               la->tail = cur;
+                               last = cur;
+                       }
+               }
+       }
+       switch_mutex_unlock(la->mutex);
+
+       return status;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_live_array_add(switch_live_array_t *la, const char *name, int index, cJSON **obj, switch_bool_t duplicate)
+{
+       la_node_t *node;
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
+       const char *action = "add";
+       cJSON *msg = NULL, *data = NULL;
+
+       switch_mutex_lock(la->mutex);
+
+       if ((node = switch_core_hash_find(la->hash, name))) {
+
+               action = "modify";
+
+               if (node->obj) {
+                       if (duplicate) {
+                               cJSON_Delete(node->obj);
+                               node->obj = NULL;
+                       }
+               }
+       } else {
+               switch_zmalloc(node, sizeof(*node));
+
+               node->name = strdup(name);
+               switch_core_hash_insert(la->hash, name, node);
+
+               if (index > -1 && index < la->pos && la->head) {
+                       la_node_t *np, *last = NULL;
+                       int i = 0;
+                       
+                       for(np = la->head; np; np = np->next) {
+                               
+                               if (i == index) {
+                                       if (last) {
+                                               node->next = last->next;
+                                               last->next = node;
+                                               np = node;
+                                       } else {
+                                               node->next = la->head;
+                                               la->head = node;
+                                               np = node;
+                                       }
+                               }
+
+                               np->pos = i;
+                               la->tail = np;
+                               last = np;
+                               i++;
+                       }
+                       
+
+               } else {
+
+                       node->pos = la->pos++;
+                       index = node->pos;
+
+                       if (!la->head) {
+                               la->head = node;
+                       } else {
+                               la->tail->next = node;
+                       }
+
+                       la->tail = node;
+               }
+       }
+
+       if (duplicate) {
+               node->obj = cJSON_Duplicate(*obj, 1);
+       } else {
+               node->obj = *obj;
+       }
+
+       msg = cJSON_CreateObject();
+       data = json_add_child_obj(msg, "data", NULL);
+       
+       cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(la->event_channel));
+       cJSON_AddItemToObject(data, "action", cJSON_CreateString(action));
+
+       if (index > -1) {
+               cJSON_AddItemToObject(data, "arrIndex", cJSON_CreateNumber(index));
+       }
+
+       cJSON_AddItemToObject(data, "name", cJSON_CreateString(la->name));
+       cJSON_AddItemToObject(data, "hashKey", cJSON_CreateString(node->name));
+       cJSON_AddItemToObject(data, "wireSerno", cJSON_CreateNumber(la->serno++));
+       cJSON_AddItemToObject(data, "data", cJSON_Duplicate(node->obj, 1));
+
+       switch_event_channel_broadcast(la->event_channel, &msg, __FILE__, la->channel_id);
+       
+       switch_mutex_unlock(la->mutex);
+
+       return status;
+}
+
+SWITCH_DECLARE(void) switch_live_array_set_user_data(switch_live_array_t *la, void *user_data)
+{
+       switch_assert(la);
+       la->user_data = user_data;
+}
+
+SWITCH_DECLARE(void) switch_live_array_set_command_handler(switch_live_array_t *la, switch_live_array_command_handler_t command_handler)
+{
+       switch_assert(la);
+       la->command_handler = command_handler;
+}
+
+
+SWITCH_DECLARE(void) switch_live_array_parse_json(cJSON *json, switch_event_channel_id_t channel_id)
+{
+       const char *context = NULL, *name = NULL;
+       switch_live_array_t *la = NULL;
+       cJSON *jla = NULL;
+       
+       if ((jla = cJSON_GetObjectItem(json, "data")) && (jla = cJSON_GetObjectItem(jla, "liveArray"))) {
+
+               if ((context = cJSON_GetObjectCstr(jla, "context")) && (name = cJSON_GetObjectCstr(jla, "name"))) {
+                       const char *command = cJSON_GetObjectCstr(jla, "command");
+                       const char *sessid = cJSON_GetObjectCstr(json, "sessid");
+                       
+                       if (command) {
+                               switch_live_array_create(context, name, channel_id, &la);
+                               
+                               if (!strcasecmp(command, "bootstrap")) {
+                                       switch_live_array_bootstrap(la, sessid, channel_id);
+                               } else {
+                                       if (la->command_handler) {
+                                               la->command_handler(la, command, sessid, jla, la->user_data);
+                                       }
+                               }
+                       }
+               }
+       }
+
+}
 
 /* For Emacs:
  * Local Variables:
index 3819cda2d2227dbb5161b9cb1a6c31d69df14eaf..4467692dba4d3c63ba661157211002c562900174 100644 (file)
@@ -487,7 +487,20 @@ static char *print_object(cJSON *item,int depth,int fmt)
 /* Get Array size/item / object item. */
 SWITCH_DECLARE(int)   cJSON_GetArraySize(cJSON *array)                                                 {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
 SWITCH_DECLARE(cJSON *)cJSON_GetArrayItem(cJSON *array,int item)                               {cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;}
-SWITCH_DECLARE(cJSON *)cJSON_GetObjectItem(cJSON *object,const char *string)   {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
+SWITCH_DECLARE(cJSON *)cJSON_GetObjectItem(const cJSON *object,const char *string)     {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
+
+
+SWITCH_DECLARE(const char *)cJSON_GetObjectCstr(const cJSON *object, const char *string)       
+{
+       cJSON *cj = cJSON_GetObjectItem(object, string);
+
+       if (!cj || cj->type != cJSON_String || !cj->valuestring) return NULL;
+
+       return cj->valuestring;
+}
+
+
+
 
 /* Utility for array list handling. */
 static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
@@ -554,3 +567,27 @@ SWITCH_DECLARE(cJSON *) cJSON_Duplicate(cJSON *item,int recurse)
        }
        return newitem;
 }
+
+
+SWITCH_DECLARE(cJSON *) cJSON_CreateStringPrintf(const char *fmt, ...)
+{
+       va_list ap;
+       char *str;
+       cJSON *item;
+
+       va_start(ap, fmt);
+       str = switch_vmprintf(fmt, ap);
+       va_end(ap);
+
+       if (!str) return NULL;
+
+       if ((item = cJSON_New_Item())) {
+               item->type=cJSON_String;
+               item->valuestring = str;
+       } else {
+               free(str);
+       }
+
+       return item;
+}
+
index 8ffe90ea117e765f9aff0fdbb682c37f0aef25d5..c9fdda1da75d1a57abacc81b01eb785cd4301c60 100644 (file)
@@ -65,6 +65,7 @@ struct switch_loadable_module_container {
        switch_hash_t *application_hash;
        switch_hash_t *chat_application_hash;
        switch_hash_t *api_hash;
+       switch_hash_t *json_api_hash;
        switch_hash_t *file_hash;
        switch_hash_t *speech_hash;
        switch_hash_t *asr_hash;
@@ -73,6 +74,7 @@ struct switch_loadable_module_container {
        switch_hash_t *say_hash;
        switch_hash_t *management_hash;
        switch_hash_t *limit_hash;
+       switch_hash_t *secondary_recover_hash;
        switch_mutex_t *mutex;
        switch_memory_pool_t *pool;
 };
@@ -318,6 +320,29 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                }
        }
 
+       if (new_module->module_interface->json_api_interface) {
+               const switch_json_api_interface_t *ptr;
+
+               for (ptr = new_module->module_interface->json_api_interface; ptr; ptr = ptr->next) {
+                       if (!ptr->interface_name) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load JSON api interface from %s due to no interface name.\n", key);
+                       } else {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding JSON API Function '%s'\n", ptr->interface_name);
+                               if (switch_event_create(&event, SWITCH_EVENT_MODULE_LOAD) == SWITCH_STATUS_SUCCESS) {
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "json_api");
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "description", switch_str_nil(ptr->desc));
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "syntax", switch_str_nil(ptr->syntax));
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
+                                       switch_event_fire(&event);
+                                       added++;
+                               }
+                               switch_core_hash_insert(loadable_modules.json_api_hash, ptr->interface_name, (const void *) ptr);
+                       }
+               }
+       }
+
        if (new_module->module_interface->file_interface) {
                const switch_file_interface_t *ptr;
 
@@ -1047,6 +1072,36 @@ static switch_status_t switch_loadable_module_unprocess(switch_loadable_module_t
                }
        }
 
+       if (old_module->module_interface->json_api_interface) {
+               const switch_json_api_interface_t *ptr;
+
+               for (ptr = old_module->module_interface->json_api_interface; ptr; ptr = ptr->next) {
+                       if (ptr->interface_name) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Deleting API Function '%s'\n", ptr->interface_name);
+
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write lock interface '%s' to wait for existing references.\n",
+                                                                 ptr->interface_name);
+
+                               if (switch_thread_rwlock_trywrlock_timeout(ptr->rwlock, 10) == SWITCH_STATUS_SUCCESS) {
+                                       switch_thread_rwlock_unlock(ptr->rwlock);
+                               } else {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Giving up on '%s' waiting for existing references.\n", ptr->interface_name);
+                               }
+
+
+                               if (switch_event_create(&event, SWITCH_EVENT_MODULE_UNLOAD) == SWITCH_STATUS_SUCCESS) {
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "api");
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "description", switch_str_nil(ptr->desc));
+                                       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "syntax", switch_str_nil(ptr->syntax));
+                                       switch_event_fire(&event);
+                                       removed++;
+                               }
+                               switch_core_hash_delete(loadable_modules.json_api_hash, ptr->interface_name);
+                       }
+               }
+       }
+
        if (old_module->module_interface->file_interface) {
                const switch_file_interface_t *ptr;
 
@@ -1721,6 +1776,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autolo
        switch_core_hash_init_nocase(&loadable_modules.application_hash, loadable_modules.pool);
        switch_core_hash_init_nocase(&loadable_modules.chat_application_hash, loadable_modules.pool);
        switch_core_hash_init_nocase(&loadable_modules.api_hash, loadable_modules.pool);
+       switch_core_hash_init_nocase(&loadable_modules.json_api_hash, loadable_modules.pool);
        switch_core_hash_init(&loadable_modules.file_hash, loadable_modules.pool);
        switch_core_hash_init_nocase(&loadable_modules.speech_hash, loadable_modules.pool);
        switch_core_hash_init_nocase(&loadable_modules.asr_hash, loadable_modules.pool);
@@ -1730,6 +1786,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autolo
        switch_core_hash_init_nocase(&loadable_modules.management_hash, loadable_modules.pool);
        switch_core_hash_init_nocase(&loadable_modules.limit_hash, loadable_modules.pool);
        switch_core_hash_init_nocase(&loadable_modules.dialplan_hash, loadable_modules.pool);
+       switch_core_hash_init(&loadable_modules.secondary_recover_hash, loadable_modules.pool);
        switch_mutex_init(&loadable_modules.mutex, SWITCH_MUTEX_NESTED, loadable_modules.pool);
 
        if (!autoload) return SWITCH_STATUS_SUCCESS;
@@ -1945,6 +2002,7 @@ SWITCH_DECLARE(void) switch_loadable_module_shutdown(void)
        switch_core_hash_destroy(&loadable_modules.application_hash);
        switch_core_hash_destroy(&loadable_modules.chat_application_hash);
        switch_core_hash_destroy(&loadable_modules.api_hash);
+       switch_core_hash_destroy(&loadable_modules.json_api_hash);
        switch_core_hash_destroy(&loadable_modules.file_hash);
        switch_core_hash_destroy(&loadable_modules.speech_hash);
        switch_core_hash_destroy(&loadable_modules.asr_hash);
@@ -2014,6 +2072,7 @@ HASH_FUNC(timer)
 HASH_FUNC(application)
 HASH_FUNC(chat_application)
 HASH_FUNC(api)
+HASH_FUNC(json_api)
 HASH_FUNC(file)
 HASH_FUNC(speech)
 HASH_FUNC(asr)
@@ -2369,6 +2428,46 @@ SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char *
        return status;
 }
 
+SWITCH_DECLARE(switch_status_t) switch_json_api_execute(cJSON *json, switch_core_session_t *session, cJSON **retval)
+{
+       switch_json_api_interface_t *json_api;
+       switch_status_t status;
+       cJSON *function, *json_reply = NULL;
+
+       switch_assert(json);
+
+       function = cJSON_GetObjectItem(json, "command");
+
+       if (function && function->valuestring 
+               && cJSON_GetObjectItem(json, "data") && (json_api = switch_loadable_module_get_json_api_interface(function->valuestring)) != 0) {
+               if ((status = json_api->function(json, session, &json_reply)) != SWITCH_STATUS_SUCCESS) {
+                       cJSON_AddItemToObject(json, "status", cJSON_CreateString("error"));
+                       cJSON_AddItemToObject(json, "message", cJSON_CreateString("The command returned an error"));
+               } else {
+                       cJSON_AddItemToObject(json, "status", cJSON_CreateString("success"));
+               }
+               
+               if (!json_reply) {
+                       json_reply = cJSON_CreateNull();
+               }
+
+               if (retval) {
+                       *retval = json_reply;
+               } else {
+                       cJSON_AddItemToObject(json, "response", json_reply);
+               }
+               
+               UNPROTECT_INTERFACE(json_api);
+       } else {
+               status = SWITCH_STATUS_FALSE;
+               cJSON_AddItemToObject(json, "status", cJSON_CreateString("error"));
+               cJSON_AddItemToObject(json, "message", cJSON_CreateString("Invalid request or non-existant command"));
+               cJSON_AddItemToObject(json, "response", cJSON_CreateNull());
+       }
+
+       return status;
+}
+
 
 SWITCH_DECLARE(switch_loadable_module_interface_t *) switch_loadable_module_create_module_interface(switch_memory_pool_t *pool, const char *name)
 {
@@ -2425,6 +2524,9 @@ SWITCH_DECLARE(void *) switch_loadable_module_create_interface(switch_loadable_m
        case SWITCH_API_INTERFACE:
                ALLOC_INTERFACE(api)
 
+       case SWITCH_JSON_API_INTERFACE:
+               ALLOC_INTERFACE(json_api)
+
        case SWITCH_FILE_INTERFACE:
                ALLOC_INTERFACE(file)
 
@@ -2549,7 +2651,42 @@ SWITCH_DECLARE(void) switch_say_file(switch_say_file_handle_t *sh, const char *f
        va_end(ap);
 }
 
+SWITCH_DECLARE(switch_core_recover_callback_t) switch_core_get_secondary_recover_callback(const char *key)
+{
+       switch_core_recover_callback_t cb;
+
+       switch_mutex_lock(loadable_modules.mutex);
+       cb = (switch_core_recover_callback_t) (intptr_t) switch_core_hash_find(loadable_modules.secondary_recover_hash, key);
+       switch_mutex_unlock(loadable_modules.mutex);
+
+       return cb;
+}
+
+
+SWITCH_DECLARE(switch_status_t) switch_core_register_secondary_recover_callback(const char *key, switch_core_recover_callback_t cb)
+{
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+       switch_assert(cb);
+
+       switch_mutex_lock(loadable_modules.mutex);
+       if (switch_core_hash_find(loadable_modules.secondary_recover_hash, key)) {
+               status = SWITCH_STATUS_FALSE;
+       } else {
+               switch_core_hash_insert(loadable_modules.secondary_recover_hash, key, (void *)(intptr_t) cb);
+       }
+       switch_mutex_unlock(loadable_modules.mutex);
+
+       return status;
+}
+
 
+SWITCH_DECLARE(void) switch_core_unregister_secondary_recover_callback(const char *key)
+{
+       switch_mutex_lock(loadable_modules.mutex);
+       switch_core_hash_delete(loadable_modules.secondary_recover_hash, key);
+       switch_mutex_unlock(loadable_modules.mutex);
+}
 
 
 /* For Emacs:
index 47590b1430dcd20086c577d0760bf4e1a9d433c8..c3027b8ba3681656b66afc34245d031b307d382a 100644 (file)
@@ -61,7 +61,7 @@
 #define WRITE_INC(rtp_session)  switch_mutex_lock(rtp_session->write_mutex); rtp_session->writing++
 #define WRITE_DEC(rtp_session) switch_mutex_unlock(rtp_session->write_mutex); rtp_session->writing--
 
-#define RTP_STUN_FREQ 2000000
+#define RTP_STUN_FREQ 1000000
 #define rtp_header_len 12
 #define RTP_START_PORT 16384
 #define RTP_END_PORT 32768
@@ -713,7 +713,7 @@ static switch_status_t ice_out(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice)
                elapsed = (unsigned int) ((switch_micro_time_now() - rtp_session->last_stun) / 1000);
 
                if (elapsed > 30000) {
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "No stun for a long time!\n");
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "No %s stun for a long time!\n", rtp_type(rtp_session));
                        rtp_session->last_stun = switch_micro_time_now();
                        //status = SWITCH_STATUS_GENERR;
                        //goto end;
@@ -912,7 +912,7 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
                        char *host = NULL;
 
                        ice->missed_count++;
-                       //switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_CRIT, "missed %d\n", ice->missed_count);
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_WARNING, "missed %d\n", ice->missed_count);
 
                        if (elapsed > 20000 && pri) {
                                int i, j;
@@ -991,6 +991,8 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
        }
 
        if (ice->missed_count > 5) {
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_WARNING, "missed too many: %d, looking for new ICE dest.\n", 
+                                                 ice->missed_count);
                ice->rready = 0;
                ok = 1;
        }
@@ -1039,6 +1041,7 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
                                char buf[80] = "";
                                char buf2[80] = "";
                                const char *err = "";
+                               int i = 0;
 
                                ice->missed_count = 0;
                                ice->rready = 1;
@@ -1049,6 +1052,21 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
                                host2 = switch_get_addr(buf2, sizeof(buf2), ice->addr);
                                port2 = switch_sockaddr_get_port(ice->addr);
                                
+                               for (i = 0; i <= ice->ice_params->cand_idx; i++) {
+                                       if (ice->ice_params->cands[i][ice->proto].con_port == port) {
+                                               if (!strcmp(ice->ice_params->cands[i][ice->proto].con_addr, host) && 
+                                                       !strcmp(ice->ice_params->cands[i][ice->proto].cand_type, "relay")) {
+
+                                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_WARNING,
+                                                                                         "Skiping RELAY stun/%s/dtls port change from %s:%u to %s:%u\n", is_rtcp ? "rtcp" : "rtp", 
+                                                                                         host2, port2,
+                                                                                         host, port);
+
+                                                       goto end;
+                                               }
+                                       }
+                               }
+
                                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_NOTICE,
                                                                  "Auto Changing stun/%s/dtls port from %s:%u to %s:%u\n", is_rtcp ? "rtcp" : "rtp", 
                                                                  host2, port2,
@@ -1056,7 +1074,8 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
                                
                                ice->ice_params->cands[ice->ice_params->chosen[ice->proto]][ice->proto].con_addr = switch_core_strdup(rtp_session->pool, host);
                                ice->ice_params->cands[ice->ice_params->chosen[ice->proto]][ice->proto].con_port = port;
-                               
+                               ice->missed_count = 0;
+
                                switch_sockaddr_info_get(&ice->addr, host, SWITCH_UNSPEC, port, 0, rtp_session->pool);
 
                                if (!is_rtcp || rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) {
@@ -1369,7 +1388,7 @@ static void send_fir(switch_rtp_t *rtp_session)
                fir->ssrc = htonl(rtp_session->remote_ssrc);
                fir->seq = ++rtp_session->fir_seq;
                fir->r1 = fir->r2 = fir->r3 = 0;
-               
+
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Sending RTCP FIR %d\n", rtp_session->fir_seq);
                
                rtcp_bytes = sizeof(switch_rtcp_ext_hdr_t) + sizeof(rtcp_fir_t);
@@ -2377,6 +2396,26 @@ static int dtls_state_handshake(switch_rtp_t *rtp_session, switch_dtls_t *dtls)
        return 0;
 }
 
+static void free_dtls(switch_dtls_t **dtlsp)
+{
+       switch_dtls_t *dtls;
+
+       if (!dtlsp) {
+               return;
+       }
+
+       dtls = *dtlsp;
+       *dtlsp = NULL;
+
+       if (dtls->ssl) {
+               SSL_free(dtls->ssl);
+       }
+
+       if (dtls->ssl_ctx) {
+               SSL_CTX_free(dtls->ssl_ctx);
+       }
+}
+
 static int do_dtls(switch_rtp_t *rtp_session, switch_dtls_t *dtls)
 {
        int r = 0, ret = 0, len;
@@ -2384,16 +2423,17 @@ static int do_dtls(switch_rtp_t *rtp_session, switch_dtls_t *dtls)
        switch_size_t bytes;
 
        if (dtls->bytes) {
+
+               //if (dtls->state == DS_READY) {
+               //      
+               //}
+
                if ((ret = BIO_write(dtls->read_bio, dtls->data, dtls->bytes)) != (int)dtls->bytes) {
                        ret = SSL_get_error(dtls->ssl, ret);
                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "%s DTLS packet read err %d\n", rtp_type(rtp_session), ret);
                        dtls_set_state(dtls, DS_FAIL);
                        return -1;
                }
-
-               if (dtls->state == DS_READY) {
-                       dtls_set_state(dtls, DS_HANDSHAKE);
-               }
        }
 
        if (SSL_read(dtls->ssl, dtls->data, dtls->bytes) == (int)dtls->bytes) {
@@ -2453,6 +2493,30 @@ SWITCH_DECLARE(int) switch_rtp_has_dtls(void) {
 #endif
 }
 
+SWITCH_DECLARE(switch_status_t) switch_rtp_del_dtls(switch_rtp_t *rtp_session, dtls_type_t type)
+{
+
+       if (!rtp_session->dtls && !rtp_session->rtcp_dtls) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       if ((type & DTLS_TYPE_RTP)) {
+               if (rtp_session->dtls && rtp_session->dtls == rtp_session->rtcp_dtls) {
+                       rtp_session->rtcp_dtls = NULL;
+               }
+               
+               if (rtp_session->dtls) {
+                       free_dtls(&rtp_session->dtls);
+               }
+       }
+
+       if ((type & DTLS_TYPE_RTCP) && rtp_session->rtcp_dtls) {
+               free_dtls(&rtp_session->rtcp_dtls);
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
 SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, dtls_fingerprint_t *local_fp, dtls_fingerprint_t *remote_fp, dtls_type_t type)
 {
        switch_dtls_t *dtls;
@@ -2471,6 +2535,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_CRIT, "INVALID TYPE!\n");
        }
 
+       switch_rtp_del_dtls(rtp_session, type);
+       
        if ((type & DTLS_TYPE_RTP) && (type & DTLS_TYPE_RTCP)) {
                kind = "RTP/RTCP";
        } else if ((type & DTLS_TYPE_RTP)) {
@@ -2487,8 +2553,6 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d
                return SWITCH_STATUS_FALSE;
        }
 
-
-
        dtls = switch_core_alloc(rtp_session->pool, sizeof(*dtls));
 
                
@@ -2579,6 +2643,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d
                SSL_set_connect_state(dtls->ssl);
        }
 
+       rtp_session->flags[SWITCH_RTP_FLAG_VIDEO_BREAK] = 1;
+       switch_rtp_break(rtp_session);
                
        return SWITCH_STATUS_SUCCESS;
        
@@ -3328,6 +3394,12 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_sessio
 
        rtp_session->rtp_bugs |= RTP_BUG_ACCEPT_ANY_PACKETS;
 
+
+       if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) {
+               rtp_session->flags[SWITCH_RTP_FLAG_VIDEO_BREAK] = 1;
+               switch_rtp_break(rtp_session);
+       }
+
        return SWITCH_STATUS_SUCCESS;
 }
 
@@ -3360,7 +3432,10 @@ SWITCH_DECLARE(void) switch_rtp_break(switch_rtp_t *rtp_session)
        if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) {
                int ret = 1;
 
-               if (rtp_session->session) {
+               if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO_BREAK]) {
+                       rtp_session->flags[SWITCH_RTP_FLAG_VIDEO_BREAK] = 0;
+                       ret = 0;
+               } else if (rtp_session->session) {
                        switch_channel_t *channel = switch_core_session_get_channel(rtp_session->session);
                        if (switch_channel_test_flag(channel, CF_VIDEO_BREAK)) {
                                switch_channel_clear_flag(channel, CF_VIDEO_BREAK);
@@ -3369,6 +3444,8 @@ SWITCH_DECLARE(void) switch_rtp_break(switch_rtp_t *rtp_session)
                }
 
                if (ret) return;
+
+               switch_rtp_video_refresh(rtp_session);
        }
 
        switch_mutex_lock(rtp_session->flag_mutex);
@@ -3429,27 +3506,6 @@ SWITCH_DECLARE(uint8_t) switch_rtp_ready(switch_rtp_t *rtp_session)
        return ret;
 }
 
-static void free_dtls(switch_dtls_t **dtlsp)
-{
-       switch_dtls_t *dtls;
-
-       if (!dtlsp) {
-               return;
-       }
-
-       dtls = *dtlsp;
-       *dtlsp = NULL;
-
-       if (dtls->ssl) {
-               SSL_free(dtls->ssl);
-       }
-
-       if (dtls->ssl_ctx) {
-               SSL_CTX_free(dtls->ssl_ctx);
-       }
-}
-
-
 SWITCH_DECLARE(void) switch_rtp_destroy(switch_rtp_t **rtp_session)
 {
        void *pop;
@@ -4635,7 +4691,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
                                pt = 100000;
                        }
 
-
+                       
                        poll_status = switch_poll(rtp_session->read_pollfd, 1, &fdr, pt);
 
 
@@ -4651,10 +4707,12 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
 
                }
                
+                       
                if (poll_status == SWITCH_STATUS_SUCCESS) {
                        if (read_pretriggered) {
                                read_pretriggered = 0;
                        } else {
+
                                status = read_rtp_packet(rtp_session, &bytes, flags, SWITCH_TRUE);
 
                                if (status == SWITCH_STATUS_GENERR) {