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;
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);
\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
\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
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
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);
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);
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
\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);
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
/* 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);
#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
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 */
*/
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
*/
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
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); \
}
-
-
+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
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);
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);
#define SWITCH_TYPES_H
#include <switch.h>
+#include <switch_json.h>
SWITCH_BEGIN_EXTERN_C
#define SWITCH_ENT_ORIGINATE_DELIM ":_:"
#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
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 {
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;
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;
#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);
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
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;
}
{
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);
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)
//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++;
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++;
}
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;
}
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);
}
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)
return SWITCH_STATUS_FALSE;\r
\r
PTRACE(4, "mod_opal\tStarted routing for connection " << *this);\r
- switch_channel_set_state(m_fsChannel, CS_ROUTING);\r
+\r
return SWITCH_STATUS_SUCCESS;\r
}\r
\r
*/
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;
}
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);
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);
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 {
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));
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);
}
}
-
-
- 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);
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;
}
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)));
tech_pvt->session_refresher = nua_no_refresher;
}
-
-
if (sofia_use_soa(tech_pvt)) {
nua_respond(tech_pvt->nh, SIP_200_OK,
NUTAG_AUTOANSWER(0),
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)
switch_channel_get_name(channel), use_uuid);
}
}
-
- switch_core_media_recover_session(session);
-
}
r++;
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);
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;
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);
switch_mutex_unlock(channel->dtmf_mutex);
+ switch_core_media_break(channel->session, SWITCH_MEDIA_TYPE_AUDIO);
+
return status;
}
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);
{
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");
}
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;
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;
}
}
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)
{
*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 =
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;
}
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)
{
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)) {
#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;
} 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;
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]) {
j += 2;
}
+
if (engine->ice_in.chosen[cid]) {
engine->ice_in.cands[engine->ice_in.chosen[cid]][cid].ready++;
}
}
+ /* 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++) {
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);
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));
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
}
+ 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) {
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
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
}
}
-
+
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);
!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;
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)
{
}
}
-static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, void *obj)
+static void check_dtls_reinvite(switch_core_session_t *session, switch_rtp_engine_t *engine)
{
- struct media_helper *mh = obj;
- switch_core_session_t *session = mh->session;
- switch_channel_t *channel = switch_core_session_get_channel(session);
- switch_status_t status;
- switch_frame_t *read_frame;
- switch_media_handle_t *smh;
-
- if (!(smh = session->media_handle)) {
- return NULL;
- }
-
- switch_core_session_read_lock(session);
-
- mh->up = 1;
- switch_mutex_lock(mh->cond_mutex);
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread started. Echo is %s\n",
- switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
- switch_core_session_refresh_video(session);
-
- while (switch_channel_up_nosig(channel)) {
-
- if (switch_channel_test_flag(channel, CF_VIDEO_PASSIVE)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread paused. Echo is %s\n",
- switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
- switch_thread_cond_wait(mh->cond, mh->cond_mutex);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread resumed Echo is %s\n",
- switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
- switch_core_session_refresh_video(session);
- }
-
- if (switch_channel_test_flag(channel, CF_VIDEO_PASSIVE)) {
- continue;
- }
-
- if (!switch_channel_media_up(session->channel)) {
- switch_yield(10000);
- continue;
- }
+ if (switch_channel_test_flag(session->channel, CF_REINVITE)) {
+ if (!zstr(engine->local_dtls_fingerprint.str) && switch_rtp_has_dtls() && dtls_ok(session)) {
+ dtls_type_t xtype, dtype = switch_ice_direction(session) == SWITCH_CALL_DIRECTION_INBOUND ? DTLS_TYPE_CLIENT : DTLS_TYPE_SERVER;
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "RE-SETTING %s DTLS\n", type2str(engine->type));
- status = switch_core_session_read_video_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
+ xtype = DTLS_TYPE_RTP;
+ if (engine->rtcp_mux > 0) xtype |= DTLS_TYPE_RTCP;
+
+ switch_rtp_add_dtls(engine->rtp_session, &engine->local_dtls_fingerprint, &engine->remote_dtls_fingerprint, dtype | xtype);
- if (!SWITCH_READ_ACCEPTABLE(status)) {
- switch_cond_next();
- continue;
- }
+ if (engine->rtcp_mux < 1) {
+ xtype = DTLS_TYPE_RTCP;
+ switch_rtp_add_dtls(engine->rtp_session, &engine->local_dtls_fingerprint, &engine->remote_dtls_fingerprint, dtype | xtype);
+ }
-
- if (switch_channel_test_flag(channel, CF_VIDEO_REFRESH_REQ)) {
- switch_core_session_refresh_video(session);
- switch_channel_clear_flag(channel, CF_VIDEO_REFRESH_REQ);
- }
-
- if (switch_test_flag(read_frame, SFF_CNG)) {
- continue;
}
-
- if (switch_channel_test_flag(channel, CF_VIDEO_ECHO)) {
- switch_core_session_write_video_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0);
- }
-
}
-
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread ended\n", switch_channel_get_name(session->channel));
-
- switch_mutex_unlock(mh->cond_mutex);
- switch_core_session_rwunlock(session);
-
- mh->up = 0;
- return NULL;
}
-
-
-
//?
SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_session_t *session)
switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
}
}
+
+ if (session && a_engine) {
+ check_dtls_reinvite(session, a_engine);
+ }
+
goto video;
}
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
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
}
}
+ 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);
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);
}
}
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"))) {
!((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);
}
}
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)) {
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
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
video_up:
+ if (session && v_engine) {
+ check_dtls_reinvite(session, v_engine);
+ }
+
status = SWITCH_STATUS_SUCCESS;
end:
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);
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);
}
- 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,
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;
}
}
- 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);
}
}
- 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,
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 {
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);
}
-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;
}
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();
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)
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)
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)) {
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;
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
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;
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");
}
}
+ switch_core_hash_destroy(&event_channel_manager.lahash);
+
switch_core_hash_destroy(&CUSTOM_HASH);
switch_core_memory_reclaim_events();
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) {
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);
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) {
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);
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;
}
+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:
/* 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;}
}
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;
+}
+
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;
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;
};
}
}
+ 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;
}
}
+ 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;
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);
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;
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);
HASH_FUNC(application)
HASH_FUNC(chat_application)
HASH_FUNC(api)
+HASH_FUNC(json_api)
HASH_FUNC(file)
HASH_FUNC(speech)
HASH_FUNC(asr)
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)
{
case SWITCH_API_INTERFACE:
ALLOC_INTERFACE(api)
+ case SWITCH_JSON_API_INTERFACE:
+ ALLOC_INTERFACE(json_api)
+
case SWITCH_FILE_INTERFACE:
ALLOC_INTERFACE(file)
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:
#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
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;
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;
}
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;
}
char buf[80] = "";
char buf2[80] = "";
const char *err = "";
+ int i = 0;
ice->missed_count = 0;
ice->rready = 1;
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,
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]) {
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);
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;
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) {
#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;
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)) {
return SWITCH_STATUS_FALSE;
}
-
-
dtls = switch_core_alloc(rtp_session->pool, sizeof(*dtls));
SSL_set_connect_state(dtls->ssl);
}
+ rtp_session->flags[SWITCH_RTP_FLAG_VIDEO_BREAK] = 1;
+ switch_rtp_break(rtp_session);
return SWITCH_STATUS_SUCCESS;
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;
}
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);
}
if (ret) return;
+
+ switch_rtp_video_refresh(rtp_session);
}
switch_mutex_lock(rtp_session->flag_mutex);
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;
pt = 100000;
}
-
+
poll_status = switch_poll(rtp_session->read_pollfd, 1, &fdr, pt);
}
+
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) {