From 4a172402d2f10aba78317ccb192c891b393117bd Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 16 Oct 2013 02:24:32 +0500 Subject: [PATCH] some refactoring and plumbing for 1.4 --- src/include/private/switch_core_pvt.h | 2 +- src/include/switch_channel.h | 2 + src/include/switch_core.h | 7 +- src/include/switch_core_media.h | 3 + src/include/switch_event.h | 33 +- src/include/switch_json.h | 52 +- src/include/switch_loadable_module.h | 34 +- src/include/switch_module_interfaces.h | 18 + src/include/switch_rtp.h | 1 + src/include/switch_types.h | 27 +- src/mod/endpoints/mod_alsa/mod_alsa.c | 3 - .../endpoints/mod_dingaling/mod_dingaling.c | 6 +- .../mod_gsmopen/mod_gsmopen.c | 5 - src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp | 5 - src/mod/endpoints/mod_h323/mod_h323.cpp | 1 - src/mod/endpoints/mod_loopback/mod_loopback.c | 4 +- src/mod/endpoints/mod_opal/mod_opal.cpp | 2 +- .../endpoints/mod_portaudio/mod_portaudio.c | 5 - .../endpoints/mod_reference/mod_reference.c | 5 - src/mod/endpoints/mod_rtmp/mod_rtmp.c | 7 - src/mod/endpoints/mod_skinny/mod_skinny.c | 3 +- src/mod/endpoints/mod_skypopen/mod_skypopen.c | 11 +- src/mod/endpoints/mod_sofia/mod_sofia.c | 56 +- src/mod/endpoints/mod_sofia/rtp.c | 2 +- src/mod/endpoints/mod_sofia/sofia_glue.c | 3 - src/mod/endpoints/mod_unicall/mod_unicall.c | 5 - src/switch_channel.c | 30 +- src/switch_core_codec.c | 2 + src/switch_core_io.c | 4 +- src/switch_core_media.c | 407 +++++--- src/switch_core_session.c | 17 +- src/switch_core_sqldb.c | 27 +- src/switch_core_state_machine.c | 49 + src/switch_event.c | 876 +++++++++++++++++- src/switch_json.c | 39 +- src/switch_loadable_module.c | 137 +++ src/switch_rtp.c | 126 ++- 37 files changed, 1729 insertions(+), 287 deletions(-) diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index f6d3474386..bff9b72a78 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -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; diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 2e53ef6107..234b692114 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -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); diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 064ab56324..11340c211c 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -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 diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index 122f9f2b65..9641718f07 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -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 diff --git a/src/include/switch_event.h b/src/include/switch_event.h index 48c942dfaa..be60c17cd9 100644 --- a/src/include/switch_event.h +++ b/src/include/switch_event.h @@ -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 diff --git a/src/include/switch_json.h b/src/include/switch_json.h index 00f4e23df4..e1d7f1e51b 100755 --- a/src/include/switch_json.h +++ b/src/include/switch_json.h @@ -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 diff --git a/src/include/switch_loadable_module.h b/src/include/switch_loadable_module.h index 43e692c05b..e76e0e5ab1 100644 --- a/src/include/switch_loadable_module.h +++ b/src/include/switch_loadable_module.h @@ -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 diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index b6f4f11554..ad6b4aefd4 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -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); diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index f704d943d1..bd509cc29a 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -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); diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 27a88dcc73..ee42de2eee 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -38,6 +38,7 @@ #define SWITCH_TYPES_H #include +#include 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 diff --git a/src/mod/endpoints/mod_alsa/mod_alsa.c b/src/mod/endpoints/mod_alsa/mod_alsa.c index dcdf215fe4..55f4ca4ba3 100644 --- a/src/mod/endpoints/mod_alsa/mod_alsa.c +++ b/src/mod/endpoints/mod_alsa/mod_alsa.c @@ -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; } diff --git a/src/mod/endpoints/mod_dingaling/mod_dingaling.c b/src/mod/endpoints/mod_dingaling/mod_dingaling.c index 5fe5d89000..e7ecaaf949 100644 --- a/src/mod/endpoints/mod_dingaling/mod_dingaling.c +++ b/src/mod/endpoints/mod_dingaling/mod_dingaling.c @@ -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) diff --git a/src/mod/endpoints/mod_gsmopen/alsa_nogsmlib_nocplusplus/mod_gsmopen/mod_gsmopen.c b/src/mod/endpoints/mod_gsmopen/alsa_nogsmlib_nocplusplus/mod_gsmopen/mod_gsmopen.c index 9f25ee1d96..f6c9605cb2 100644 --- a/src/mod/endpoints/mod_gsmopen/alsa_nogsmlib_nocplusplus/mod_gsmopen/mod_gsmopen.c +++ b/src/mod/endpoints/mod_gsmopen/alsa_nogsmlib_nocplusplus/mod_gsmopen/mod_gsmopen.c @@ -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++; diff --git a/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp b/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp index 9e78b8f55b..b3b3c1546c 100644 --- a/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp +++ b/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp @@ -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++; diff --git a/src/mod/endpoints/mod_h323/mod_h323.cpp b/src/mod/endpoints/mod_h323/mod_h323.cpp index 17619129cf..adaf38deb1 100644 --- a/src/mod/endpoints/mod_h323/mod_h323.cpp +++ b/src/mod/endpoints/mod_h323/mod_h323.cpp @@ -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; } diff --git a/src/mod/endpoints/mod_loopback/mod_loopback.c b/src/mod/endpoints/mod_loopback/mod_loopback.c index c6cbfc8994..ee354ad90b 100644 --- a/src/mod/endpoints/mod_loopback/mod_loopback.c +++ b/src/mod/endpoints/mod_loopback/mod_loopback.c @@ -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) diff --git a/src/mod/endpoints/mod_opal/mod_opal.cpp b/src/mod/endpoints/mod_opal/mod_opal.cpp index 633bcdbd3a..6f0fb3addd 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.cpp +++ b/src/mod/endpoints/mod_opal/mod_opal.cpp @@ -853,7 +853,7 @@ switch_status_t FSConnection::on_init() return SWITCH_STATUS_FALSE; PTRACE(4, "mod_opal\tStarted routing for connection " << *this); - switch_channel_set_state(m_fsChannel, CS_ROUTING); + return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index 9ce6730d9e..7f66558c61 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -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; } diff --git a/src/mod/endpoints/mod_reference/mod_reference.c b/src/mod/endpoints/mod_reference/mod_reference.c index 08c27da0eb..ece46f8d63 100644 --- a/src/mod/endpoints/mod_reference/mod_reference.c +++ b/src/mod/endpoints/mod_reference/mod_reference.c @@ -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); diff --git a/src/mod/endpoints/mod_rtmp/mod_rtmp.c b/src/mod/endpoints/mod_rtmp/mod_rtmp.c index 339ce81873..e25f38b861 100644 --- a/src/mod/endpoints/mod_rtmp/mod_rtmp.c +++ b/src/mod/endpoints/mod_rtmp/mod_rtmp.c @@ -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); diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index cc94f1129f..0e1e700264 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -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 { diff --git a/src/mod/endpoints/mod_skypopen/mod_skypopen.c b/src/mod/endpoints/mod_skypopen/mod_skypopen.c index 024942e00e..b586bd0489 100644 --- a/src/mod/endpoints/mod_skypopen/mod_skypopen.c +++ b/src/mod/endpoints/mod_skypopen/mod_skypopen.c @@ -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); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index a4c8913ee5..b99c7aae96 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -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), diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index ea4921052e..953ea6d8f0 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -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) diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index f569a12dd2..833a725d44 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -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++; diff --git a/src/mod/endpoints/mod_unicall/mod_unicall.c b/src/mod/endpoints/mod_unicall/mod_unicall.c index 18cd5d11d5..35c3cde286 100644 --- a/src/mod/endpoints/mod_unicall/mod_unicall.c +++ b/src/mod/endpoints/mod_unicall/mod_unicall.c @@ -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); diff --git a/src/switch_channel.c b/src/switch_channel.c index ae94061c26..76d3d49f97 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -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"); diff --git a/src/switch_core_codec.c b/src/switch_core_codec.c index 0c27fdcb46..bd3b521a98 100644 --- a/src/switch_core_codec.c +++ b/src/switch_core_codec.c @@ -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; diff --git a/src/switch_core_io.c b/src/switch_core_io.c index aad6192ece..47f6289a73 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -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; } } diff --git a/src/switch_core_media.c b/src/switch_core_media.c index d8553d0766..b412a518f5 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -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 (switch_channel_test_flag(session->channel, CF_REINVITE)) { - if (!(smh = session->media_handle)) { - return NULL; + 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)); + + 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 (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); + } + + } } - - 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; } - - - //? 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); diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 430b20d013..52cb871aa9 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -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; } diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index a9c8d22fbc..7dd02df818 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -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(); diff --git a/src/switch_core_state_machine.c b/src/switch_core_state_machine.c index 5926e52586..6de6b9798e 100644 --- a/src/switch_core_state_machine.c +++ b/src/switch_core_state_machine.c @@ -38,6 +38,16 @@ 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)) { diff --git a/src/switch_event.c b/src/switch_event.c index 080a331dcd..926b3d85f6 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -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: diff --git a/src/switch_json.c b/src/switch_json.c index 3819cda2d2..4467692dba 100644 --- a/src/switch_json.c +++ b/src/switch_json.c @@ -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; +} + diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c index 8ffe90ea11..c9fdda1da7 100644 --- a/src/switch_loadable_module.c +++ b/src/switch_loadable_module.c @@ -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: diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 47590b1430..c3027b8ba3 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -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) {