mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-10-21 10:44:16 +00:00
Merge branch 'master' into smgmaster
Conflicts: src/mod/endpoints/mod_sofia/mod_sofia.c
This commit is contained in:
commit
10d252b0fa
246 files changed
+15717
-6277
No files matched your search
@@ -31,7 +31,8 @@
|
||||
* this file does not exist!!!!
|
||||
*
|
||||
*/
|
||||
|
||||
#define SPANDSP_NO_TIFF 1
|
||||
#include "spandsp.h"
|
||||
#include "switch_profile.h"
|
||||
|
||||
#ifndef WIN32
|
||||
@@ -169,6 +170,7 @@ struct switch_core_session {
|
||||
switch_log_level_t loglevel;
|
||||
uint32_t soft_lock;
|
||||
switch_ivr_dmachine_t *dmachine;
|
||||
plc_state_t *plc;
|
||||
};
|
||||
|
||||
struct switch_media_bug {
|
||||
|
||||
@@ -1230,6 +1230,8 @@ SWITCH_DECLARE(int) switch_sockaddr_equal(const switch_sockaddr_t *sa1, const sw
|
||||
SWITCH_DECLARE(switch_status_t) switch_sockaddr_info_get(switch_sockaddr_t ** sa, const char *hostname,
|
||||
int32_t family, switch_port_t port, int32_t flags, switch_memory_pool_t *pool);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_sockaddr_create(switch_sockaddr_t **sa, switch_memory_pool_t *pool);
|
||||
|
||||
/**
|
||||
* Send data over a network.
|
||||
* @param sock The socket to send the data over.
|
||||
|
||||
@@ -312,6 +312,8 @@ SWITCH_DECLARE(switch_status_t) switch_channel_caller_extension_masquerade(switc
|
||||
*/
|
||||
SWITCH_DECLARE(void) switch_channel_set_caller_extension(switch_channel_t *channel, switch_caller_extension_t *caller_extension);
|
||||
|
||||
SWITCH_DECLARE(void) switch_channel_sort_cid(switch_channel_t *channel, switch_bool_t in);
|
||||
|
||||
/*!
|
||||
\brief Retrieve caller extension from a given channel
|
||||
\param channel channel to retrieve extension from
|
||||
|
||||
@@ -246,6 +246,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_close(_Inout_ switch_media
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all(_In_ switch_core_session_t *session);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_enumerate(switch_core_session_t *session, switch_stream_handle_t *stream);
|
||||
|
||||
/*!
|
||||
\brief Read a frame from the bug
|
||||
\param bug the bug to read from
|
||||
|
||||
@@ -216,6 +216,7 @@ SWITCH_DECLARE(void) consoleCleanLog(char *msg);
|
||||
char *tts_name;
|
||||
char *voice_name;
|
||||
|
||||
SWITCH_DECLARE(int) insertFile(const char *file, const char *insert_file, int sample_point);
|
||||
SWITCH_DECLARE(int) answer();
|
||||
SWITCH_DECLARE(int) preAnswer();
|
||||
SWITCH_DECLARE(void) hangup(const char *cause = "normal_clearing");
|
||||
|
||||
@@ -229,7 +229,14 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_sessi
|
||||
\param queue_frames the number of frames to delay
|
||||
\return SWITCH_STATUS_SUCCESS
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *rtp_session, uint32_t queue_frames);
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *rtp_session,
|
||||
uint32_t queue_frames,
|
||||
uint32_t max_queue_frames,
|
||||
uint32_t samples_per_packet, uint32_t samples_per_second);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_debug_jitter_buffer(switch_rtp_t *rtp_session, const char *name);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_deactivate_jitter_buffer(switch_rtp_t *rtp_session);
|
||||
|
||||
/*!
|
||||
\brief Set an RTP Flag
|
||||
|
||||
@@ -790,6 +790,8 @@ typedef enum {
|
||||
SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION,
|
||||
SWITCH_MESSAGE_INDICATE_UDPTL_MODE,
|
||||
SWITCH_MESSAGE_INDICATE_CLEAR_PROGRESS,
|
||||
SWITCH_MESSAGE_INDICATE_JITTER_BUFFER,
|
||||
SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH,
|
||||
SWITCH_MESSAGE_INVALID
|
||||
} switch_core_session_message_types_t;
|
||||
|
||||
@@ -1093,6 +1095,10 @@ typedef enum {
|
||||
CF_PASSTHRU_PTIME_MISMATCH,
|
||||
CF_BRIDGE_NOWRITE,
|
||||
CF_RECOVERED,
|
||||
CF_JITTERBUFFER,
|
||||
CF_DIALPLAN,
|
||||
CF_BLOCK_BROADCAST_UNTIL_MEDIA,
|
||||
CF_CNG_PLC,
|
||||
/* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */
|
||||
CF_FLAG_MAX
|
||||
} switch_channel_flag_t;
|
||||
|
||||
@@ -622,7 +622,7 @@ SWITCH_DECLARE(unsigned int) switch_separate_string(_In_ char *buf, char delim,
|
||||
SWITCH_DECLARE(unsigned int) switch_separate_string_string(char *buf, char *delim, _Post_count_(return) char **array, unsigned int arraylen);
|
||||
|
||||
SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str);
|
||||
SWITCH_DECLARE(char *) switch_strip_spaces(const char *str);
|
||||
SWITCH_DECLARE(char *) switch_strip_spaces(char *str, switch_bool_t dup);
|
||||
SWITCH_DECLARE(char *) switch_strip_whitespace(const char *str);
|
||||
SWITCH_DECLARE(char *) switch_strip_commas(char *in, char *out, switch_size_t len);
|
||||
SWITCH_DECLARE(char *) switch_strip_nonnumerics(char *in, char *out, switch_size_t len);
|
||||
|
||||
@@ -1428,8 +1428,8 @@ SWITCH_STANDARD_API(cond_function)
|
||||
int a_is_num, b_is_num;
|
||||
*expr++ = '\0';
|
||||
b = expr;
|
||||
s_a = switch_strip_spaces(a);
|
||||
s_b = switch_strip_spaces(b);
|
||||
s_a = switch_strip_spaces(a, SWITCH_TRUE);
|
||||
s_b = switch_strip_spaces(b, SWITCH_TRUE);
|
||||
a_is_num = switch_is_number(s_a);
|
||||
b_is_num = switch_is_number(s_b);
|
||||
|
||||
@@ -2226,6 +2226,40 @@ SWITCH_STANDARD_API(uuid_deflect)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define UUID_RECOVERY_REFRESH_SYNTAX "<uuid> <uri>"
|
||||
SWITCH_STANDARD_API(uuid_recovery_refresh)
|
||||
{
|
||||
switch_core_session_t *tsession = NULL;
|
||||
char *uuid = NULL, *text = NULL;
|
||||
|
||||
if (!zstr(cmd) && (uuid = strdup(cmd))) {
|
||||
if ((text = strchr(uuid, ' '))) {
|
||||
*text++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (zstr(uuid) || zstr(text)) {
|
||||
stream->write_function(stream, "-USAGE: %s\n", UUID_RECOVERY_REFRESH_SYNTAX);
|
||||
} else {
|
||||
if ((tsession = switch_core_session_locate(uuid))) {
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
|
||||
/* Tell the channel to recovery_refresh the call */
|
||||
msg.from = __FILE__;
|
||||
msg.string_arg = text;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH;
|
||||
switch_core_session_receive_message(tsession, &msg);
|
||||
stream->write_function(stream, "+OK:%s\n", msg.string_reply);
|
||||
switch_core_session_rwunlock(tsession);
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR No Such Channel %s!\n", uuid);
|
||||
}
|
||||
}
|
||||
|
||||
switch_safe_free(uuid);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define SCHED_TRANSFER_SYNTAX "[+]<time> <uuid> <extension> [<dialplan>] [<context>]"
|
||||
SWITCH_STANDARD_API(sched_transfer_function)
|
||||
{
|
||||
@@ -2488,6 +2522,48 @@ SWITCH_STANDARD_API(uuid_display_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define BUGLIST_SYNTAX "<uuid>"
|
||||
SWITCH_STANDARD_API(uuid_buglist_function)
|
||||
{
|
||||
char *mydata = NULL, *argv[2] = { 0 };
|
||||
int argc = 0;
|
||||
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (zstr(cmd)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
mydata = strdup(cmd);
|
||||
switch_assert(mydata);
|
||||
|
||||
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
|
||||
if (argc < 1) {
|
||||
goto error;
|
||||
}
|
||||
if (argv[0]) {
|
||||
switch_core_session_t *lsession = NULL;
|
||||
|
||||
if ((lsession = switch_core_session_locate(argv[0]))) {
|
||||
status = switch_core_media_bug_enumerate(lsession, stream);
|
||||
switch_core_session_rwunlock(lsession);
|
||||
}
|
||||
goto ok;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
stream->write_function(stream, "-USAGE: %s\n", BUGLIST_SYNTAX);
|
||||
switch_safe_free(mydata);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
ok:
|
||||
switch_safe_free(mydata);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define SIMPLIFY_SYNTAX "<uuid>"
|
||||
SWITCH_STANDARD_API(uuid_simplify_function)
|
||||
{
|
||||
@@ -2541,6 +2617,59 @@ SWITCH_STANDARD_API(uuid_simplify_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define JITTERBUFFER_SYNTAX "<uuid> [0|<min_msec>[:<max_msec>]]"
|
||||
SWITCH_STANDARD_API(uuid_jitterbuffer_function)
|
||||
{
|
||||
char *mydata = NULL, *argv[2] = { 0 };
|
||||
int argc = 0;
|
||||
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (zstr(cmd)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
mydata = strdup(cmd);
|
||||
switch_assert(mydata);
|
||||
|
||||
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
|
||||
if (argc < 2) {
|
||||
goto error;
|
||||
}
|
||||
if (argv[1]) {
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
switch_core_session_t *lsession = NULL;
|
||||
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_JITTER_BUFFER;
|
||||
msg.string_arg = argv[1];
|
||||
msg.from = __FILE__;
|
||||
|
||||
if ((lsession = switch_core_session_locate(argv[0]))) {
|
||||
status = switch_core_session_receive_message(lsession, &msg);
|
||||
switch_core_session_rwunlock(lsession);
|
||||
}
|
||||
goto ok;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
stream->write_function(stream, "-USAGE: %s\n", JITTERBUFFER_SYNTAX);
|
||||
switch_safe_free(mydata);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
ok:
|
||||
switch_safe_free(mydata);
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "+OK Success\n");
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR Operation Failed\n");
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#define PHONE_EVENT_SYNTAX "<uuid>"
|
||||
SWITCH_STANDARD_API(uuid_phone_event_function)
|
||||
@@ -4278,21 +4407,33 @@ SWITCH_STANDARD_API(strftime_tz_api_function)
|
||||
char *format = NULL;
|
||||
const char *tz_name = NULL;
|
||||
char date[80] = "";
|
||||
char *mycmd = NULL, *p;
|
||||
switch_time_t when = 0;
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
format = strchr(cmd, ' ');
|
||||
tz_name = cmd;
|
||||
if (format) {
|
||||
if (cmd) mycmd = strdup(cmd);
|
||||
|
||||
if (!zstr(mycmd)) {
|
||||
tz_name = mycmd;
|
||||
|
||||
if ((format = strchr(mycmd, ' '))) {
|
||||
*format++ = '\0';
|
||||
}
|
||||
|
||||
if ((p = strchr(format, '|'))) {
|
||||
*p++ = '\0';
|
||||
when = atol(format);
|
||||
format = p;
|
||||
}
|
||||
}
|
||||
|
||||
if (switch_strftime_tz(tz_name, format, date, sizeof(date), 0) == SWITCH_STATUS_SUCCESS) { /* The lookup of the zone may fail. */
|
||||
if (switch_strftime_tz(tz_name, format, date, sizeof(date), when * 1000000) == SWITCH_STATUS_SUCCESS) { /* The lookup of the zone may fail. */
|
||||
stream->write_function(stream, "%s", date);
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR Invalid Timezone\n");
|
||||
}
|
||||
|
||||
switch_safe_free(mycmd);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -4715,7 +4856,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
SWITCH_ADD_API(commands_api_interface, "show", "Show", show_function, SHOW_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "sql_escape", "Escape a string to prevent sql injection", sql_escape, SQL_ESCAPE_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "status", "status", status_function, "");
|
||||
SWITCH_ADD_API(commands_api_interface, "strftime_tz", "strftime_tz", strftime_tz_api_function, "<Timezone_name> [format string]");
|
||||
SWITCH_ADD_API(commands_api_interface, "strftime_tz", "strftime_tz", strftime_tz_api_function, "<Timezone_name> [<epoch>|][format string]");
|
||||
SWITCH_ADD_API(commands_api_interface, "stun", "stun", stun_function, "<stun_server>[:port]");
|
||||
SWITCH_ADD_API(commands_api_interface, "system", "Execute a system command", system_function, SYSTEM_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "time_test", "time_test", time_test_function, "<mss> [count]");
|
||||
@@ -4731,6 +4872,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_break", "Break", break_function, BREAK_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_bridge", "uuid_bridge", uuid_bridge_function, "");
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_broadcast", "broadcast", uuid_broadcast_function, BROADCAST_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_buglist", "List media bugs on a session", uuid_buglist_function, BUGLIST_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_chat", "Send a chat message", uuid_chat, UUID_CHAT_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_debug_audio", "debug audio", uuid_debug_audio_function, DEBUG_AUDIO_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_deflect", "Send a deflect", uuid_deflect, UUID_DEFLECT_SYNTAX);
|
||||
@@ -4750,6 +4892,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_phone_event", "Send and event to the phone", uuid_phone_event_function, PHONE_EVENT_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_preprocess", "Pre-process Channel", preprocess_function, PREPROCESS_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_record", "session record", session_record_function, SESS_REC_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_recovery_refresh", "Send a recovery_refresh", uuid_recovery_refresh, UUID_RECOVERY_REFRESH_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_recv_dtmf", "receive dtmf digits", uuid_recv_dtmf_function, UUID_RECV_DTMF_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_send_dtmf", "send dtmf digits", uuid_send_dtmf_function, UUID_SEND_DTMF_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_session_heartbeat", "uuid_session_heartbeat", uuid_session_heartbeat_function, HEARTBEAT_SYNTAX);
|
||||
@@ -4758,6 +4901,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_transfer", "Transfer a session", transfer_function, TRANSFER_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_dual_transfer", "Transfer a session and its partner", dual_transfer_function, DUAL_TRANSFER_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_simplify", "Try to cut out of a call path / attended xfer", uuid_simplify_function, SIMPLIFY_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "uuid_jitterbuffer", "Try to cut out of a call path / attended xfer",
|
||||
uuid_jitterbuffer_function, JITTERBUFFER_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "xml_locate", "find some xml", xml_locate_function, "[root | <section> <tag> <tag_attr_name> <tag_attr_val>]");
|
||||
SWITCH_ADD_API(commands_api_interface, "xml_wrap", "Wrap another api command in xml", xml_wrap_api_function, "<command> <args>");
|
||||
switch_console_set_complete("add alias add");
|
||||
@@ -4843,6 +4988,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
switch_console_set_complete("add uuid_break ::console::list_uuid both");
|
||||
switch_console_set_complete("add uuid_bridge ::console::list_uuid ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_broadcast ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_buglist ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_chat ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_debug_audio ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_deflect ::console::list_uuid");
|
||||
@@ -4854,6 +5000,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
switch_console_set_complete("add uuid_flush_dtmf ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_getvar ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_hold ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_jitterbuffer ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_kill ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_limit_release ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_loglevel ::console::list_uuid console");
|
||||
@@ -4870,7 +5017,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
switch_console_set_complete("add uuid_phone_event ::console::list_uuid talk");
|
||||
switch_console_set_complete("add uuid_phone_event ::console::list_uuid hold");
|
||||
switch_console_set_complete("add uuid_preprocess ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_record ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_record ::console::list_uuid ::[start:stop");
|
||||
switch_console_set_complete("add uuid_recovery_refresh ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_recv_dtmf ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_send_dtmf ::console::list_uuid");
|
||||
switch_console_set_complete("add uuid_session_heartbeat ::console::list_uuid");
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
* Chris Danielson <chris at maxpowersoft dot com>
|
||||
* Rupa Schomaker <rupa@rupa.com>
|
||||
* David Weekly <david@weekly.org>
|
||||
* Joao Mesquita <jmesquita@gmail.com>
|
||||
*
|
||||
* mod_conference.c -- Software Conference Bridge
|
||||
*
|
||||
@@ -191,7 +192,8 @@ typedef enum {
|
||||
EFLAG_TRANSFER = (1 << 23),
|
||||
EFLAG_BGDIAL_RESULT = (1 << 24),
|
||||
EFLAG_FLOOR_CHANGE = (1 << 25),
|
||||
EFLAG_MUTE_DETECT = (1 << 26)
|
||||
EFLAG_MUTE_DETECT = (1 << 26),
|
||||
EFLAG_RECORD = (1 << 27)
|
||||
} event_type_t;
|
||||
|
||||
typedef struct conference_file_node {
|
||||
@@ -270,6 +272,7 @@ typedef struct conference_obj {
|
||||
uint32_t not_talking_buf_len;
|
||||
int comfort_noise_level;
|
||||
int is_recording;
|
||||
int record_count;
|
||||
int video_running;
|
||||
uint32_t eflags;
|
||||
uint32_t verbose_events;
|
||||
@@ -283,6 +286,8 @@ typedef struct conference_obj {
|
||||
uint32_t avg_score;
|
||||
uint32_t avg_itt;
|
||||
uint32_t avg_tally;
|
||||
switch_time_t run_time;
|
||||
char *uuid_str;
|
||||
} conference_obj_t;
|
||||
|
||||
/* Relationship with another member */
|
||||
@@ -404,7 +409,7 @@ static switch_status_t conference_local_play_file(conference_obj_t *conference,
|
||||
static switch_status_t conference_member_play_file(conference_member_t *member, char *file, uint32_t leadin);
|
||||
static switch_status_t conference_member_say(conference_member_t *member, char *text, uint32_t leadin);
|
||||
static uint32_t conference_member_stop_file(conference_member_t *member, file_stop_t stop);
|
||||
static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_memory_pool_t *pool);
|
||||
static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_core_session_t *session, switch_memory_pool_t *pool);
|
||||
static switch_status_t chat_send(const char *proto, const char *from, const char *to, const char *subject,
|
||||
const char *body, const char *type, const char *hint);
|
||||
|
||||
@@ -436,6 +441,7 @@ static switch_status_t conference_add_event_data(conference_obj_t *conference, s
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Conference-Name", conference->name);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Conference-Size", "%u", conference->count);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Conference-Profile-Name", conference->profile_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Conference-Unique-ID", conference->uuid_str);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -468,6 +474,7 @@ static switch_status_t conference_add_event_member_data(conference_member_t *mem
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Hear", "%s", switch_test_flag(member, MFLAG_CAN_HEAR) ? "true" : "false" );
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Speak", "%s", switch_test_flag(member, MFLAG_CAN_SPEAK) ? "true" : "false" );
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Talking", "%s", switch_test_flag(member, MFLAG_TALKING) ? "true" : "false" );
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Mute-Detect", "%s", switch_test_flag(member, MFLAG_MUTE_DETECT) ? "true" : "false" );
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-ID", "%u", member->id);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-Type", "%s", switch_test_flag(member, MFLAG_MOD) ? "moderator" : "member");
|
||||
|
||||
@@ -563,6 +570,7 @@ static switch_status_t conference_record_stop(conference_obj_t *conference, char
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/* Add a custom relationship to a member */
|
||||
static conference_relationship_t *member_add_relationship(conference_member_t *member, uint32_t id)
|
||||
{
|
||||
@@ -684,8 +692,14 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
|
||||
}
|
||||
|
||||
if (!switch_channel_test_app_flag_key("conf_silent", channel, CONF_SILENT_REQ) && !zstr(conference->enter_sound)) {
|
||||
conference_play_file(conference, conference->enter_sound, CONF_DEFAULT_LEADIN, switch_core_session_get_channel(member->session),
|
||||
switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1);
|
||||
const char * enter_sound = switch_channel_get_variable(channel, "conference_enter_sound");
|
||||
if (!zstr(enter_sound)) {
|
||||
conference_play_file(conference, (char *)enter_sound, CONF_DEFAULT_LEADIN,
|
||||
switch_core_session_get_channel(member->session), !switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1);
|
||||
} else {
|
||||
conference_play_file(conference, conference->enter_sound, CONF_DEFAULT_LEADIN, switch_core_session_get_channel(member->session),
|
||||
!switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1035,6 +1049,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
|
||||
switch_mutex_unlock(globals.hash_mutex);
|
||||
|
||||
conference->is_recording = 0;
|
||||
conference->record_count = 0;
|
||||
|
||||
while (globals.running && !switch_test_flag(conference, CFLAG_DESTRUCT)) {
|
||||
switch_size_t file_sample_len = samples;
|
||||
@@ -1099,6 +1114,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
|
||||
/* Start recording if there's more than one participant. */
|
||||
if (conference->auto_record && !conference->is_recording && conference->count > 1) {
|
||||
conference->is_recording = 1;
|
||||
conference->record_count++;
|
||||
imember = conference->members;
|
||||
if (imember) {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(imember->session);
|
||||
@@ -2456,7 +2472,7 @@ static void conference_loop_output(conference_member_t *member)
|
||||
switch_event_destroy(&event);
|
||||
}
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
/* test to see if outbound channel has answered */
|
||||
if (switch_channel_test_flag(channel, CF_ANSWERED) && !switch_test_flag(member->conference, CFLAG_ANSWERED)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG,
|
||||
@@ -2485,7 +2501,9 @@ static void conference_loop_output(conference_member_t *member)
|
||||
|
||||
use_buffer = NULL;
|
||||
mux_used = (uint32_t) switch_buffer_inuse(member->mux_buffer);
|
||||
|
||||
|
||||
use_timer = 1;
|
||||
|
||||
if (mux_used) {
|
||||
if (mux_used < bytes) {
|
||||
if (++low_count >= 5) {
|
||||
@@ -2498,10 +2516,7 @@ static void conference_loop_output(conference_member_t *member)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
use_timer = 1;
|
||||
|
||||
if (mux_used) {
|
||||
if (mux_used >= bytes) {
|
||||
/* Flush the output buffer and write all the data (presumably muxed) back to the channel */
|
||||
switch_mutex_lock(member->audio_out_mutex);
|
||||
write_frame.data = data;
|
||||
@@ -2509,7 +2524,7 @@ static void conference_loop_output(conference_member_t *member)
|
||||
low_count = 0;
|
||||
if ((write_frame.datalen = (uint32_t) switch_buffer_read(use_buffer, write_frame.data, bytes))) {
|
||||
if (write_frame.datalen) {
|
||||
write_frame.samples = write_frame.datalen / 2;
|
||||
write_frame.samples = write_frame.datalen / 2;
|
||||
|
||||
if( !switch_test_flag(member, MFLAG_CAN_HEAR)) {
|
||||
memset(write_frame.data, 255, write_frame.datalen);
|
||||
@@ -2537,6 +2552,7 @@ static void conference_loop_output(conference_member_t *member)
|
||||
write_frame.datalen = bytes;
|
||||
write_frame.samples = samples;
|
||||
memset(write_frame.data, 255, write_frame.datalen);
|
||||
write_frame.timestamp = timer.samplecount;
|
||||
member_add_file_data(member, write_frame.data, write_frame.datalen);
|
||||
if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
||||
@@ -2599,7 +2615,7 @@ static void conference_loop_output(conference_member_t *member)
|
||||
switch_channel_cause2str(switch_channel_get_cause(channel)));
|
||||
|
||||
/* if it's an outbound channel, store the release cause in the conference struct, we might need it */
|
||||
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
member->conference->bridge_hangup_cause = switch_channel_get_cause(channel);
|
||||
}
|
||||
|
||||
@@ -2623,6 +2639,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
|
||||
switch_timer_t timer = { 0 };
|
||||
uint32_t rlen;
|
||||
switch_size_t data_buf_len;
|
||||
switch_event_t *event;
|
||||
|
||||
data_buf_len = samples * sizeof(int16_t);
|
||||
|
||||
@@ -2701,6 +2718,15 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
|
||||
|
||||
switch_core_file_set_string(&fh, SWITCH_AUDIO_COL_STR_ARTIST, "FreeSWITCH mod_conference Software Conference Module");
|
||||
|
||||
if (test_eflag(conference, EFLAG_RECORD) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_add_event_data(conference, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "start-recording");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Path", rec->path);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
|
||||
while (switch_test_flag(member, MFLAG_RUNNING) && switch_test_flag(conference, CFLAG_RUNNING) && conference->count) {
|
||||
switch_size_t len = 0;
|
||||
mux_used = (uint32_t) switch_buffer_inuse(member->mux_buffer);
|
||||
@@ -2755,6 +2781,12 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
|
||||
switch_core_file_close(&fh);
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Recording of %s Stopped\n", rec->path);
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_add_event_data(conference, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "stop-recording");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Path", rec->path);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
if (rec->pool) {
|
||||
switch_memory_pool_t *pool = rec->pool;
|
||||
@@ -3759,6 +3791,13 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer
|
||||
switch_xml_set_attr_d(x_conference, "dynamic", "true");
|
||||
}
|
||||
|
||||
if (conference->record_count > 0) {
|
||||
switch_xml_set_attr_d(x_conference, "recording", "true");
|
||||
}
|
||||
|
||||
switch_snprintf(i, sizeof(i), "%d", switch_epoch_time_now(NULL) - conference->run_time);
|
||||
switch_xml_set_attr_d(x_conference, "run_time", ival);
|
||||
|
||||
if (conference->agc_level) {
|
||||
char tmp[30] = "";
|
||||
switch_snprintf(tmp, sizeof(tmp), "%d", conference->agc_level);
|
||||
@@ -3825,6 +3864,9 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer
|
||||
x_tag = switch_xml_add_child_d(x_flags, "can_speak", count++);
|
||||
switch_xml_set_txt_d(x_tag, switch_test_flag(member, MFLAG_CAN_SPEAK) ? "true" : "false");
|
||||
|
||||
x_tag = switch_xml_add_child_d(x_flags, "mute_detect", count++);
|
||||
switch_xml_set_txt_d(x_tag, switch_test_flag(member, MFLAG_MUTE_DETECT) ? "true" : "false");
|
||||
|
||||
x_tag = switch_xml_add_child_d(x_flags, "talking", count++);
|
||||
switch_xml_set_txt_d(x_tag, switch_test_flag(member, MFLAG_TALKING) ? "true" : "false");
|
||||
|
||||
@@ -4243,6 +4285,7 @@ static switch_status_t conf_api_sub_transfer(conference_obj_t *conference, switc
|
||||
switch_event_t *params = NULL;
|
||||
conference_obj_t *new_conference = NULL;
|
||||
int locked = 0;
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
|
||||
switch_assert(conference != NULL);
|
||||
switch_assert(stream != NULL);
|
||||
@@ -4313,7 +4356,7 @@ static switch_status_t conf_api_sub_transfer(conference_obj_t *conference, switc
|
||||
}
|
||||
|
||||
/* Create the conference object. */
|
||||
new_conference = conference_new(conf_name, xml_cfg, pool);
|
||||
new_conference = conference_new(conf_name, xml_cfg, member->session, pool);
|
||||
|
||||
/* Release the config registry handle */
|
||||
if (cxml) {
|
||||
@@ -4366,6 +4409,13 @@ static switch_status_t conf_api_sub_transfer(conference_obj_t *conference, switc
|
||||
}
|
||||
}
|
||||
|
||||
switch_channel_set_variable(channel, "last_transfered_conference", argv[2]);
|
||||
|
||||
/* Sync the recovery data */
|
||||
msg.from = __FILE__;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH;
|
||||
switch_core_session_receive_message(member->session, &msg);
|
||||
|
||||
unlock_member(member);
|
||||
|
||||
stream->write_function(stream, "OK Member '%d' sent to conference %s.\n", member->id, argv[2]);
|
||||
@@ -4412,6 +4462,7 @@ static switch_status_t conf_api_sub_record(conference_obj_t *conference, switch_
|
||||
return SWITCH_STATUS_GENERR;
|
||||
|
||||
stream->write_function(stream, "Record file %s\n", argv[2]);
|
||||
conference->record_count++;
|
||||
launch_conference_record_thread(conference, argv[2]);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -4419,6 +4470,7 @@ static switch_status_t conf_api_sub_record(conference_obj_t *conference, switch_
|
||||
static switch_status_t conf_api_sub_norecord(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
|
||||
{
|
||||
int all;
|
||||
switch_event_t *event;
|
||||
|
||||
switch_assert(conference != NULL);
|
||||
switch_assert(stream != NULL);
|
||||
@@ -4430,6 +4482,20 @@ static switch_status_t conf_api_sub_norecord(conference_obj_t *conference, switc
|
||||
stream->write_function(stream, "Stop recording file %s\n", argv[2]);
|
||||
if (!conference_record_stop(conference, all ? NULL : argv[2]) && !all) {
|
||||
stream->write_function(stream, "non-existant recording '%s'\n", argv[2]);
|
||||
} else {
|
||||
if (all) {
|
||||
conference->record_count = 0;
|
||||
} else {
|
||||
conference->record_count--;
|
||||
}
|
||||
if (test_eflag(conference, EFLAG_RECORD) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_add_event_data(conference, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "stop-recording");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Path", all ? "all" : argv[2]);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Other-Recordings", conference->record_count ? "true" : "false");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
@@ -5136,6 +5202,8 @@ static void clear_eflags(char *events, uint32_t *f)
|
||||
*f &= ~EFLAG_BGDIAL_RESULT;
|
||||
} else if (!strcmp(event, "floor-change")) {
|
||||
*f &= ~EFLAG_FLOOR_CHANGE;
|
||||
} else if (!strcmp(event, "record")) {
|
||||
*f &= ~EFLAG_RECORD;
|
||||
}
|
||||
|
||||
event = next;
|
||||
@@ -5374,6 +5442,14 @@ SWITCH_STANDARD_APP(conference_function)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_RECOVERED)) {
|
||||
const char *check = switch_channel_get_variable(channel, "last_transfered_conference");
|
||||
|
||||
if (!zstr(check)) {
|
||||
conf_name = (char *) check;
|
||||
}
|
||||
}
|
||||
|
||||
switch_event_create(¶ms, SWITCH_EVENT_COMMAND);
|
||||
switch_assert(params);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "conf_name", conf_name);
|
||||
@@ -5410,7 +5486,7 @@ SWITCH_STANDARD_APP(conference_function)
|
||||
}
|
||||
|
||||
/* Create the conference object. */
|
||||
conference = conference_new(conf_name, xml_cfg, NULL);
|
||||
conference = conference_new(conf_name, xml_cfg, session, NULL);
|
||||
|
||||
if (!conference) {
|
||||
goto done;
|
||||
@@ -5436,7 +5512,7 @@ SWITCH_STANDARD_APP(conference_function)
|
||||
launch_conference_thread(conference);
|
||||
|
||||
} else {
|
||||
int enforce_security = !switch_channel_test_flag(channel, CF_OUTBOUND);
|
||||
int enforce_security = switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND;
|
||||
const char *pvar = switch_channel_get_variable(channel, "conference_enforce_security");
|
||||
|
||||
if (pvar) {
|
||||
@@ -5455,7 +5531,7 @@ SWITCH_STANDARD_APP(conference_function)
|
||||
const char *max_members_str;
|
||||
|
||||
/* couldn't find the conference, create one */
|
||||
conference = conference_new(conf_name, xml_cfg, NULL);
|
||||
conference = conference_new(conf_name, xml_cfg, session, NULL);
|
||||
|
||||
if (!conference) {
|
||||
goto done;
|
||||
@@ -5645,7 +5721,7 @@ SWITCH_STANDARD_APP(conference_function)
|
||||
} else {
|
||||
/* if we're not using "bridge:" set the conference answered flag */
|
||||
/* and this isn't an outbound channel, answer the call */
|
||||
if (!switch_channel_test_flag(channel, CF_OUTBOUND))
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND)
|
||||
switch_set_flag(conference, CFLAG_ANSWERED);
|
||||
}
|
||||
|
||||
@@ -5737,22 +5813,29 @@ SWITCH_STANDARD_APP(conference_function)
|
||||
if (conference && switch_test_flag(&member, MFLAG_KICKED) && conference->kicked_sound) {
|
||||
char *toplay = NULL;
|
||||
char *dfile = NULL;
|
||||
char *expanded = NULL;
|
||||
|
||||
if (!strncasecmp(conference->kicked_sound, "say:", 4)) {
|
||||
if (conference->tts_engine && conference->tts_voice) {
|
||||
switch_ivr_speak_text(session, conference->tts_engine, conference->tts_voice, conference->kicked_sound + 4, NULL);
|
||||
}
|
||||
} else {
|
||||
if ((expanded = switch_channel_expand_variables(switch_core_session_get_channel(session), conference->kicked_sound)) != conference->kicked_sound) {
|
||||
toplay = expanded;
|
||||
} else {
|
||||
expanded = NULL;
|
||||
toplay = conference->kicked_sound;
|
||||
}
|
||||
|
||||
if (conference->sound_prefix) {
|
||||
dfile = switch_mprintf("%s%s%s", conference->sound_prefix, SWITCH_PATH_SEPARATOR, conference->kicked_sound);
|
||||
dfile = switch_mprintf("%s%s%s", conference->sound_prefix, SWITCH_PATH_SEPARATOR, toplay);
|
||||
switch_assert(dfile);
|
||||
toplay = dfile;
|
||||
} else {
|
||||
toplay = conference->kicked_sound;
|
||||
}
|
||||
|
||||
switch_ivr_play_file(session, NULL, toplay, NULL);
|
||||
switch_safe_free(dfile);
|
||||
switch_safe_free(expanded);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5880,7 +5963,7 @@ static conference_obj_t *conference_find(char *name)
|
||||
}
|
||||
|
||||
/* create a new conferene with a specific profile */
|
||||
static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_memory_pool_t *pool)
|
||||
static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_core_session_t *session, switch_memory_pool_t *pool)
|
||||
{
|
||||
conference_obj_t *conference;
|
||||
switch_xml_t xml_kvp;
|
||||
@@ -5923,13 +6006,50 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_m
|
||||
char *verbose_events = NULL;
|
||||
char *auto_record = NULL;
|
||||
char *terminate_on_silence = NULL;
|
||||
|
||||
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH+1];
|
||||
switch_uuid_t uuid;
|
||||
switch_codec_implementation_t read_impl = { 0 };
|
||||
switch_channel_t *channel = NULL;
|
||||
const char *force_rate = NULL, *force_interval = NULL;
|
||||
uint32_t force_rate_i = 0, force_interval_i = 0;
|
||||
|
||||
/* Validate the conference name */
|
||||
if (zstr(name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Record! no name.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (session) {
|
||||
uint32_t tmp;
|
||||
|
||||
switch_core_session_get_read_impl(session, &read_impl);
|
||||
channel = switch_core_session_get_channel(session);
|
||||
|
||||
if ((force_rate = switch_channel_get_variable(channel, "conference_force_rate"))) {
|
||||
if (!strcasecmp(force_rate, "auto")) {
|
||||
force_rate_i = read_impl.actual_samples_per_second;
|
||||
} else {
|
||||
tmp = atoi(force_rate);
|
||||
|
||||
if (tmp == 8000 || tmp == 12000 || tmp == 16000 || tmp == 24000 || tmp == 32000 || tmp == 48000) {
|
||||
force_rate_i = rate = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((force_interval = switch_channel_get_variable(channel, "conference_force_interval"))) {
|
||||
if (!strcasecmp(force_interval, "auto")) {
|
||||
force_interval_i = read_impl.microseconds_per_packet / 1000;
|
||||
} else {
|
||||
tmp = atoi(force_interval);
|
||||
|
||||
if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
|
||||
force_interval_i = interval = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.hash_mutex);
|
||||
|
||||
/* parse the profile tree for param values */
|
||||
@@ -5950,20 +6070,33 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_m
|
||||
var = buf;
|
||||
}
|
||||
|
||||
if (!strcasecmp(var, "rate") && !zstr(val)) {
|
||||
if (!force_rate_i && !strcasecmp(var, "rate") && !zstr(val)) {
|
||||
uint32_t tmp = atoi(val);
|
||||
if (tmp == 8000 || tmp == 12000 || tmp == 16000 || tmp == 24000 || tmp == 32000 || tmp == 48000) {
|
||||
rate = tmp;
|
||||
if (session && tmp == 0) {
|
||||
if (!strcasecmp(val, "auto")) {
|
||||
rate = read_impl.actual_samples_per_second;
|
||||
}
|
||||
} else {
|
||||
if (tmp == 8000 || tmp == 12000 || tmp == 16000 || tmp == 24000 || tmp == 32000 || tmp == 48000) {
|
||||
rate = tmp;
|
||||
}
|
||||
}
|
||||
} else if (!strcasecmp(var, "domain") && !zstr(val)) {
|
||||
domain = val;
|
||||
} else if (!strcasecmp(var, "interval") && !zstr(val)) {
|
||||
} else if (!force_interval_i && !strcasecmp(var, "interval") && !zstr(val)) {
|
||||
uint32_t tmp = atoi(val);
|
||||
if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
|
||||
interval = tmp;
|
||||
|
||||
if (session && tmp == 0) {
|
||||
if (!strcasecmp(val, "auto")) {
|
||||
interval = read_impl.microseconds_per_packet / 1000;
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||
"Interval must be multipe of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
|
||||
if (SWITCH_ACCEPTABLE_INTERVAL(tmp)) {
|
||||
interval = tmp;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||
"Interval must be multipe of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
|
||||
}
|
||||
}
|
||||
} else if (!strcasecmp(var, "timer-name") && !zstr(val)) {
|
||||
timer_name = val;
|
||||
@@ -6111,6 +6244,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_m
|
||||
conference->caller_id_name = switch_core_strdup(conference->pool, caller_id_name);
|
||||
conference->caller_id_number = switch_core_strdup(conference->pool, caller_id_number);
|
||||
conference->caller_controls = switch_core_strdup(conference->pool, caller_controls);
|
||||
conference->run_time = switch_epoch_time_now(NULL);
|
||||
|
||||
|
||||
if (!zstr(perpetual_sound)) {
|
||||
@@ -6233,6 +6367,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_m
|
||||
} else {
|
||||
conference->domain = "cluecon.com";
|
||||
}
|
||||
|
||||
conference->rate = rate;
|
||||
conference->interval = interval;
|
||||
|
||||
@@ -6252,6 +6387,12 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_m
|
||||
conference->verbose_events = 1;
|
||||
}
|
||||
|
||||
/* Create the conference unique identifier */
|
||||
switch_uuid_get(&uuid);
|
||||
switch_uuid_format(uuid_str, &uuid);
|
||||
conference->uuid_str = switch_core_strdup(conference->pool, uuid_str);
|
||||
|
||||
|
||||
/* Activate the conference mutex for exclusivity */
|
||||
switch_mutex_init(&conference->mutex, SWITCH_MUTEX_NESTED, conference->pool);
|
||||
switch_mutex_init(&conference->flag_mutex, SWITCH_MUTEX_NESTED, conference->pool);
|
||||
|
||||
@@ -269,7 +269,7 @@ SWITCH_STANDARD_APP(bind_digit_action_function)
|
||||
}
|
||||
|
||||
|
||||
#define DETECT_SPEECH_SYNTAX "<mod_name> <gram_name> <gram_path> [<addr>] OR grammar <gram_name> [<path>] OR pause OR resume"
|
||||
#define DETECT_SPEECH_SYNTAX "<mod_name> <gram_name> <gram_path> [<addr>] OR grammar <gram_name> [<path>] OR nogrammar <gram_name> OR pause OR resume OR stop OR param <name> <value>"
|
||||
SWITCH_STANDARD_APP(detect_speech_function)
|
||||
{
|
||||
char *argv[4];
|
||||
@@ -957,6 +957,17 @@ SWITCH_STANDARD_APP(redirect_function)
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(jitterbuffer_function)
|
||||
{
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
|
||||
/* Tell the channel to change the jitter buffer */
|
||||
msg.from = __FILE__;
|
||||
msg.string_arg = data;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_JITTER_BUFFER;
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(display_function)
|
||||
{
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
@@ -990,6 +1001,17 @@ SWITCH_STANDARD_APP(deflect_function)
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(recovery_refresh_function)
|
||||
{
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
|
||||
/* Tell the channel to recovery_refresh the call */
|
||||
msg.from = __FILE__;
|
||||
msg.string_arg = data;
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH;
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
}
|
||||
|
||||
|
||||
SWITCH_STANDARD_APP(sched_cancel_function)
|
||||
{
|
||||
@@ -1303,13 +1325,22 @@ SWITCH_STANDARD_API(strftime_api_function)
|
||||
char date[80] = "";
|
||||
switch_time_t thetime;
|
||||
char *p;
|
||||
if (!zstr(cmd) && (p = strchr(cmd, '|'))) {
|
||||
thetime = switch_time_make(atoi(cmd), 0);
|
||||
char *mycmd = NULL;
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mycmd = strdup(cmd);
|
||||
}
|
||||
|
||||
if (!zstr(mycmd) && (p = strchr(cmd, '|'))) {
|
||||
*p++ = '\0';
|
||||
|
||||
thetime = switch_time_make(atol(cmd), 0);
|
||||
cmd = p + 1;
|
||||
} else {
|
||||
thetime = switch_micro_time_now();
|
||||
}
|
||||
switch_time_exp_lt(&tm, thetime);
|
||||
|
||||
if (zstr(cmd)) {
|
||||
switch_strftime_nocheck(date, &retsize, sizeof(date), "%Y-%m-%d %T", &tm);
|
||||
} else {
|
||||
@@ -3092,6 +3123,11 @@ SWITCH_STANDARD_APP(verbose_events_function)
|
||||
switch_channel_set_flag(switch_core_session_get_channel(session), CF_VERBOSE_EVENTS);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(cng_plc_function)
|
||||
{
|
||||
switch_channel_set_flag(switch_core_session_get_channel(session), CF_CNG_PLC);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_APP(early_hangup_function)
|
||||
{
|
||||
switch_channel_set_flag(switch_core_session_get_channel(session), CF_EARLY_HANGUP);
|
||||
@@ -3477,6 +3513,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
"<ip> <acl | cidr> [<hangup_cause>]", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "verbose_events", "Make ALL Events verbose.", "Make ALL Events verbose.", verbose_events_function, "",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "cng_plc", "Do PLC on CNG frames", "", cng_plc_function, "",
|
||||
SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "early_hangup", "Enable early hangup", "", early_hangup_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
|
||||
SWITCH_ADD_APP(app_interface, "sleep", "Pause a channel", SLEEP_LONG_DESC, sleep_function, "<pausemilliseconds>", SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "delay_echo", "echo audio at a specified delay", "Delay n ms", delay_function, "<delay ms>", SAF_NONE);
|
||||
@@ -3513,11 +3551,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
SWITCH_ADD_APP(app_interface, "ivr", "Run an ivr menu", "Run an ivr menu.", ivr_application_function, "<menu_name>", SAF_NONE);
|
||||
SWITCH_ADD_APP(app_interface, "redirect", "Send session redirect", "Send a redirect message to a session.", redirect_function, "<redirect_data>",
|
||||
SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "jitterbuffer", "Send session jitterbuffer", "Send a jitterbuffer message to a session.",
|
||||
jitterbuffer_function, "<jitterbuffer_data>", SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "send_display", "Send session a new display", "Send session a new display.", display_function, "<text>",
|
||||
SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "respond", "Send session respond", "Send a respond message to a session.", respond_function, "<respond_data>",
|
||||
SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "deflect", "Send call deflect", "Send a call deflect.", deflect_function, "<deflect_data>", SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "recovery_refresh", "Send call recovery_refresh", "Send a call recovery_refresh.", recovery_refresh_function, "", SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "queue_dtmf", "Queue dtmf to be sent", "Queue dtmf to be sent from a session", queue_dtmf_function, "<dtmf_data>",
|
||||
SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "send_dtmf", "Send dtmf to be sent", "Send dtmf to be sent from a session", send_dtmf_function, "<dtmf_data>",
|
||||
|
||||
@@ -291,6 +291,7 @@ static switch_status_t fifo_queue_popfly(fifo_queue_t *queue, const char *uuid)
|
||||
struct fifo_node {
|
||||
char *name;
|
||||
switch_mutex_t *mutex;
|
||||
switch_mutex_t *update_mutex;
|
||||
fifo_queue_t *fifo_list[MAX_PRI];
|
||||
switch_hash_t *consumer_hash;
|
||||
int outbound_priority;
|
||||
@@ -801,6 +802,7 @@ static fifo_node_t *create_node(const char *name, uint32_t importance, switch_mu
|
||||
switch_core_hash_init(&node->consumer_hash, node->pool);
|
||||
switch_thread_rwlock_create(&node->rwlock, node->pool);
|
||||
switch_mutex_init(&node->mutex, SWITCH_MUTEX_NESTED, node->pool);
|
||||
switch_mutex_init(&node->update_mutex, SWITCH_MUTEX_NESTED, node->pool);
|
||||
cbt.buf = outbound_count;
|
||||
cbt.len = sizeof(outbound_count);
|
||||
sql = switch_mprintf("select count(*) from fifo_outbound where fifo_name = '%q'", name);
|
||||
@@ -1193,10 +1195,10 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void
|
||||
|
||||
|
||||
if (node) {
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
node->busy = 0;
|
||||
node->ring_consumer_count = 1;
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
} else {
|
||||
goto end;
|
||||
}
|
||||
@@ -1437,10 +1439,10 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void
|
||||
cbh->ready = 1;
|
||||
|
||||
if (node) {
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
node->ring_consumer_count = 0;
|
||||
node->busy = 0;
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
}
|
||||
|
||||
|
||||
@@ -1501,10 +1503,10 @@ static void *SWITCH_THREAD_FUNC o_thread_run(switch_thread_t *thread, void *obj)
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
if (node) {
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
node->ring_consumer_count++;
|
||||
node->busy = 0;
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
}
|
||||
|
||||
switch_event_create(&ovars, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
@@ -1601,12 +1603,12 @@ static void *SWITCH_THREAD_FUNC o_thread_run(switch_thread_t *thread, void *obj)
|
||||
|
||||
switch_event_destroy(&ovars);
|
||||
if (node) {
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
if (node->ring_consumer_count-- < 0) {
|
||||
node->ring_consumer_count = 0;
|
||||
}
|
||||
node->busy = 0;
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
}
|
||||
switch_core_destroy_memory_pool(&h->pool);
|
||||
|
||||
@@ -1754,9 +1756,36 @@ static void *SWITCH_THREAD_FUNC node_thread_run(switch_thread_t *thread, void *o
|
||||
if (globals.debug) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Trying priority: %d\n", cur_priority);
|
||||
|
||||
|
||||
restart:
|
||||
|
||||
for (hi = switch_hash_first(NULL, globals.fifo_hash); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, &var, NULL, &val);
|
||||
if ((node = (fifo_node_t *) val)) {
|
||||
int x = 0;
|
||||
switch_event_t *pop;
|
||||
|
||||
if (node->ready == FIFO_DELAY_DESTROY) {
|
||||
if (switch_thread_rwlock_trywrlock(node->rwlock) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s removed.\n", node->name);
|
||||
switch_core_hash_delete(globals.fifo_hash, node->name);
|
||||
|
||||
for (x = 0; x < MAX_PRI; x++) {
|
||||
while (fifo_queue_pop(node->fifo_list[x], &pop, 2) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_destroy(&pop);
|
||||
}
|
||||
}
|
||||
|
||||
node->ready = 0;
|
||||
switch_core_hash_destroy(&node->consumer_hash);
|
||||
switch_mutex_unlock(node->mutex);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_core_destroy_memory_pool(&node->pool);
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (node->outbound_priority == 0) node->outbound_priority = 5;
|
||||
if (node->has_outbound && node->ready && !node->busy && node->outbound_priority == cur_priority) {
|
||||
ppl_waiting = node_caller_count(node);
|
||||
@@ -2144,7 +2173,7 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
char *mydata = NULL, *argv[5] = { 0 };
|
||||
fifo_node_t *node = NULL, *node_list[MAX_NODES_PER_CONSUMER + 1] = { 0 };
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
int do_wait = 1, node_count = 0, i = 0;
|
||||
int do_destroy = 0, do_wait = 1, node_count = 0, i = 0;
|
||||
const char *moh = NULL;
|
||||
const char *announce = NULL;
|
||||
switch_event_t *event = NULL;
|
||||
@@ -2220,11 +2249,9 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
node = create_node(nlist[i], importance, globals.sql_mutex);
|
||||
node->ready = 1;
|
||||
}
|
||||
node_list[node_count++] = node;
|
||||
}
|
||||
|
||||
if (switch_true(switch_channel_get_variable(channel, "fifo_destroy_after_use")) && node->ready == 1) {
|
||||
node->ready = FIFO_DELAY_DESTROY;
|
||||
switch_thread_rwlock_rdlock(node->rwlock);
|
||||
node_list[node_count++] = node;
|
||||
}
|
||||
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
@@ -2306,7 +2333,7 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
|
||||
switch_channel_answer(channel);
|
||||
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
|
||||
if ((pri = switch_channel_get_variable(channel, "fifo_priority"))) {
|
||||
p = atoi(pri);
|
||||
@@ -2344,7 +2371,7 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
switch_channel_set_variable(channel, "fifo_priority", tmp);
|
||||
}
|
||||
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
|
||||
ts = switch_micro_time_now();
|
||||
switch_time_exp_lt(&tm, ts);
|
||||
@@ -2450,9 +2477,9 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
node_remove_uuid(node, uuid);
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
send_presence(node);
|
||||
check_cancel(node);
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
@@ -2682,9 +2709,9 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
}
|
||||
|
||||
if (pop && !node_caller_count(node)) {
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
node->start_waiting = 0;
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3074,22 +3101,22 @@ SWITCH_STANDARD_APP(fifo_function)
|
||||
|
||||
done:
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
if (node && node->ready == FIFO_DELAY_DESTROY && node->consumer_count == 0 && node_caller_count(node) == 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "%s removed.\n", node->name);
|
||||
switch_core_hash_delete(globals.fifo_hash, node->name);
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
node->ready = 0;
|
||||
switch_mutex_lock(node->mutex);
|
||||
switch_core_hash_destroy(&node->consumer_hash);
|
||||
switch_mutex_unlock(node->mutex);
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_core_destroy_memory_pool(&node->pool);
|
||||
if (switch_true(switch_channel_get_variable(channel, "fifo_destroy_after_use"))) {
|
||||
do_destroy = 1;
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
for (i = 0; i < node_count; i++) {
|
||||
if (!(node = node_list[i])) {
|
||||
continue;
|
||||
}
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
if (node->ready == 1 && do_destroy) {
|
||||
node->ready = FIFO_DELAY_DESTROY;
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
|
||||
switch_channel_clear_app_flag_key(FIFO_APP_KEY, channel, FIFO_APP_BRIDGE_TAG);
|
||||
|
||||
switch_core_media_bug_resume(session);
|
||||
@@ -3699,9 +3726,9 @@ SWITCH_STANDARD_API(fifo_api_function)
|
||||
switch_hash_this(hi, &var, NULL, &val);
|
||||
node = (fifo_node_t *) val;
|
||||
len = node_caller_count(node);
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
stream->write_function(stream, "%s:%d:%d:%d\n", (char *) var, node->consumer_count, node_caller_count(node), len);
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
x++;
|
||||
}
|
||||
|
||||
@@ -3710,9 +3737,9 @@ SWITCH_STANDARD_API(fifo_api_function)
|
||||
}
|
||||
} else if ((node = switch_core_hash_find(globals.fifo_hash, argv[1]))) {
|
||||
len = node_caller_count(node);
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
stream->write_function(stream, "%s:%d:%d:%d\n", argv[1], node->consumer_count, node_caller_count(node), len);
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
} else {
|
||||
stream->write_function(stream, "none\n");
|
||||
}
|
||||
@@ -3722,9 +3749,9 @@ SWITCH_STANDARD_API(fifo_api_function)
|
||||
switch_hash_this(hi, &var, NULL, &val);
|
||||
node = (fifo_node_t *) val;
|
||||
len = node_caller_count(node);
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
stream->write_function(stream, "%s:%d\n", (char *) var, node->has_outbound);
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
x++;
|
||||
}
|
||||
|
||||
@@ -3733,9 +3760,9 @@ SWITCH_STANDARD_API(fifo_api_function)
|
||||
}
|
||||
} else if ((node = switch_core_hash_find(globals.fifo_hash, argv[1]))) {
|
||||
len = node_caller_count(node);
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
stream->write_function(stream, "%s:%d\n", argv[1], node->has_outbound);
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
} else {
|
||||
stream->write_function(stream, "none\n");
|
||||
}
|
||||
@@ -4108,7 +4135,7 @@ static switch_status_t load_config(int reload, int del_all)
|
||||
node->ready = FIFO_DELAY_DESTROY;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s removed.\n", node->name);
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
for (x = 0; x < MAX_PRI; x++) {
|
||||
while (fifo_queue_pop(node->fifo_list[x], &pop, 2) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_destroy(&pop);
|
||||
@@ -4117,7 +4144,7 @@ static switch_status_t load_config(int reload, int del_all)
|
||||
|
||||
switch_core_hash_delete(globals.fifo_hash, node->name);
|
||||
switch_core_hash_destroy(&node->consumer_hash);
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
switch_core_destroy_memory_pool(&node->pool);
|
||||
goto top;
|
||||
}
|
||||
@@ -4393,7 +4420,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_fifo_shutdown)
|
||||
switch_hash_this(hi, NULL, NULL, &val);
|
||||
node = (fifo_node_t *) val;
|
||||
|
||||
switch_thread_rwlock_wrlock(node->rwlock);
|
||||
switch_mutex_lock(node->update_mutex);
|
||||
switch_mutex_lock(node->mutex);
|
||||
for (x = 0; x < MAX_PRI; x++) {
|
||||
while (fifo_queue_pop(node->fifo_list[x], &pop, 2) == SWITCH_STATUS_SUCCESS) {
|
||||
@@ -4403,7 +4430,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_fifo_shutdown)
|
||||
switch_mutex_unlock(node->mutex);
|
||||
switch_core_hash_delete(globals.fifo_hash, node->name);
|
||||
switch_core_hash_destroy(&node->consumer_hash);
|
||||
switch_thread_rwlock_unlock(node->rwlock);
|
||||
switch_mutex_unlock(node->update_mutex);
|
||||
switch_core_destroy_memory_pool(&node->pool);
|
||||
}
|
||||
|
||||
|
||||
@@ -188,10 +188,12 @@ static switch_status_t do_snap(switch_core_session_t *session)
|
||||
switch_core_file_close(&fh);
|
||||
switch_core_set_variable("file", file);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Wrote %s\n", file);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s Bug is not attached.\n", switch_channel_get_name(channel));
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
}
|
||||
|
||||
#define SNAP_SYNTAX "start <sec> <read|write>"
|
||||
@@ -249,7 +251,7 @@ SWITCH_STANDARD_APP(snapshot_app_function)
|
||||
}
|
||||
|
||||
|
||||
#define SNAP_API_SYNTAX "<uuid> <warning>"
|
||||
#define SNAP_API_SYNTAX "<uuid> snap|start [<sec> read|write <base>]"
|
||||
SWITCH_STANDARD_API(snapshot_function)
|
||||
{
|
||||
char *mycmd = NULL, *argv[5] = { 0 };
|
||||
@@ -260,7 +262,7 @@ SWITCH_STANDARD_API(snapshot_function)
|
||||
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (zstr(cmd) || argc < 1 || zstr(argv[0])) {
|
||||
if (zstr(cmd) || argc < 2 || zstr(argv[0])) {
|
||||
stream->write_function(stream, "-USAGE: %s\n", SNAP_API_SYNTAX);
|
||||
goto done;
|
||||
} else {
|
||||
@@ -270,9 +272,9 @@ SWITCH_STANDARD_API(snapshot_function)
|
||||
if (!strcasecmp(argv[1], "snap")) {
|
||||
status = do_snap(lsession);
|
||||
} else if (!strcasecmp(argv[1], "start")) {
|
||||
char *sec = argv[1];
|
||||
char *fl = argv[2];
|
||||
const char *base = argv[3];
|
||||
char *sec = argv[2];
|
||||
char *fl = argv[3];
|
||||
const char *base = argv[4];
|
||||
int seconds = 5;
|
||||
switch_media_bug_flag_t flags = SMBF_READ_STREAM | SMBF_WRITE_STREAM | SMBF_READ_PING;
|
||||
|
||||
@@ -325,10 +327,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_snapshot_load)
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Hello World!\n");
|
||||
|
||||
SWITCH_ADD_API(api_interface, "uuid_snapshot", "Snapshot API", snapshot_function, SNAP_API_SYNTAX);
|
||||
SWITCH_ADD_APP(app_interface, "snapshot", "", "", snapshot_app_function, SNAP_SYNTAX, SAF_SUPPORT_NOMEDIA);
|
||||
switch_console_set_complete("add uuid_snapshot ::console::list_uuid");
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
@@ -131,7 +131,6 @@ SWITCH_STANDARD_API(dump_hash)
|
||||
static switch_status_t process_event(switch_event_t *event)
|
||||
{
|
||||
switch_core_session_t *session = NULL;
|
||||
switch_channel_t *channel;
|
||||
char *username[3] = { 0 };
|
||||
char *domain[3] = { 0 };
|
||||
char key[512];
|
||||
@@ -172,18 +171,19 @@ static switch_status_t process_event(switch_event_t *event)
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
session = switch_core_session_locate(uuid);
|
||||
channel = switch_core_session_get_channel(session);
|
||||
if ((session = switch_core_session_locate(uuid))) {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "UserSpy retrieved uuid %s for key %s, activating eavesdrop \n", uuid, key);
|
||||
my_uuid = switch_event_get_header(event, "Unique-ID");
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "UserSpy retrieved uuid %s for key %s, activating eavesdrop \n", uuid, key);
|
||||
my_uuid = switch_event_get_header(event, "Unique-ID");
|
||||
|
||||
switch_channel_set_variable(channel, "spy_uuid", my_uuid);
|
||||
switch_channel_set_variable(channel, "spy_uuid", my_uuid);
|
||||
|
||||
switch_channel_set_state(channel, CS_EXCHANGE_MEDIA);
|
||||
switch_channel_set_flag(channel, CF_BREAK);
|
||||
switch_channel_set_state(channel, CS_EXCHANGE_MEDIA);
|
||||
switch_channel_set_flag(channel, CF_BREAK);
|
||||
|
||||
switch_core_session_rwunlock(session);
|
||||
switch_core_session_rwunlock(session);
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
@@ -1324,7 +1324,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
|
||||
caller_profile = tech_pvt->caller_profile;
|
||||
caller_profile->destination_number = rdest;
|
||||
|
||||
switch_channel_set_flag(channel, CF_OUTBOUND);
|
||||
switch_set_flag(tech_pvt, TFLAG_OUTBOUND);
|
||||
switch_channel_set_state(channel, CS_INIT);
|
||||
gsmopen_call(tech_pvt, rdest, 30);
|
||||
|
||||
@@ -589,7 +589,7 @@ FSH323EndPoint::FSH323EndPoint()
|
||||
,m_fax_old_asn(false)
|
||||
{
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"======>FSH323EndPoint::FSH323EndPoint [%p]\n",this);
|
||||
terminalType = e_GatewayOnly;
|
||||
terminalType = e_GatewayAndMC;
|
||||
}
|
||||
|
||||
FSH323EndPoint::~FSH323EndPoint()
|
||||
@@ -725,7 +725,6 @@ FSH323Connection::FSH323Connection(FSH323EndPoint& endpoint, H323Transport* tran
|
||||
name += outbound_profile->destination_number;
|
||||
switch_channel_set_name(m_fsChannel, name);
|
||||
|
||||
switch_channel_set_flag(m_fsChannel, CF_OUTBOUND);
|
||||
switch_channel_set_state(m_fsChannel, CS_INIT);
|
||||
}
|
||||
|
||||
@@ -1508,7 +1507,7 @@ switch_status_t FSH323Connection::receive_message(switch_core_session_message_t
|
||||
break;
|
||||
}
|
||||
case SWITCH_MESSAGE_INDICATE_ANSWER: {
|
||||
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
AnsweringCall(H323Connection::AnswerCallNow);
|
||||
|
||||
@@ -868,7 +868,6 @@ switch_status_t Board::KhompPvt::justStart(switch_caller_profile_t *profile)
|
||||
_caller_profile = switch_caller_profile_clone(_session, profile);
|
||||
switch_channel_set_caller_profile(channel, _caller_profile);
|
||||
|
||||
switch_channel_set_flag(channel, CF_OUTBOUND);
|
||||
switch_channel_set_state(channel, CS_INIT);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -580,7 +580,6 @@ FSConnection::FSConnection(OpalCall & call, FSEndPoint & endpoint, void* userDat
|
||||
name += outbound_profile->destination_number;
|
||||
switch_channel_set_name(m_fsChannel, name);
|
||||
|
||||
switch_channel_set_flag(m_fsChannel, CF_OUTBOUND);
|
||||
switch_channel_set_state(m_fsChannel, CS_INIT);
|
||||
}
|
||||
}
|
||||
@@ -966,7 +965,7 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg
|
||||
It would only happen if someone called switch_channel_answer() instead of switch_channel_mark_answered() on an outbound call.
|
||||
it should not do anything if someone does it by accident somewhere hense this in both cases:
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
@@ -1025,7 +1024,7 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg
|
||||
{
|
||||
int fixed = 0;
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ sub _find {
|
||||
my ($name, $value) = ($1,hex($2));
|
||||
$sub{$name} = sub () { $value };
|
||||
$const{$name} = $value;
|
||||
} elsif(/^\s*struct\s+([a-z_]+)\s*\{\s*$/) {
|
||||
} elsif(/^\s*struct\s+PACKED\s+([a-z_]+)\s*\{\s*$/) {
|
||||
my $struct_name = $1;
|
||||
$struct{$struct_name} = [];
|
||||
while(<$fh>) {
|
||||
|
||||
@@ -1080,8 +1080,6 @@ switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, swi
|
||||
switch_channel_set_caller_profile(nchannel, caller_profile);
|
||||
tech_pvt->caller_profile = caller_profile;
|
||||
|
||||
switch_channel_set_flag(nchannel, CF_OUTBOUND);
|
||||
|
||||
if ((sql = switch_mprintf(
|
||||
"INSERT INTO skinny_active_lines "
|
||||
"(device_name, device_instance, line_instance, channel_uuid, call_id, call_state) "
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#define SKINNY_EVENT_UNREGISTER "skinny::unregister"
|
||||
#define SKINNY_EVENT_EXPIRE "skinny::expire"
|
||||
#define SKINNY_EVENT_ALARM "skinny::alarm"
|
||||
#define SKINNY_EVENT_XML_ALARM "skinny::xml_alarm"
|
||||
#define SKINNY_EVENT_CALL_STATE "skinny::call_state"
|
||||
#define SKINNY_EVENT_USER_TO_DEVICE "skinny::user_to_device"
|
||||
#define SKINNY_EVENT_DEVICE_TO_USER "skinny::device_to_user"
|
||||
|
||||
@@ -547,12 +547,15 @@ struct PACKED service_url_stat_res_message {
|
||||
#define USER_TO_DEVICE_DATA_VERSION1_MESSAGE 0x013F
|
||||
/* See struct PACKED extended_data_message */
|
||||
|
||||
/* XMLAlarmMessage */
|
||||
#define XML_ALARM_MESSAGE 0x015A
|
||||
|
||||
/*****************************************************************************/
|
||||
/* SKINNY MESSAGE */
|
||||
/*****************************************************************************/
|
||||
#define SKINNY_MESSAGE_FIELD_SIZE 4 /* 4-bytes field */
|
||||
#define SKINNY_MESSAGE_HEADERSIZE 12 /* three 4-bytes fields */
|
||||
#define SKINNY_MESSAGE_MAXSIZE 1000
|
||||
#define SKINNY_MESSAGE_MAXSIZE 2048
|
||||
|
||||
union skinny_data {
|
||||
/* no data for KEEP_ALIVE_MESSAGE */
|
||||
@@ -624,8 +627,7 @@ union skinny_data {
|
||||
struct extended_data_message extended_data;
|
||||
|
||||
uint16_t as_uint16;
|
||||
char as_char;
|
||||
void *raw;
|
||||
char as_char[1];
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -343,7 +343,7 @@ switch_status_t skinny_session_send_call_info(switch_core_session_t *session, li
|
||||
zstr((called_party_number = switch_channel_get_variable(channel, "destination_number")))) {
|
||||
called_party_number = "0000000000";
|
||||
}
|
||||
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
call_type = SKINNY_INBOUND_CALL;
|
||||
} else {
|
||||
call_type = SKINNY_OUTBOUND_CALL;
|
||||
@@ -1674,7 +1674,7 @@ switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *liste
|
||||
);
|
||||
|
||||
switch_set_flag_locked(tech_pvt, TFLAG_IO);
|
||||
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
switch_channel_mark_answered(channel);
|
||||
}
|
||||
if (switch_channel_test_flag(channel, CF_HOLD)) {
|
||||
@@ -1963,6 +1963,26 @@ switch_status_t skinny_handle_extended_data_message(listener_t *listener, skinny
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_status_t skinny_handle_xml_alarm(listener_t *listener, skinny_message_t *request)
|
||||
{
|
||||
switch_event_t *event = NULL;
|
||||
char *tmp = NULL;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
|
||||
"Received XML alarm.\n");
|
||||
/* skinny::xml_alarm event */
|
||||
skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_XML_ALARM);
|
||||
/* Ensure that the body is null-terminated */
|
||||
tmp = malloc(request->length - 4 + 1);
|
||||
memcpy(tmp, request->data.as_char, request->length - 4);
|
||||
tmp[request->length - 4] = '\0';
|
||||
switch_event_add_body(event, "%s", tmp);
|
||||
switch_safe_free(tmp);
|
||||
switch_event_fire(&event);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *request)
|
||||
{
|
||||
if (listener->profile->debug >= 10 || request->type != KEEP_ALIVE_MESSAGE) {
|
||||
@@ -1970,7 +1990,7 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re
|
||||
"Received %s (type=%x,length=%d) from %s:%d.\n", skinny_message_type2str(request->type), request->type, request->length,
|
||||
listener->device_name, listener->device_instance);
|
||||
}
|
||||
if(zstr(listener->device_name) && request->type != REGISTER_MESSAGE && request->type != ALARM_MESSAGE) {
|
||||
if(zstr(listener->device_name) && request->type != REGISTER_MESSAGE && request->type != ALARM_MESSAGE && request->type != XML_ALARM_MESSAGE) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"Device should send a register message first.\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
@@ -2032,6 +2052,8 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re
|
||||
return skinny_handle_extended_data_message(listener, request);
|
||||
case DEVICE_TO_USER_DATA_RESPONSE_VERSION1_MESSAGE:
|
||||
return skinny_handle_extended_data_message(listener, request);
|
||||
case XML_ALARM_MESSAGE:
|
||||
return skinny_handle_xml_alarm(listener, request);
|
||||
default:
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||
"Unhandled request %s (type=%x,length=%d).\n", skinny_message_type2str(request->type), request->type, request->length);
|
||||
|
||||
@@ -99,6 +99,7 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = {
|
||||
{"DisplayPriNotifyMessage", DISPLAY_PRI_NOTIFY_MESSAGE},
|
||||
{"ServiceUrlStatMessage", SERVICE_URL_STAT_RES_MESSAGE},
|
||||
{"UserToDeviceDataVersion1Message", USER_TO_DEVICE_DATA_VERSION1_MESSAGE},
|
||||
{"XMLAlarmMessage", XML_ALARM_MESSAGE},
|
||||
{NULL, 0}
|
||||
};
|
||||
SKINNY_DECLARE_ID2STR(skinny_message_type2str, SKINNY_MESSAGE_TYPES, "UnknownMessage")
|
||||
|
||||
@@ -87,7 +87,7 @@ uint32_t func(const char *str)\
|
||||
}
|
||||
|
||||
|
||||
extern struct skinny_table SKINNY_MESSAGE_TYPES[65];
|
||||
extern struct skinny_table SKINNY_MESSAGE_TYPES[66];
|
||||
const char *skinny_message_type2str(uint32_t id);
|
||||
uint32_t skinny_str2message_type(const char *str);
|
||||
#define SKINNY_PUSH_MESSAGE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_MESSAGE_TYPES)
|
||||
|
||||
@@ -1364,7 +1364,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
|
||||
caller_profile = tech_pvt->caller_profile;
|
||||
caller_profile->destination_number = rdest;
|
||||
|
||||
switch_channel_set_flag(channel, CF_OUTBOUND);
|
||||
switch_mutex_lock(tech_pvt->flag_mutex);
|
||||
switch_set_flag(tech_pvt, TFLAG_OUTBOUND);
|
||||
switch_mutex_unlock(tech_pvt->flag_mutex);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# Comment/uncomment the following line to disable/enable debugging
|
||||
#DEBUG = y
|
||||
#LDDINC=/usr/src/linux-headers-2.6.32-26-server/include
|
||||
|
||||
# Add your debugging flag (or not) to CFLAGS
|
||||
ifeq ($(DEBUG),y)
|
||||
DEBFLAGS = -O -g -DSKYPOPEN_DEBUG # "-O" is needed to expand inlines
|
||||
else
|
||||
DEBFLAGS = -O2 -Wall
|
||||
endif
|
||||
|
||||
EXTRA_CFLAGS += $(DEBFLAGS)
|
||||
EXTRA_CFLAGS += -I$(LDDINC)
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
# call from kernel build system
|
||||
|
||||
skypopen-objs := main.o
|
||||
|
||||
obj-m := skypopen.o
|
||||
|
||||
else
|
||||
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)/../include modules
|
||||
|
||||
endif
|
||||
|
||||
|
||||
|
||||
clean:
|
||||
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
|
||||
|
||||
depend .depend dep:
|
||||
$(CC) $(EXTRA_CFLAGS) -M *.c > .depend
|
||||
|
||||
|
||||
ifeq (.depend,$(wildcard .depend))
|
||||
include .depend
|
||||
endif
|
||||
@@ -0,0 +1,494 @@
|
||||
/*
|
||||
* main.c -- the bare skypopen char module
|
||||
*
|
||||
* Copyright (C) 2010 Giovanni Maruzzelli
|
||||
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
|
||||
* Copyright (C) 2001 O'Reilly & Associates
|
||||
*
|
||||
* The source code in this file can be freely used, adapted,
|
||||
* and redistributed in source or binary form, so long as an
|
||||
* acknowledgment appears in derived source files. The citation
|
||||
* should list that the code comes from the book "Linux Device
|
||||
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
|
||||
* by O'Reilly & Associates. No warranty is attached;
|
||||
* we cannot take responsibility for errors or fitness for use.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <linux/kernel.h> /* printk() */
|
||||
#include <linux/slab.h> /* kmalloc() */
|
||||
#include <linux/fs.h> /* everything... */
|
||||
#include <linux/errno.h> /* error codes */
|
||||
#include <linux/types.h> /* size_t */
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/fcntl.h> /* O_ACCMODE */
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
#include <asm/system.h> /* cli(), *_flags */
|
||||
#include <asm/uaccess.h> /* copy_*_user */
|
||||
|
||||
#include <linux/soundcard.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/ktime.h>
|
||||
|
||||
#include "skypopen.h" /* local definitions */
|
||||
|
||||
/*
|
||||
* Our parameters which can be set at load time.
|
||||
*/
|
||||
|
||||
int skypopen_major = SKYPOPEN_MAJOR;
|
||||
int skypopen_minor = 3;
|
||||
int skypopen_nr_devs = SKYPOPEN_NR_DEVS; /* number of bare skypopen devices */
|
||||
|
||||
module_param(skypopen_major, int, S_IRUGO);
|
||||
module_param(skypopen_minor, int, S_IRUGO);
|
||||
module_param(skypopen_nr_devs, int, S_IRUGO);
|
||||
|
||||
MODULE_AUTHOR("Original: Alessandro Rubini, Jonathan Corbet. Modified by: Giovanni Maruzzelli for FreeSWITCH skypopen");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
static struct skypopen_dev *skypopen_devices; /* allocated in skypopen_init_module */
|
||||
|
||||
static int unload = 0;
|
||||
#ifdef CENTOS
|
||||
#define HRTIMER_MODE_REL HRTIMER_REL
|
||||
#endif// CENTOS
|
||||
|
||||
#ifndef WANT_HRTIMER
|
||||
void my_timer_callback_inq( unsigned long data )
|
||||
{
|
||||
struct skypopen_dev *dev = (void *)data;
|
||||
|
||||
wake_up_interruptible(&dev->inq);
|
||||
mod_timer( &dev->timer_inq, jiffies + msecs_to_jiffies(SKYPOPEN_SLEEP) );
|
||||
|
||||
}
|
||||
|
||||
void my_timer_callback_outq( unsigned long data )
|
||||
{
|
||||
struct skypopen_dev *dev = (void *)data;
|
||||
|
||||
wake_up_interruptible(&dev->outq);
|
||||
mod_timer( &dev->timer_outq, jiffies + msecs_to_jiffies(SKYPOPEN_SLEEP) );
|
||||
}
|
||||
#else// WANT_HRTIMER
|
||||
|
||||
#ifndef CENTOS
|
||||
static enum hrtimer_restart my_hrtimer_callback_inq( struct hrtimer *timer_inq )
|
||||
{
|
||||
struct skypopen_dev *dev = container_of(timer_inq, struct skypopen_dev, timer_inq);
|
||||
ktime_t now;
|
||||
|
||||
if(unload)
|
||||
return HRTIMER_NORESTART;
|
||||
|
||||
now = ktime_get();
|
||||
hrtimer_forward(&dev->timer_inq, now, ktime_set(0, SKYPOPEN_SLEEP * 1000000));
|
||||
wake_up_interruptible(&dev->inq);
|
||||
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
static enum hrtimer_restart my_hrtimer_callback_outq( struct hrtimer *timer_outq )
|
||||
{
|
||||
struct skypopen_dev *dev = container_of(timer_outq, struct skypopen_dev, timer_outq);
|
||||
ktime_t now;
|
||||
|
||||
if(unload)
|
||||
return HRTIMER_NORESTART;
|
||||
|
||||
now = ktime_get();
|
||||
hrtimer_forward(&dev->timer_outq, now, ktime_set(0, SKYPOPEN_SLEEP * 1000000));
|
||||
wake_up_interruptible(&dev->outq);
|
||||
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
#else// CENTOS
|
||||
static int my_hrtimer_callback_inq( struct hrtimer *timer_inq )
|
||||
{
|
||||
struct skypopen_dev *dev = container_of(timer_inq, struct skypopen_dev, timer_inq);
|
||||
|
||||
if(unload)
|
||||
return HRTIMER_NORESTART;
|
||||
|
||||
hrtimer_forward(&dev->timer_inq, timer_inq->expires, ktime_set(0, SKYPOPEN_SLEEP * 1000000));
|
||||
wake_up_interruptible(&dev->inq);
|
||||
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
static int my_hrtimer_callback_outq( struct hrtimer *timer_outq )
|
||||
{
|
||||
struct skypopen_dev *dev = container_of(timer_outq, struct skypopen_dev, timer_outq);
|
||||
|
||||
if(unload)
|
||||
return HRTIMER_NORESTART;
|
||||
|
||||
hrtimer_forward(&dev->timer_outq, timer_outq->expires, ktime_set(0, SKYPOPEN_SLEEP * 1000000));
|
||||
wake_up_interruptible(&dev->outq);
|
||||
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
#endif// CENTOS
|
||||
#endif// WANT_HRTIMER
|
||||
|
||||
/* The clone-specific data structure includes a key field */
|
||||
|
||||
struct skypopen_listitem {
|
||||
struct skypopen_dev device;
|
||||
dev_t key;
|
||||
struct list_head list;
|
||||
|
||||
};
|
||||
|
||||
/* The list of devices, and a lock to protect it */
|
||||
static LIST_HEAD(skypopen_c_list);
|
||||
static spinlock_t skypopen_c_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
/* Look for a device or create one if missing */
|
||||
static struct skypopen_dev *skypopen_c_lookfor_device(dev_t key)
|
||||
{
|
||||
struct skypopen_listitem *lptr;
|
||||
#ifdef WANT_HRTIMER
|
||||
#if 0
|
||||
ktime_t ktime_inq;
|
||||
ktime_t ktime_outq;
|
||||
#endif //0
|
||||
#endif// WANT_HRTIMER
|
||||
|
||||
list_for_each_entry(lptr, &skypopen_c_list, list) {
|
||||
if (lptr->key == key)
|
||||
return &(lptr->device);
|
||||
}
|
||||
|
||||
/* not found */
|
||||
lptr = kmalloc(sizeof(struct skypopen_listitem), GFP_KERNEL);
|
||||
if (!lptr)
|
||||
return NULL;
|
||||
|
||||
/* initialize the device */
|
||||
memset(lptr, 0, sizeof(struct skypopen_listitem));
|
||||
lptr->key = key;
|
||||
|
||||
init_waitqueue_head(&lptr->device.inq);
|
||||
init_waitqueue_head(&lptr->device.outq);
|
||||
#ifndef WANT_HRTIMER
|
||||
setup_timer( &lptr->device.timer_inq, my_timer_callback_inq, (long int)lptr );
|
||||
setup_timer( &lptr->device.timer_outq, my_timer_callback_outq, (long int)lptr );
|
||||
printk( "Starting skypopen OSS driver read timer (%dms) skype client:(%d)\n", SKYPOPEN_SLEEP, current->tgid );
|
||||
mod_timer( &lptr->device.timer_inq, jiffies + msecs_to_jiffies(SKYPOPEN_SLEEP) );
|
||||
printk( "Starting skypopen OSS driver write timer (%dms) skype client:(%d)\n", SKYPOPEN_SLEEP, current->tgid );
|
||||
mod_timer( &lptr->device.timer_outq, jiffies + msecs_to_jiffies(SKYPOPEN_SLEEP) );
|
||||
#else// WANT_HRTIMER
|
||||
#if 0
|
||||
ktime_inq = ktime_set( 0, SKYPOPEN_SLEEP * 1000000);
|
||||
hrtimer_init( &lptr->device.timer_inq, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
|
||||
lptr->device.timer_inq.function = &my_hrtimer_callback_inq;
|
||||
hrtimer_start( &lptr->device.timer_inq, ktime_inq, HRTIMER_MODE_REL );
|
||||
|
||||
ktime_outq = ktime_set( 0, SKYPOPEN_SLEEP * 1000000);
|
||||
hrtimer_init( &lptr->device.timer_outq, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
|
||||
lptr->device.timer_outq.function = &my_hrtimer_callback_outq;
|
||||
hrtimer_start( &lptr->device.timer_outq, ktime_outq, HRTIMER_MODE_REL );
|
||||
#endif
|
||||
|
||||
#endif// WANT_HRTIMER
|
||||
|
||||
/* place it in the list */
|
||||
list_add(&lptr->list, &skypopen_c_list);
|
||||
|
||||
return &(lptr->device);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open and close
|
||||
*/
|
||||
static int skypopen_c_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct skypopen_dev *dev;
|
||||
dev_t key;
|
||||
|
||||
key = current->tgid;
|
||||
|
||||
/* look for a skypopenc device in the list */
|
||||
spin_lock(&skypopen_c_lock);
|
||||
dev = skypopen_c_lookfor_device(key);
|
||||
spin_unlock(&skypopen_c_lock);
|
||||
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
/* then, everything else is copied from the bare skypopen device */
|
||||
filp->private_data = dev;
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
static int skypopen_c_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
/*
|
||||
* Nothing to do, because the device is persistent.
|
||||
* A `real' cloned device should be freed on last close
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
static ssize_t skypopen_read(struct file *filp, char __user *buf, size_t count,
|
||||
loff_t *f_pos)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
size_t written;
|
||||
struct skypopen_dev *dev = filp->private_data;
|
||||
|
||||
if(unload)
|
||||
return -1;
|
||||
|
||||
#ifdef WANT_HRTIMER
|
||||
#if 1
|
||||
if(dev->timer_inq_started == 0){
|
||||
ktime_t ktime_inq;
|
||||
|
||||
ktime_inq = ktime_set( 0, SKYPOPEN_SLEEP * 1000000);
|
||||
hrtimer_init( &dev->timer_inq, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
|
||||
dev->timer_inq.function = &my_hrtimer_callback_inq;
|
||||
hrtimer_start( &dev->timer_inq, ktime_inq, HRTIMER_MODE_REL );
|
||||
dev->timer_inq_started = 1;
|
||||
}
|
||||
#endif
|
||||
#endif// WANT_HRTIMER
|
||||
|
||||
|
||||
//printk("READ\n");
|
||||
prepare_to_wait(&dev->inq, &wait, TASK_INTERRUPTIBLE);
|
||||
schedule();
|
||||
finish_wait(&dev->inq, &wait);
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
written = 0;
|
||||
while (count) {
|
||||
unsigned long unwritten;
|
||||
size_t chunk = count;
|
||||
|
||||
if (chunk > PAGE_SIZE)
|
||||
chunk = PAGE_SIZE; /* Just for latency reasons */
|
||||
unwritten = __clear_user(buf, chunk);
|
||||
written += chunk - unwritten;
|
||||
if (unwritten)
|
||||
break;
|
||||
if (signal_pending(current))
|
||||
return written ? written : -ERESTARTSYS;
|
||||
buf += chunk;
|
||||
count -= chunk;
|
||||
cond_resched();
|
||||
}
|
||||
return written ? written : -EFAULT;
|
||||
}
|
||||
|
||||
static ssize_t skypopen_write(struct file *filp, const char __user *buf, size_t count,
|
||||
loff_t *f_pos)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
struct skypopen_dev *dev = filp->private_data;
|
||||
|
||||
if(unload)
|
||||
return -1;
|
||||
|
||||
#ifdef WANT_HRTIMER
|
||||
#if 1
|
||||
if(dev->timer_outq_started == 0){
|
||||
ktime_t ktime_outq;
|
||||
|
||||
ktime_outq = ktime_set( 0, SKYPOPEN_SLEEP * 1000000);
|
||||
hrtimer_init( &dev->timer_outq, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
|
||||
dev->timer_outq.function = &my_hrtimer_callback_outq;
|
||||
hrtimer_start( &dev->timer_outq, ktime_outq, HRTIMER_MODE_REL );
|
||||
dev->timer_outq_started = 1;
|
||||
}
|
||||
#endif
|
||||
#endif// WANT_HRTIMER
|
||||
|
||||
|
||||
//printk("WRITE\n");
|
||||
prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE);
|
||||
schedule();
|
||||
finish_wait(&dev->outq, &wait);
|
||||
return count;
|
||||
|
||||
}
|
||||
/*
|
||||
* The ioctl() implementation
|
||||
*/
|
||||
|
||||
static int skypopen_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
void __user *argp = (void __user *)arg;
|
||||
int __user *p = argp;
|
||||
|
||||
switch (cmd) {
|
||||
case OSS_GETVERSION:
|
||||
return put_user(SOUND_VERSION, p);
|
||||
case SNDCTL_DSP_GETBLKSIZE:
|
||||
return put_user(SKYPOPEN_BLK, p);
|
||||
case SNDCTL_DSP_GETFMTS:
|
||||
return put_user(28731, p);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct file_operations skypopen_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
.read = skypopen_read,
|
||||
.write = skypopen_write,
|
||||
.ioctl = skypopen_ioctl,
|
||||
.open = skypopen_c_open,
|
||||
.release = skypopen_c_release,
|
||||
};
|
||||
|
||||
/*
|
||||
* Finally, the module stuff
|
||||
*/
|
||||
|
||||
/*
|
||||
* The cleanup function is used to handle initialization failures as well.
|
||||
* Thefore, it must be careful to work correctly even if some of the items
|
||||
* have not been initialized
|
||||
*/
|
||||
|
||||
void skypopen_cleanup_module(void)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
struct skypopen_listitem *lptr, *next;
|
||||
dev_t devno = MKDEV(skypopen_major, skypopen_minor);
|
||||
|
||||
|
||||
unload = 1;
|
||||
|
||||
msleep(100);
|
||||
|
||||
/* Get rid of our char dev entries */
|
||||
if (skypopen_devices) {
|
||||
for (i = 0; i < skypopen_nr_devs; i++) {
|
||||
cdev_del(&skypopen_devices[i].cdev);
|
||||
}
|
||||
kfree(skypopen_devices);
|
||||
}
|
||||
|
||||
/* And all the cloned devices */
|
||||
list_for_each_entry_safe(lptr, next, &skypopen_c_list, list) {
|
||||
#ifndef WANT_HRTIMER
|
||||
ret= del_timer( &lptr->device.timer_inq );
|
||||
printk( "Stopped skypopen OSS driver read timer\n");
|
||||
ret= del_timer( &lptr->device.timer_outq );
|
||||
printk( "Stopped skypopen OSS driver write timer\n");
|
||||
#else// WANT_HRTIMER
|
||||
if(lptr->device.timer_inq_started){
|
||||
ret = hrtimer_cancel( &lptr->device.timer_inq );
|
||||
printk( "Stopped skypopen OSS driver read HRtimer\n");
|
||||
}
|
||||
if(lptr->device.timer_outq_started){
|
||||
ret = hrtimer_cancel( &lptr->device.timer_outq );
|
||||
printk( "Stopped skypopen OSS driver write HRtimer\n");
|
||||
}
|
||||
|
||||
#endif// WANT_HRTIMER
|
||||
list_del(&lptr->list);
|
||||
kfree(lptr);
|
||||
}
|
||||
/* cleanup_module is never called if registering failed */
|
||||
unregister_chrdev_region(devno, skypopen_nr_devs);
|
||||
printk("skypopen OSS driver unloaded\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set up the char_dev structure for this device.
|
||||
*/
|
||||
static void skypopen_setup_cdev(struct skypopen_dev *dev, int index)
|
||||
{
|
||||
int err, devno = MKDEV(skypopen_major, skypopen_minor + index);
|
||||
|
||||
cdev_init(&dev->cdev, &skypopen_fops);
|
||||
dev->cdev.owner = THIS_MODULE;
|
||||
dev->cdev.ops = &skypopen_fops;
|
||||
err = cdev_add (&dev->cdev, devno, 1);
|
||||
/* Fail gracefully if need be */
|
||||
if (err)
|
||||
printk(KERN_NOTICE "Error %d adding skypopen%d", err, index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int skypopen_init_module(void)
|
||||
{
|
||||
int result, i;
|
||||
dev_t dev = 0;
|
||||
|
||||
printk("skypopen OSS driver loading (www.freeswitch.org)\n");
|
||||
/*
|
||||
* Get a range of minor numbers to work with, asking for a dynamic
|
||||
* major unless directed otherwise at load time.
|
||||
*/
|
||||
if (skypopen_major) {
|
||||
dev = MKDEV(skypopen_major, skypopen_minor);
|
||||
result = register_chrdev_region(dev, skypopen_nr_devs, "dsp");
|
||||
} else {
|
||||
result = alloc_chrdev_region(&dev, skypopen_minor, skypopen_nr_devs,
|
||||
"dsp");
|
||||
skypopen_major = MAJOR(dev);
|
||||
}
|
||||
if (result < 0) {
|
||||
printk(KERN_WARNING "skypopen OSS driver: can't get major %d\n", skypopen_major);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate the devices -- we can't have them static, as the number
|
||||
* can be specified at load time
|
||||
*/
|
||||
skypopen_devices = kmalloc(skypopen_nr_devs * sizeof(struct skypopen_dev), GFP_KERNEL);
|
||||
if (!skypopen_devices) {
|
||||
result = -ENOMEM;
|
||||
goto fail; /* Make this more graceful */
|
||||
}
|
||||
memset(skypopen_devices, 0, skypopen_nr_devs * sizeof(struct skypopen_dev));
|
||||
|
||||
/* Initialize each device. */
|
||||
for (i = 0; i < skypopen_nr_devs; i++) {
|
||||
skypopen_setup_cdev(&skypopen_devices[i], i);
|
||||
}
|
||||
|
||||
/* At this point call the init function for any friend device */
|
||||
dev = MKDEV(skypopen_major, skypopen_minor + skypopen_nr_devs);
|
||||
return 0; /* succeed */
|
||||
|
||||
fail:
|
||||
skypopen_cleanup_module();
|
||||
return result;
|
||||
}
|
||||
|
||||
module_init(skypopen_init_module);
|
||||
module_exit(skypopen_cleanup_module);
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* skypopen.h -- definitions for the char module
|
||||
*
|
||||
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
|
||||
* Copyright (C) 2001 O'Reilly & Associates
|
||||
*
|
||||
* The source code in this file can be freely used, adapted,
|
||||
* and redistributed in source or binary form, so long as an
|
||||
* acknowledgment appears in derived source files. The citation
|
||||
* should list that the code comes from the book "Linux Device
|
||||
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
|
||||
* by O'Reilly & Associates. No warranty is attached;
|
||||
* we cannot take responsibility for errors or fitness for use.
|
||||
*
|
||||
* $Id: skypopen.h,v 1.15 2004/11/04 17:51:18 rubini Exp $
|
||||
*/
|
||||
|
||||
#ifndef _SKYPOPEN_H_
|
||||
#define _SKYPOPEN_H_
|
||||
|
||||
#include <linux/ioctl.h> /* needed for the _IOW etc stuff used later */
|
||||
|
||||
#define SKYPOPEN_BLK 960
|
||||
#define SKYPOPEN_SLEEP 10
|
||||
|
||||
#define CENTOS
|
||||
|
||||
#ifndef SKYPOPEN_MAJOR
|
||||
#define SKYPOPEN_MAJOR 14 /* dynamic major by default */
|
||||
#endif
|
||||
|
||||
#ifndef SKYPOPEN_NR_DEVS
|
||||
#define SKYPOPEN_NR_DEVS 1 /* skypopen0 through skypopen3 */
|
||||
#endif
|
||||
|
||||
#define WANT_HRTIMER
|
||||
struct skypopen_dev {
|
||||
struct cdev cdev; /* Char device structure */
|
||||
wait_queue_head_t inq; /* read and write queues */
|
||||
wait_queue_head_t outq; /* read and write queues */
|
||||
#ifndef WANT_HRTIMER
|
||||
struct timer_list timer_inq;
|
||||
struct timer_list timer_outq;
|
||||
#else// WANT_HRTIMER
|
||||
struct hrtimer timer_inq;
|
||||
struct hrtimer timer_outq;
|
||||
#endif// WANT_HRTIMER
|
||||
int timer_inq_started;
|
||||
int timer_outq_started;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The different configurable parameters
|
||||
*/
|
||||
extern int skypopen_major; /* main.c */
|
||||
extern int skypopen_nr_devs;
|
||||
|
||||
|
||||
/*
|
||||
* Prototypes for shared functions
|
||||
*/
|
||||
|
||||
//ssize_t skypopen_read(struct file *filp, char __user *buf, size_t count,
|
||||
//loff_t *f_pos);
|
||||
//ssize_t skypopen_write(struct file *filp, const char __user *buf, size_t count,
|
||||
//loff_t *f_pos);
|
||||
//int skypopen_ioctl(struct inode *inode, struct file *filp,
|
||||
//unsigned int cmd, unsigned long arg);
|
||||
|
||||
#endif /* _SKYPOPEN_H_ */
|
||||
@@ -508,7 +508,7 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session)
|
||||
TAG_IF(!zstr(bye_headers), SIPTAG_HEADER_STR(bye_headers)), TAG_END());
|
||||
}
|
||||
} else {
|
||||
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Sending CANCEL to %s\n", switch_channel_get_name(channel));
|
||||
if (!tech_pvt->got_bye) {
|
||||
switch_channel_set_variable(channel, "sip_hangup_disposition", "send_cancel");
|
||||
@@ -573,7 +573,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
|
||||
char *sticky = NULL;
|
||||
const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full");
|
||||
|
||||
if (sofia_test_flag(tech_pvt, TFLAG_ANS) || switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (sofia_test_flag(tech_pvt, TFLAG_ANS) || switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -653,7 +653,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
|
||||
switch_channel_clear_flag(channel, CF_PROXY_MODE);
|
||||
}
|
||||
|
||||
if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
|
||||
const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
|
||||
tech_pvt->num_codecs = 0;
|
||||
sofia_glue_tech_prepare_codecs(tech_pvt);
|
||||
@@ -723,7 +723,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
|
||||
TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)),
|
||||
TAG_IF(cid, SIPTAG_HEADER_STR(cid)),
|
||||
NUTAG_SESSION_TIMER(session_timeout),
|
||||
TAG_IF(session_timeout, NUTAG_SESSION_REFRESHER(nua_remote_refresher)),
|
||||
NUTAG_SESSION_REFRESHER(session_timeout ? nua_local_refresher : nua_no_refresher),
|
||||
SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
|
||||
SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")),
|
||||
SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
|
||||
@@ -739,7 +739,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
|
||||
TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)),
|
||||
TAG_IF(cid, SIPTAG_HEADER_STR(cid)),
|
||||
NUTAG_SESSION_TIMER(session_timeout),
|
||||
TAG_IF(session_timeout, NUTAG_SESSION_REFRESHER(nua_remote_refresher)),
|
||||
NUTAG_SESSION_REFRESHER(session_timeout ? nua_local_refresher : nua_no_refresher),
|
||||
SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
|
||||
SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")),
|
||||
SIPTAG_CONTENT_TYPE_STR("application/sdp"),
|
||||
@@ -906,7 +906,7 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f
|
||||
tech_pvt->read_frame.flags = SFF_NONE;
|
||||
|
||||
status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags);
|
||||
|
||||
|
||||
if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
|
||||
if (status == SWITCH_STATUS_TIMEOUT) {
|
||||
|
||||
@@ -1084,7 +1084,7 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f
|
||||
tech_pvt->last_ts = 0;
|
||||
|
||||
/* inform them of the codec they are actually sending */
|
||||
|
||||
#if 0
|
||||
if (++tech_pvt->codec_reinvites > 2) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
|
||||
"Ok, some devices *cough* X-lite *cough*\n"
|
||||
@@ -1093,7 +1093,10 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f
|
||||
} else {
|
||||
sofia_glue_do_invite(session);
|
||||
}
|
||||
#endif
|
||||
|
||||
*frame = &silence_frame;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1316,6 +1319,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
|
||||
/* ones that do not need to lock sofia mutex */
|
||||
switch (msg->message_id) {
|
||||
case SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH:
|
||||
case SWITCH_MESSAGE_INDICATE_APPLICATION_EXEC:
|
||||
{
|
||||
sofia_glue_tech_track(tech_pvt->profile, session);
|
||||
@@ -1332,6 +1336,61 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SWITCH_MESSAGE_INDICATE_JITTER_BUFFER:
|
||||
{
|
||||
if (switch_rtp_ready(tech_pvt->rtp_session)) {
|
||||
int len, maxlen = 0, qlen = 0, maxqlen = 50;
|
||||
|
||||
if (msg->string_arg) {
|
||||
char *p;
|
||||
const char *s;
|
||||
|
||||
if (!strncasecmp(msg->string_arg, "debug:", 6)) {
|
||||
s = msg->string_arg + 6;
|
||||
if (s && !strcmp(s, "off")) {
|
||||
s = NULL;
|
||||
}
|
||||
switch_rtp_debug_jitter_buffer(tech_pvt->rtp_session, s);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
||||
if ((len = atoi(msg->string_arg))) {
|
||||
qlen = len / (tech_pvt->read_impl.microseconds_per_packet / 1000);
|
||||
}
|
||||
|
||||
if (qlen) {
|
||||
if ((p = strchr(msg->string_arg, ':'))) {
|
||||
p++;
|
||||
maxlen = atol(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (maxlen) {
|
||||
maxqlen = maxlen / (tech_pvt->read_impl.microseconds_per_packet / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (qlen) {
|
||||
if (switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen, maxqlen,
|
||||
tech_pvt->read_impl.samples_per_packet,
|
||||
tech_pvt->read_impl.samples_per_second) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session),
|
||||
SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames) (%d max frames)\n", len, qlen, maxqlen);
|
||||
switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session),
|
||||
SWITCH_LOG_WARNING, "Error Setting Jitterbuffer to %dms (%d frames)\n", len, qlen);
|
||||
}
|
||||
|
||||
} else {
|
||||
switch_rtp_deactivate_jitter_buffer(tech_pvt->rtp_session);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SWITCH_MESSAGE_INDICATE_DEBUG_AUDIO:
|
||||
{
|
||||
if (switch_rtp_ready(tech_pvt->rtp_session) && !zstr(msg->string_array_arg[0]) && !zstr(msg->string_array_arg[1])) {
|
||||
@@ -1629,7 +1688,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
sofia_glue_tech_set_local_sdp(tech_pvt, NULL, SWITCH_FALSE);
|
||||
|
||||
if (!(switch_channel_test_flag(channel, CF_ANSWERED) || switch_channel_test_flag(channel, CF_EARLY_MEDIA))) {
|
||||
if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
|
||||
const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
|
||||
|
||||
tech_pvt->num_codecs = 0;
|
||||
@@ -2144,7 +2203,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
} else {
|
||||
if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) || !tech_pvt->iananame) {
|
||||
sofia_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
|
||||
if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
|
||||
const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
|
||||
|
||||
tech_pvt->num_codecs = 0;
|
||||
@@ -3338,6 +3397,36 @@ SWITCH_STANDARD_API(sofia_count_reg_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void select_from_profile(sofia_profile_t *profile,
|
||||
const char *user,
|
||||
const char *domain,
|
||||
const char *concat,
|
||||
const char *exclude_contact,
|
||||
switch_stream_handle_t *stream)
|
||||
{
|
||||
struct cb_helper cb;
|
||||
char *sql;
|
||||
|
||||
cb.row_process = 0;
|
||||
|
||||
cb.profile = profile;
|
||||
cb.stream = stream;
|
||||
|
||||
if (exclude_contact) {
|
||||
sql = switch_mprintf("select contact, profile_name, '%q' "
|
||||
"from sip_registrations where sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%') "
|
||||
"and contact not like '%%%s%%'", (concat != NULL) ? concat : "", user, domain, domain, exclude_contact);
|
||||
} else {
|
||||
sql = switch_mprintf("select contact, profile_name, '%q' "
|
||||
"from sip_registrations where sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%')",
|
||||
(concat != NULL) ? concat : "", user, domain, domain);
|
||||
}
|
||||
|
||||
switch_assert(sql);
|
||||
sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, contact_callback, &cb);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_API(sofia_contact_function)
|
||||
{
|
||||
char *data;
|
||||
@@ -3350,6 +3439,7 @@ SWITCH_STANDARD_API(sofia_contact_function)
|
||||
const char *exclude_contact = NULL;
|
||||
const char *user_replacement = NULL;
|
||||
char *reply = "error/facility_not_subscribed";
|
||||
switch_stream_handle_t mystream = { 0 };
|
||||
|
||||
if (!cmd) {
|
||||
stream->write_function(stream, "%s", "");
|
||||
@@ -3385,57 +3475,52 @@ SWITCH_STANDARD_API(sofia_contact_function)
|
||||
}
|
||||
}
|
||||
|
||||
if (!profile_name && domain) {
|
||||
profile_name = domain;
|
||||
if (zstr(domain)) {
|
||||
domain = switch_core_get_variable("domain");
|
||||
}
|
||||
|
||||
if (user && profile_name) {
|
||||
char *sql;
|
||||
if (!user) goto end;
|
||||
|
||||
if (!(profile = sofia_glue_find_profile(profile_name))) {
|
||||
profile_name = domain;
|
||||
domain = NULL;
|
||||
}
|
||||
|
||||
if (!profile && profile_name) {
|
||||
if (zstr(profile_name) || strcmp(profile_name, "*") || zstr(domain)) {
|
||||
if (!zstr(profile_name)) {
|
||||
profile = sofia_glue_find_profile(profile_name);
|
||||
}
|
||||
|
||||
if (!profile) {
|
||||
profile = sofia_glue_find_profile(domain);
|
||||
}
|
||||
}
|
||||
|
||||
if (profile) {
|
||||
struct cb_helper cb;
|
||||
switch_stream_handle_t mystream = { 0 };
|
||||
if (profile || !zstr(domain)) {
|
||||
SWITCH_STANDARD_STREAM(mystream);
|
||||
switch_assert(mystream.data);
|
||||
}
|
||||
|
||||
cb.row_process = 0;
|
||||
if (profile) {
|
||||
if (zstr(domain)) {
|
||||
domain = profile->name;
|
||||
}
|
||||
|
||||
if (!domain || (!strchr(domain, '.') && strcmp(profile_name, domain))) {
|
||||
domain = profile->name;
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_STREAM(mystream);
|
||||
switch_assert(mystream.data);
|
||||
cb.profile = profile;
|
||||
cb.stream = &mystream;
|
||||
|
||||
if (exclude_contact) {
|
||||
sql = switch_mprintf("select contact, profile_name, '%q' "
|
||||
"from sip_registrations where sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%') "
|
||||
"and contact not like '%%%s%%'", (concat != NULL) ? concat : "", user, domain, domain, exclude_contact);
|
||||
} else {
|
||||
sql = switch_mprintf("select contact, profile_name, '%q' "
|
||||
"from sip_registrations where sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%')",
|
||||
(concat != NULL) ? concat : "", user, domain, domain);
|
||||
}
|
||||
|
||||
switch_assert(sql);
|
||||
sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, contact_callback, &cb);
|
||||
switch_safe_free(sql);
|
||||
reply = (char *) mystream.data;
|
||||
if (!zstr(reply) && end_of(reply) == ',') {
|
||||
end_of(reply) = '\0';
|
||||
}
|
||||
|
||||
if (zstr(reply)) {
|
||||
reply = "error/user_not_registered";
|
||||
if (!zstr(profile->domain_name) && !zstr(profile_name) && !strcmp(profile_name, profile->name)) {
|
||||
domain = profile->domain_name;
|
||||
}
|
||||
|
||||
select_from_profile(profile, user, domain, concat, exclude_contact, &mystream);
|
||||
sofia_glue_release_profile(profile);
|
||||
|
||||
} else if (!zstr(domain)) {
|
||||
switch_mutex_lock(mod_sofia_globals.hash_mutex);
|
||||
if (mod_sofia_globals.profile_hash) {
|
||||
switch_hash_index_t *hi;
|
||||
const void *var;
|
||||
void *val;
|
||||
|
||||
for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, &var, NULL, &val);
|
||||
if ((profile = (sofia_profile_t *) val) && !strcmp((char *)var, profile->name)) {
|
||||
select_from_profile(profile, user, domain, concat, exclude_contact, &mystream);
|
||||
profile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (user_replacement) {
|
||||
@@ -3530,18 +3615,27 @@ copydone:
|
||||
|
||||
switch_safe_free(mystream.data);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(mod_sofia_globals.hash_mutex);
|
||||
}
|
||||
|
||||
reply = (char *) mystream.data;
|
||||
|
||||
end:
|
||||
|
||||
if (zstr(reply)) {
|
||||
reply = "error/user_not_registered";
|
||||
} else if (end_of(reply) == ',') {
|
||||
end_of(reply) = '\0';
|
||||
}
|
||||
|
||||
if (reply) {
|
||||
stream->write_function(stream, "%s", reply);
|
||||
}
|
||||
stream->write_function(stream, "%s", reply);
|
||||
reply = NULL;
|
||||
|
||||
switch_safe_free(mystream.data);
|
||||
|
||||
switch_safe_free(data);
|
||||
|
||||
if (profile) {
|
||||
sofia_glue_release_profile(profile);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -3942,7 +4036,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (profile->domain_name && profile->domain_name != profile->name) {
|
||||
if (profile->domain_name && strcmp(profile->domain_name, profile->name)) {
|
||||
profile_name = profile->domain_name;
|
||||
}
|
||||
|
||||
|
||||
@@ -225,6 +225,7 @@ typedef enum {
|
||||
PFLAG_DEL_SUBS_ON_REG,
|
||||
PFLAG_IGNORE_183NOSDP,
|
||||
PFLAG_PRESENCE_PROBE_ON_REGISTER,
|
||||
PFLAG_NO_CONNECTION_REUSE,
|
||||
/* No new flags below this line */
|
||||
PFLAG_MAX
|
||||
} PFLAGS;
|
||||
@@ -744,6 +745,14 @@ typedef struct {
|
||||
char *route_uri;
|
||||
} sofia_destination_t;
|
||||
|
||||
typedef struct {
|
||||
char network_ip[80];
|
||||
int network_port;
|
||||
const char *is_nat;
|
||||
int is_auto_nat;
|
||||
} sofia_nat_parse_t;
|
||||
|
||||
|
||||
#define sofia_test_pflag(obj, flag) ((obj)->pflags[flag] ? 1 : 0)
|
||||
#define sofia_set_pflag(obj, flag) (obj)->pflags[flag] = 1
|
||||
#define sofia_set_pflag_locked(obj, flag) assert(obj->flag_mutex != NULL);\
|
||||
@@ -1026,6 +1035,7 @@ void sofia_profile_destroy(sofia_profile_t *profile);
|
||||
switch_status_t sip_dig_function(_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream);
|
||||
const char *sofia_gateway_status_name(sofia_gateway_status_t status);
|
||||
void sofia_reg_fire_custom_gateway_state_event(sofia_gateway_t *gateway, int status, const char *phrase);
|
||||
uint32_t sofia_reg_reg_count(sofia_profile_t *profile, const char *user, const char *host);
|
||||
void sofia_glue_copy_t38_options(switch_t38_options_t *t38_options, switch_core_session_t *session);
|
||||
switch_t38_options_t *sofia_glue_extract_t38_options(switch_core_session_t *session, const char *r_sdp);
|
||||
char *sofia_glue_get_multipart(switch_core_session_t *session, const char *prefix, const char *sdp, char **mp_type);
|
||||
@@ -1039,3 +1049,4 @@ switch_status_t sofia_glue_sdp_map(const char *r_sdp, switch_event_t **fmtp, swi
|
||||
void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl);
|
||||
void sofia_glue_check_dtmf_type(private_object_t *tech_pvt);
|
||||
void sofia_glue_parse_rtp_bugs(uint32_t *flag_pole, const char *str);
|
||||
char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, sofia_nat_parse_t *np);
|
||||
@@ -357,7 +357,7 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
|
||||
switch_channel_answer(channel);
|
||||
switch_channel_set_variable(channel, "auto_answer_destination", switch_channel_get_variable(channel, "destination_number"));
|
||||
switch_ivr_session_transfer(session, "auto_answer", NULL, NULL);
|
||||
@@ -1486,6 +1486,8 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
|
||||
TAG_IF(profile->timer_t2, NTATAG_SIP_T2(profile->timer_t2)),
|
||||
TAG_IF(profile->timer_t4, NTATAG_SIP_T4(profile->timer_t4)),
|
||||
SIPTAG_ACCEPT_STR("application/sdp, multipart/mixed"),
|
||||
TAG_IF(sofia_test_pflag(profile, PFLAG_NO_CONNECTION_REUSE),
|
||||
TPTAG_REUSE(0)),
|
||||
TAG_END()); /* Last tag should always finish the sequence */
|
||||
|
||||
if (!profile->nua) {
|
||||
@@ -1715,16 +1717,9 @@ void launch_sofia_profile_thread(sofia_profile_t *profile)
|
||||
|
||||
static void logger(void *logarg, char const *fmt, va_list ap)
|
||||
{
|
||||
/* gcc 4.4 gets mad at us for testing if (ap) so let's try to work around it....*/
|
||||
void *ap_ptr = (void *) (intptr_t) ap;
|
||||
|
||||
if (!fmt) return;
|
||||
|
||||
if (ap_ptr) {
|
||||
switch_log_vprintf(SWITCH_CHANNEL_LOG_CLEAN, mod_sofia_globals.tracelevel, fmt, ap);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, mod_sofia_globals.tracelevel, "%s", fmt);
|
||||
}
|
||||
switch_log_vprintf(SWITCH_CHANNEL_LOG_CLEAN, mod_sofia_globals.tracelevel, fmt, ap);
|
||||
}
|
||||
|
||||
static su_log_t *sofia_get_logger(const char *name)
|
||||
@@ -3673,6 +3668,13 @@ switch_status_t config_sofia(int reload, char *profile_name)
|
||||
} else {
|
||||
profile->timer_t4 = 4000;
|
||||
}
|
||||
} else if (!strcasecmp(var, "reuse-connections")) {
|
||||
switch_bool_t value = switch_true(val);
|
||||
if (!value) {
|
||||
sofia_set_pflag(profile, PFLAG_NO_CONNECTION_REUSE);
|
||||
} else {
|
||||
sofia_clear_pflag(profile, PFLAG_NO_CONNECTION_REUSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4112,7 +4114,7 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status
|
||||
|
||||
}
|
||||
|
||||
if (channel && sip && (status == 300 || status == 301 || status == 302 || status == 305) && switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (channel && sip && (status == 300 || status == 301 || status == 302 || status == 305) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
sip_contact_t *p_contact = sip->sip_contact;
|
||||
int i = 0;
|
||||
char var_name[80];
|
||||
@@ -4643,7 +4645,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
status = 183;
|
||||
}
|
||||
|
||||
if (channel && (status == 180 || status == 183) && switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (channel && (status == 180 || status == 183) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
const char *val;
|
||||
if ((val = switch_channel_get_variable(channel, "sip_auto_answer")) && switch_true(val)) {
|
||||
nua_notify(nh, NUTAG_NEWSUB(1), NUTAG_SUBSTATE(nua_substate_active), SIPTAG_EVENT_STR("talk"), TAG_END());
|
||||
@@ -4690,7 +4692,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
|
||||
if (r_sdp) {
|
||||
if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
|
||||
if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) && !switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) && switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
|
||||
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA");
|
||||
}
|
||||
sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
|
||||
@@ -4713,7 +4715,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
}
|
||||
goto done;
|
||||
} else {
|
||||
if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) && !switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
|
||||
if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) && switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
|
||||
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION");
|
||||
} else {
|
||||
if (sofia_glue_tech_media(tech_pvt, (char *) r_sdp) != SWITCH_STATUS_SUCCESS) {
|
||||
@@ -4908,7 +4910,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
sofia_glue_tech_set_local_sdp(tech_pvt, NULL, SWITCH_FALSE);
|
||||
|
||||
if (!switch_channel_media_ready(channel)) {
|
||||
if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
|
||||
//const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
|
||||
|
||||
tech_pvt->num_codecs = 0;
|
||||
@@ -6253,7 +6255,8 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_
|
||||
|
||||
if (!is_nat && profile->nat_acl_count) {
|
||||
uint32_t x = 0;
|
||||
int ok = 1;
|
||||
int contact_private_ip = 1;
|
||||
int network_private_ip = 0;
|
||||
char *last_acl = NULL;
|
||||
const char *contact_host = NULL;
|
||||
|
||||
@@ -6262,14 +6265,37 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_
|
||||
}
|
||||
|
||||
if (!zstr(contact_host)) {
|
||||
/* NAT mode double check logic and examples.
|
||||
|
||||
Example 1: the contact_host is 192.168.1.100 and the network_ip is also 192.168.1.100 the end point
|
||||
is most likely behind nat with us so we need to veto that decision to turn on nat processing.
|
||||
|
||||
Example 2: the contact_host is 192.168.1.100 and the network_ip is 192.0.2.100 which is a public internet ip
|
||||
the remote endpoint is likely behind a remote nat traversing the public internet.
|
||||
|
||||
This secondary check is here to double check the conclusion of nat settigs to ensure we don't set net
|
||||
in cases where we don't really need to be doing this.
|
||||
|
||||
Why would you want to do this? Well if your FreeSWITCH is behind nat and you want to talk to endpoints behind
|
||||
remote NAT over the public internet in addition to endpoints behind nat with you. This simplifies that process.
|
||||
|
||||
*/
|
||||
|
||||
for (x = 0; x < profile->nat_acl_count; x++) {
|
||||
last_acl = profile->nat_acl[x];
|
||||
if (!(ok = switch_check_network_list_ip(contact_host, last_acl))) {
|
||||
if ((contact_private_ip = switch_check_network_list_ip(contact_host, last_acl))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (contact_private_ip) {
|
||||
for (x = 0; x < profile->nat_acl_count; x++) {
|
||||
if ((network_private_ip = switch_check_network_list_ip(network_ip, profile->nat_acl[x]))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
if (contact_private_ip && !network_private_ip) {
|
||||
is_nat = last_acl;
|
||||
}
|
||||
}
|
||||
@@ -6818,11 +6844,19 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_
|
||||
|
||||
|
||||
if (sip->sip_request->rq_url->url_params) {
|
||||
gw_name = sofia_glue_find_parameter(sip->sip_request->rq_url->url_params, "gw=");
|
||||
gw_name = sofia_glue_find_parameter_value(session, sip->sip_request->rq_url->url_params, "gw=");
|
||||
}
|
||||
|
||||
if (strstr(destination_number, "gw+")) {
|
||||
gw_name = destination_number + 3;
|
||||
if (sofia_test_pflag(profile, PFLAG_FULL_ID)) {
|
||||
char *tmp;
|
||||
gw_name = switch_core_session_strdup(session, destination_number + 3);
|
||||
if ((tmp = strchr(gw_name, '@'))) {
|
||||
*tmp = '\0';
|
||||
}
|
||||
} else {
|
||||
gw_name = destination_number + 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (gw_name) {
|
||||
|
||||
@@ -2342,7 +2342,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
|
||||
nua_invite(tech_pvt->nh,
|
||||
NUTAG_AUTOANSWER(0),
|
||||
NUTAG_SESSION_TIMER(session_timeout),
|
||||
TAG_IF(session_timeout, NUTAG_SESSION_REFRESHER(nua_remote_refresher)),
|
||||
NUTAG_SESSION_REFRESHER(session_timeout ? nua_local_refresher : nua_no_refresher),
|
||||
TAG_IF(sofia_test_flag(tech_pvt, TFLAG_RECOVERED), NUTAG_INVITE_TIMER(UINT_MAX)),
|
||||
TAG_IF(invite_full_from, SIPTAG_FROM_STR(invite_full_from)),
|
||||
TAG_IF(invite_full_to, SIPTAG_TO_STR(invite_full_to)),
|
||||
@@ -2669,7 +2669,8 @@ switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force)
|
||||
tech_pvt->rm_encoding,
|
||||
tech_pvt->codec_ms,
|
||||
tech_pvt->rm_rate);
|
||||
|
||||
|
||||
switch_yield(tech_pvt->read_impl.microseconds_per_packet);
|
||||
switch_core_session_lock_codec_write(tech_pvt->session);
|
||||
switch_core_session_lock_codec_read(tech_pvt->session);
|
||||
resetting = 1;
|
||||
@@ -3153,18 +3154,37 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
|
||||
|
||||
if ((val = switch_channel_get_variable(tech_pvt->channel, "jitterbuffer_msec"))) {
|
||||
int len = atoi(val);
|
||||
int maxlen = 0;
|
||||
char *p;
|
||||
|
||||
if (len < 100 || len > 1000) {
|
||||
if ((p = strchr(val, ':'))) {
|
||||
p++;
|
||||
maxlen = atoi(p);
|
||||
}
|
||||
|
||||
if (len < 20 || len > 10000) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR,
|
||||
"Invalid Jitterbuffer spec [%d] must be between 100 and 1000\n", len);
|
||||
"Invalid Jitterbuffer spec [%d] must be between 20 and 10000\n", len);
|
||||
} else {
|
||||
int qlen;
|
||||
|
||||
int qlen, maxqlen = 50;
|
||||
|
||||
qlen = len / (tech_pvt->read_impl.microseconds_per_packet / 1000);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames)\n", len,
|
||||
qlen);
|
||||
switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen);
|
||||
if (maxlen) {
|
||||
maxqlen = maxlen / (tech_pvt->read_impl.microseconds_per_packet / 1000);
|
||||
}
|
||||
|
||||
if (switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen, maxqlen,
|
||||
tech_pvt->read_impl.samples_per_packet,
|
||||
tech_pvt->read_impl.samples_per_second) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session),
|
||||
SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames)\n", len, qlen);
|
||||
switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session),
|
||||
SWITCH_LOG_WARNING, "Error Setting Jitterbuffer to %dms (%d frames)\n", len, qlen);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4668,8 +4688,8 @@ void sofia_glue_pass_sdp(private_object_t *tech_pvt, char *sdp)
|
||||
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, sdp);
|
||||
|
||||
if (!sofia_test_flag(tech_pvt, TFLAG_CHANGE_MEDIA) && !sofia_test_flag(tech_pvt, TFLAG_RECOVERING) &&
|
||||
(switch_channel_test_flag(other_channel, CF_OUTBOUND) &&
|
||||
switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND) && switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE))) {
|
||||
(switch_channel_direction(other_channel) == SWITCH_CALL_DIRECTION_OUTBOUND &&
|
||||
switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_OUTBOUND && switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE))) {
|
||||
switch_ivr_nomedia(val, SMF_FORCE);
|
||||
sofia_set_flag_locked(tech_pvt, TFLAG_CHANGE_MEDIA);
|
||||
}
|
||||
@@ -5041,9 +5061,20 @@ static int recover_callback(void *pArg, int argc, char **argv, char **columnName
|
||||
const char *port = switch_channel_get_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
|
||||
const char *r_ip = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE);
|
||||
const char *r_port = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE);
|
||||
const char *use_uuid;
|
||||
|
||||
sofia_set_flag(tech_pvt, TFLAG_RECOVERING);
|
||||
|
||||
if ((use_uuid = switch_channel_get_variable(channel, "origination_uuid"))) {
|
||||
if (switch_core_session_set_uuid(session, use_uuid) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s set UUID=%s\n", switch_channel_get_name(channel),
|
||||
use_uuid);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "%s set UUID=%s FAILED\n",
|
||||
switch_channel_get_name(channel), use_uuid);
|
||||
}
|
||||
}
|
||||
|
||||
if (!switch_channel_test_flag(channel, CF_PROXY_MODE) && ip && port) {
|
||||
const char *tmp;
|
||||
tech_pvt->iananame = tech_pvt->rm_encoding = (char *) switch_channel_get_variable(channel, "sip_use_codec_name");
|
||||
@@ -6105,6 +6136,129 @@ void sofia_glue_parse_rtp_bugs(uint32_t *flag_pole, const char *str)
|
||||
}
|
||||
}
|
||||
|
||||
char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, sofia_nat_parse_t *np)
|
||||
{
|
||||
char *contact_str = NULL;
|
||||
const char *contact_host, *contact_user;
|
||||
sip_contact_t const *contact;
|
||||
char *port;
|
||||
const char *display = "\"user\"";
|
||||
char new_port[25] = "";
|
||||
sofia_nat_parse_t lnp = { { 0 } };
|
||||
const char *ipv6;
|
||||
sip_from_t const *from;
|
||||
|
||||
if (!sip || !sip->sip_contact || !sip->sip_contact->m_url) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
from = sip->sip_from;
|
||||
contact = sip->sip_contact;
|
||||
|
||||
if (!np) {
|
||||
np = &lnp;
|
||||
}
|
||||
|
||||
sofia_glue_get_addr(nua_current_request(profile->nua), np->network_ip, sizeof(np->network_ip), &np->network_port);
|
||||
|
||||
if (sofia_glue_check_nat(profile, np->network_ip)) {
|
||||
np->is_auto_nat = 1;
|
||||
}
|
||||
|
||||
port = (char *) contact->m_url->url_port;
|
||||
contact_host = sip->sip_contact->m_url->url_host;
|
||||
contact_user = sip->sip_contact->m_url->url_user;
|
||||
|
||||
display = contact->m_display;
|
||||
|
||||
|
||||
if (zstr(display)) {
|
||||
if (from) {
|
||||
display = from->a_display;
|
||||
if (zstr(display)) {
|
||||
display = "\"user\"";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
display = "\"user\"";
|
||||
}
|
||||
|
||||
if (sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION)) {
|
||||
if (sip->sip_via) {
|
||||
const char *v_port = sip->sip_via->v_port;
|
||||
const char *v_host = sip->sip_via->v_host;
|
||||
|
||||
if (v_host && sip->sip_via->v_received) {
|
||||
np->is_nat = "via received";
|
||||
} else if (v_host && strcmp(np->network_ip, v_host)) {
|
||||
np->is_nat = "via host";
|
||||
} else if (v_port && atoi(v_port) != np->network_port) {
|
||||
np->is_nat = "via port";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!np->is_nat && sip && sip->sip_via && sip->sip_via->v_port &&
|
||||
atoi(sip->sip_via->v_port) == 5060 && np->network_port != 5060 ) {
|
||||
np->is_nat = "via port";
|
||||
}
|
||||
|
||||
if (!np->is_nat && profile->nat_acl_count) {
|
||||
uint32_t x = 0;
|
||||
int ok = 1;
|
||||
char *last_acl = NULL;
|
||||
|
||||
if (!zstr(contact_host)) {
|
||||
for (x = 0; x < profile->nat_acl_count; x++) {
|
||||
last_acl = profile->nat_acl[x];
|
||||
if (!(ok = switch_check_network_list_ip(contact_host, last_acl))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
np->is_nat = last_acl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (np->is_nat && profile->local_network && switch_check_network_list_ip(np->network_ip, profile->local_network)) {
|
||||
if (profile->debug) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s is on local network, not seting NAT mode.\n", np->network_ip);
|
||||
}
|
||||
np->is_nat = NULL;
|
||||
}
|
||||
|
||||
if (zstr(contact_host)) {
|
||||
np->is_nat = "No contact host";
|
||||
}
|
||||
|
||||
if (np->is_nat) {
|
||||
contact_host = np->network_ip;
|
||||
switch_snprintf(new_port, sizeof(new_port), ":%d", np->network_port);
|
||||
port = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (port) {
|
||||
switch_snprintf(new_port, sizeof(new_port), ":%s", port);
|
||||
}
|
||||
|
||||
ipv6 = strchr(contact_host, ':');
|
||||
if (contact->m_url->url_params) {
|
||||
contact_str = switch_mprintf("%s <sip:%s@%s%s%s%s;%s>%s",
|
||||
display, contact->m_url->url_user,
|
||||
ipv6 ? "[" : "",
|
||||
contact_host, ipv6 ? "]" : "", new_port, contact->m_url->url_params, np->is_nat ? ";fs_nat=yes" : "");
|
||||
} else {
|
||||
contact_str = switch_mprintf("%s <sip:%s@%s%s%s%s>%s",
|
||||
display,
|
||||
contact->m_url->url_user, ipv6 ? "[" : "", contact_host, ipv6 ? "]" : "", new_port, np->is_nat ? ";fs_nat=yes" : "");
|
||||
}
|
||||
|
||||
|
||||
return contact_str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -817,6 +817,19 @@ void sofia_reg_auth_challenge(nua_t *nua, sofia_profile_t *profile, nua_handle_t
|
||||
switch_safe_free(auth_str);
|
||||
}
|
||||
|
||||
uint32_t sofia_reg_reg_count(sofia_profile_t *profile, const char *user, const char *host)
|
||||
{
|
||||
char buf[32] = "";
|
||||
char *sql;
|
||||
|
||||
sql = switch_mprintf("select count(*) from sip_registrations where profile_name='%q' and "
|
||||
"sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%')", profile->name, user, host, host);
|
||||
|
||||
sofia_glue_execute_sql2str(profile, profile->ireg_mutex, sql, buf, sizeof(buf));
|
||||
switch_safe_free(sql);
|
||||
return atoi(buf);
|
||||
}
|
||||
|
||||
uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, sofia_regtype_t regtype, char *key,
|
||||
uint32_t keylen, switch_event_t **v_event, const char *is_nat)
|
||||
{
|
||||
@@ -1065,6 +1078,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
|
||||
if (exptime && v_event && *v_event) {
|
||||
char *exp_var;
|
||||
char *allow_multireg = NULL;
|
||||
int force_connectile = 0;
|
||||
|
||||
allow_multireg = switch_event_get_header(*v_event, "sip-allow-multiple-registrations");
|
||||
if (allow_multireg && switch_false(allow_multireg)) {
|
||||
@@ -1081,8 +1095,13 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
|
||||
to_user = force_user;
|
||||
}
|
||||
|
||||
if ((v_contact_str = switch_event_get_header(*v_event, "sip-force-contact"))) {
|
||||
if (!strcasecmp(v_contact_str, "NDLB-connectile-dysfunction-2.0")) {
|
||||
if (profile->rport_level == 3 && sip->sip_user_agent &&
|
||||
sip->sip_user_agent->g_string && !strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7)) {
|
||||
force_connectile = 1;
|
||||
}
|
||||
|
||||
if ((v_contact_str = switch_event_get_header(*v_event, "sip-force-contact")) || force_connectile) {
|
||||
if ((!strcasecmp(v_contact_str, "NDLB-connectile-dysfunction-2.0")) || force_connectile) {
|
||||
char *path_encoded;
|
||||
size_t path_encoded_len;
|
||||
char my_contact_str[1024];
|
||||
@@ -1139,30 +1158,24 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
|
||||
}
|
||||
|
||||
if (auth_res != AUTH_OK && !stale) {
|
||||
if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) {
|
||||
if (regtype == REG_REGISTER) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SIP auth %s (REGISTER) on sofia profile '%s' "
|
||||
"for [%s@%s] from ip %s\n", forbidden ? "failure" : "challenge", profile->name, to_user, to_host, network_ip);
|
||||
}
|
||||
if (auth_res == AUTH_FORBIDDEN) {
|
||||
nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
|
||||
forbidden = 1;
|
||||
} else {
|
||||
nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), TAG_END());
|
||||
}
|
||||
|
||||
if (profile->debug) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send %s for [%s@%s]\n",
|
||||
forbidden ? "forbidden" : "challenge", to_user, to_host);
|
||||
}
|
||||
if (auth_res == AUTH_FORBIDDEN) {
|
||||
nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
|
||||
|
||||
/* Log line added to support Fail2Ban */
|
||||
if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) {
|
||||
if (regtype == REG_INVITE) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SIP auth failure (INVITE) on sofia profile '%s' "
|
||||
"for [%s@%s] from ip %s\n", profile->name, to_user, to_host, network_ip);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), TAG_END());
|
||||
/* Log line added to support Fail2Ban */
|
||||
if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SIP auth %s (%s) on sofia profile '%s' "
|
||||
"for [%s@%s] from ip %s\n", forbidden ? "failure" : "challenge",
|
||||
(regtype == REG_INVITE) ? "INVITE" : "REGISTER", profile->name, to_user, to_host, network_ip);
|
||||
}
|
||||
|
||||
switch_goto_int(r, 1, end);
|
||||
}
|
||||
}
|
||||
@@ -1193,14 +1206,18 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
|
||||
realm = from_host;
|
||||
}
|
||||
|
||||
if (regtype == REG_REGISTER) {
|
||||
sofia_reg_auth_challenge(nua, profile, nh, regtype, realm, stale);
|
||||
if (profile->debug) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Requesting Registration from: [%s@%s]\n", to_user, to_host);
|
||||
}
|
||||
} else {
|
||||
sofia_reg_auth_challenge(nua, profile, nh, regtype, realm, stale);
|
||||
sofia_reg_auth_challenge(nua, profile, nh, regtype, realm, stale);
|
||||
|
||||
if (profile->debug) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send challenge for [%s@%s]\n", to_user, to_host);
|
||||
}
|
||||
/* Log line added to support Fail2Ban */
|
||||
if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SIP auth challenge (%s) on sofia profile '%s' "
|
||||
"for [%s@%s] from ip %s\n", (regtype == REG_INVITE) ? "INVITE" : "REGISTER",
|
||||
profile->name, to_user, to_host, network_ip);
|
||||
}
|
||||
|
||||
switch_goto_int(r, 1, end);
|
||||
}
|
||||
reg:
|
||||
@@ -1294,6 +1311,12 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
|
||||
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
|
||||
}
|
||||
|
||||
if (sofia_reg_reg_count(profile, to_user, reg_host) == 1) {
|
||||
sql = switch_mprintf("delete from sip_presence where sip_user='%q' and sip_host='%q' and profile_name='%q' and open_closed='closed'",
|
||||
to_user, reg_host, profile->name);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DELETE PRESENCE SQL: %s\n", sql);
|
||||
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(profile->ireg_mutex);
|
||||
|
||||
@@ -1357,8 +1380,16 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
|
||||
|
||||
|
||||
} else {
|
||||
int send = 1;
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
if (multi_reg) {
|
||||
if (sofia_reg_reg_count(profile, to_user, sub_host) > 0) {
|
||||
send = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (send && switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
|
||||
|
||||
@@ -346,8 +346,8 @@ static switch_status_t load_config(switch_memory_pool_t *pool)
|
||||
} else if (!strcasecmp(var, "default-template")) {
|
||||
globals.default_template = switch_core_strdup(pool, val);
|
||||
} else if (!strcasecmp(var, "master-file-only")) {
|
||||
globals.masterfileonly = switch_true(val);
|
||||
}
|
||||
globals.masterfileonly = switch_true(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,8 +405,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_cdr_csv_load)
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ else
|
||||
LOCAL_LDFLAGS=-L/usr/postgres/8.3/lib -R/usr/postgres/8.3/lib -lpq -static
|
||||
endif
|
||||
else
|
||||
LOCAL_CFLAGS=-I/usr/include/postgresql
|
||||
LOCAL_LDFLAGS=-lpq -static
|
||||
endif
|
||||
include ../../../../build/modmake.rules
|
||||
@@ -1,5 +1,6 @@
|
||||
-- Sample CDR table schema
|
||||
|
||||
create table a (
|
||||
create table cdr (
|
||||
id serial primary key,
|
||||
local_ip_v4 inet not null,
|
||||
caller_id_name varchar,
|
||||
@@ -20,26 +21,3 @@ create table a (
|
||||
sip_hangup_disposition varchar,
|
||||
ani varchar
|
||||
);
|
||||
|
||||
create table g (
|
||||
id serial primary key,
|
||||
local_ip_v4 inet not null,
|
||||
caller_id_name varchar,
|
||||
caller_id_number varchar,
|
||||
destination_number varchar not null,
|
||||
context varchar not null,
|
||||
start_stamp timestamp with time zone not null,
|
||||
answer_stamp timestamp with time zone,
|
||||
end_stamp timestamp with time zone not null,
|
||||
duration int not null,
|
||||
billsec int not null,
|
||||
hangup_cause varchar not null,
|
||||
uuid uuid not null,
|
||||
bleg_uuid uuid,
|
||||
accountcode varchar,
|
||||
read_codec varchar,
|
||||
write_codec varchar,
|
||||
sip_hangup_disposition varchar,
|
||||
ani varchar
|
||||
);
|
||||
|
||||
@@ -52,8 +52,8 @@ typedef struct cdr_fd cdr_fd_t;
|
||||
|
||||
const char *default_template =
|
||||
"\"${local_ip_v4}\",\"${caller_id_name}\",\"${caller_id_number}\",\"${destination_number}\",\"${context}\",\"${start_stamp}\","
|
||||
"\"${answer_stamp}\",\"${end_stamp}\",\"${duration}\",\"${billsec}\",\"${hangup_cause}\",\"${uuid}\",\"${bleg_uuid}\", \"${accountcode}\","
|
||||
"\"${read_codec}\", \"${write_codec}\"\n";
|
||||
"\"${answer_stamp}\",\"${end_stamp}\",\"${duration}\",\"${billsec}\",\"${hangup_cause}\",\"${uuid}\",\"${bleg_uuid}\",\"${accountcode}\","
|
||||
"\"${read_codec}\",\"${write_codec}\"";
|
||||
|
||||
static struct {
|
||||
switch_memory_pool_t *pool;
|
||||
@@ -65,9 +65,9 @@ static struct {
|
||||
int rotate;
|
||||
int debug;
|
||||
cdr_leg_t legs;
|
||||
char *a_table;
|
||||
char *g_table;
|
||||
char *db_info;
|
||||
char *db_table;
|
||||
char *spool_format;
|
||||
PGconn *db_connection;
|
||||
int db_online;
|
||||
switch_mutex_t *db_mutex;
|
||||
@@ -115,13 +115,13 @@ static void do_rotate(cdr_fd_t *fd)
|
||||
|
||||
if (globals.rotate) {
|
||||
switch_time_exp_lt(&tm, switch_micro_time_now());
|
||||
switch_strftime(date, &retsize, sizeof(date), "%Y-%m-%d-%H-%M-%S", &tm);
|
||||
switch_strftime_nocheck(date, &retsize, sizeof(date), "%Y-%m-%d-%H-%M-%S", &tm);
|
||||
|
||||
len = strlen(fd->path) + strlen(date) + 2;
|
||||
p = switch_mprintf("%s.%s", fd->path, date);
|
||||
assert(p);
|
||||
switch_file_rename(fd->path, p, globals.pool);
|
||||
free(p);
|
||||
switch_safe_free(p);
|
||||
}
|
||||
|
||||
do_reopen(fd);
|
||||
@@ -139,10 +139,12 @@ static void do_rotate(cdr_fd_t *fd)
|
||||
|
||||
}
|
||||
|
||||
static void write_cdr(const char *path, const char *log_line)
|
||||
static void spool_cdr(const char *path, const char *log_line)
|
||||
{
|
||||
cdr_fd_t *fd = NULL;
|
||||
char *log_line_lf = NULL;
|
||||
unsigned int bytes_in, bytes_out;
|
||||
int loops = 0;
|
||||
|
||||
if (!(fd = switch_core_hash_find(globals.fd_hash, path))) {
|
||||
fd = switch_core_alloc(globals.pool, sizeof(*fd));
|
||||
@@ -154,8 +156,15 @@ static void write_cdr(const char *path, const char *log_line)
|
||||
switch_core_hash_insert(globals.fd_hash, path, fd);
|
||||
}
|
||||
|
||||
if (end_of(log_line) != '\n') {
|
||||
log_line_lf = switch_mprintf("%s\n", log_line);
|
||||
} else {
|
||||
switch_strdup(log_line_lf, log_line);
|
||||
}
|
||||
assert(log_line_lf);
|
||||
|
||||
switch_mutex_lock(fd->mutex);
|
||||
bytes_out = (unsigned) strlen(log_line);
|
||||
bytes_out = (unsigned) strlen(log_line_lf);
|
||||
|
||||
if (fd->fd < 0) {
|
||||
do_reopen(fd);
|
||||
@@ -169,167 +178,154 @@ static void write_cdr(const char *path, const char *log_line)
|
||||
do_rotate(fd);
|
||||
}
|
||||
|
||||
if ((bytes_in = write(fd->fd, log_line, bytes_out)) != bytes_out) {
|
||||
while ((bytes_in = write(fd->fd, log_line_lf, bytes_out)) != bytes_out && ++loops < 10) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Write error to file %s %d/%d\n", path, (int) bytes_in, (int) bytes_out);
|
||||
do_rotate(fd);
|
||||
switch_yield(250000);
|
||||
}
|
||||
|
||||
fd->bytes += bytes_in;
|
||||
if (bytes_in > 0) {
|
||||
fd->bytes += bytes_in;
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
switch_mutex_unlock(fd->mutex);
|
||||
switch_safe_free(log_line_lf);
|
||||
}
|
||||
|
||||
static int save_cdr(const char* const table, const char* const template, const char* const cdr)
|
||||
static switch_status_t insert_cdr(const char * const template, const char * const cdr)
|
||||
{
|
||||
char* columns;
|
||||
char* values;
|
||||
char* p;
|
||||
unsigned clen;
|
||||
unsigned vlen;
|
||||
char* query;
|
||||
const char* const query_template = "INSERT INTO %s (%s) VALUES (%s);";
|
||||
PGresult* res;
|
||||
char *columns, *values;
|
||||
char *p, *q;
|
||||
unsigned vlen;
|
||||
char *nullValues, *temp, *tp;
|
||||
int nullCounter = 0, charCounter = 0;
|
||||
char *sql = NULL, *path = NULL;
|
||||
PGresult *res;
|
||||
|
||||
if (!table || !*table || !template || !*template || !cdr || !*cdr) {
|
||||
if (!template || !*template || !cdr || !*cdr) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Bad parameter\n");
|
||||
return 0;
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
columns = strdup(template);
|
||||
for (p = columns; *p; ++p) {
|
||||
/* Build comma-separated list of field names by dropping $ { } ; chars */
|
||||
switch_strdup(columns, template);
|
||||
for (p = columns, q = columns; *p; ++p) {
|
||||
switch (*p) {
|
||||
case '$': case '"': case '{': case '}': case ';':
|
||||
*p = ' ';
|
||||
break;
|
||||
case '$': case '"': case '{': case '}': case ';':
|
||||
break;
|
||||
default:
|
||||
*q++ = *p;
|
||||
}
|
||||
}
|
||||
clen = p - columns;
|
||||
*q = '\0';
|
||||
|
||||
values = strdup(cdr);
|
||||
/*
|
||||
* In the expanded vars, replace double quotes (") with single quotes (')
|
||||
* for correct PostgreSQL syntax, and replace semi-colon with space to
|
||||
* prevent SQL injection attacks
|
||||
*/
|
||||
switch_strdup(values, cdr);
|
||||
for (p = values; *p; ++p) {
|
||||
switch(*p) {
|
||||
case '"':
|
||||
*p = '\'';
|
||||
break;
|
||||
case ';':
|
||||
*p = ' ';
|
||||
break;
|
||||
case '"':
|
||||
*p = '\'';
|
||||
break;
|
||||
case ';':
|
||||
*p = ' ';
|
||||
break;
|
||||
}
|
||||
}
|
||||
vlen = p - values;
|
||||
/*
|
||||
Patch for changing spaces (; ;) in the template paterns to NULL (ex.) ; ; --PACH--> null
|
||||
- added new functionality - space removing
|
||||
*/
|
||||
char *spaceColumns;
|
||||
int spaceCounter=0;
|
||||
for (p=columns; *p; ++p)
|
||||
{
|
||||
if (*p==' ')
|
||||
{
|
||||
spaceCounter++;
|
||||
}
|
||||
}
|
||||
spaceColumns = (char*)malloc(clen-spaceCounter+1);
|
||||
char *pt=spaceColumns;
|
||||
for (p=columns; *p; ++p)
|
||||
{
|
||||
if (*p!=' ')
|
||||
{
|
||||
*pt=*p;
|
||||
pt++;
|
||||
}
|
||||
}
|
||||
*pt=0;
|
||||
pt=columns;
|
||||
columns=spaceColumns;
|
||||
free(pt);
|
||||
char *nullValues;
|
||||
int nullCounter=0;
|
||||
int charCounter=0;
|
||||
for (p=values; *p; ++p)
|
||||
{
|
||||
if (*p==',')
|
||||
{
|
||||
if (charCounter==0)
|
||||
{
|
||||
|
||||
/*
|
||||
* Patch for changing empty strings ('') in the expanded variables to
|
||||
* PostgreSQL null
|
||||
*/
|
||||
for (p = values; *p; ++p) {
|
||||
if (*p == ',') {
|
||||
if (charCounter == 0) {
|
||||
nullCounter++;
|
||||
}
|
||||
charCounter=0;
|
||||
}
|
||||
else if (*p!=' ' && *p!='\'')
|
||||
{
|
||||
charCounter = 0;
|
||||
} else if (*p != ' ' && *p != '\'') {
|
||||
charCounter++;
|
||||
}
|
||||
}
|
||||
if (charCounter==0)
|
||||
{
|
||||
|
||||
if (charCounter == 0) {
|
||||
nullCounter++;
|
||||
}
|
||||
charCounter=0;
|
||||
nullCounter*=4;
|
||||
vlen+=nullCounter;
|
||||
nullValues=(char*)malloc(strlen(values)+nullCounter+1);
|
||||
charCounter=0;
|
||||
char *temp=nullValues;
|
||||
char *tp=nullValues;
|
||||
for (p=values; *p; ++tp,++p)
|
||||
{
|
||||
if (*p==',')
|
||||
{
|
||||
if (charCounter==0)
|
||||
{
|
||||
|
||||
nullCounter *= 4;
|
||||
vlen += nullCounter;
|
||||
switch_zmalloc(nullValues, strlen(values) + nullCounter + 1);
|
||||
charCounter = 0;
|
||||
temp = nullValues;
|
||||
tp = nullValues;
|
||||
|
||||
for (p = values; *p; ++tp, ++p) {
|
||||
if (*p == ',') {
|
||||
if (charCounter == 0) {
|
||||
temp++;
|
||||
*temp='n';temp++;
|
||||
if (temp==tp) tp++;
|
||||
*temp='u';temp++;
|
||||
if (temp==tp) tp++;
|
||||
*temp='l';temp++;
|
||||
if (temp==tp) tp++;
|
||||
*temp='l';temp++;
|
||||
while (temp!=tp)
|
||||
{
|
||||
*temp=' ';temp++;
|
||||
*temp = 'n';
|
||||
temp++;
|
||||
if (temp == tp) tp++;
|
||||
*temp = 'u';
|
||||
temp++;
|
||||
if (temp == tp) tp++;
|
||||
*temp = 'l';
|
||||
temp++;
|
||||
if (temp == tp) tp++;
|
||||
*temp = 'l';
|
||||
temp++;
|
||||
while (temp != tp) {
|
||||
*temp = ' ';
|
||||
temp++;
|
||||
}
|
||||
}
|
||||
charCounter=0;
|
||||
temp=tp;
|
||||
}
|
||||
else if (*p!=' ' && *p!='\'')
|
||||
{
|
||||
charCounter = 0;
|
||||
temp = tp;
|
||||
} else if (*p != ' ' && *p != '\'') {
|
||||
charCounter++;
|
||||
}
|
||||
*tp=*p;
|
||||
*tp = *p;
|
||||
}
|
||||
if (charCounter==0)
|
||||
{
|
||||
|
||||
if (charCounter == 0) {
|
||||
temp++;
|
||||
*temp='n';temp++;
|
||||
if (temp==tp) tp++;
|
||||
*temp='u';temp++;
|
||||
if (temp==tp) tp++;
|
||||
*temp='l';temp++;
|
||||
if (temp==tp) tp++;
|
||||
*temp='l';temp++;
|
||||
while (temp!=tp)
|
||||
{
|
||||
*temp=' ';temp++;
|
||||
*temp = 'n';
|
||||
temp++;
|
||||
if (temp == tp) tp++;
|
||||
*temp = 'u';
|
||||
temp++;
|
||||
if (temp == tp) tp++;
|
||||
*temp = 'l';
|
||||
temp++;
|
||||
if (temp == tp) tp++;
|
||||
*temp = 'l';
|
||||
temp++;
|
||||
while (temp != tp) {
|
||||
*temp = ' ';
|
||||
temp++;
|
||||
}
|
||||
}
|
||||
charCounter=0;
|
||||
temp=tp;
|
||||
*tp=0;
|
||||
tp=values;
|
||||
values=nullValues;
|
||||
free(tp);
|
||||
//-----------------------------END_OF_PATCH----------------------------------------------------------------
|
||||
query = malloc(strlen(query_template) - 6 + strlen(table) + clen + vlen + 1);
|
||||
sprintf(query, query_template, table, columns, values);
|
||||
free(columns);
|
||||
free(values);
|
||||
|
||||
charCounter = 0;
|
||||
temp = tp;
|
||||
*tp = 0;
|
||||
tp = values;
|
||||
values = nullValues;
|
||||
switch_safe_free(tp);
|
||||
|
||||
sql = switch_mprintf("INSERT INTO %s (%s) VALUES (%s);", globals.db_table, columns, values);
|
||||
assert(sql);
|
||||
switch_safe_free(columns);
|
||||
switch_safe_free(values);
|
||||
|
||||
if (globals.debug) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Query: \"%s\"\n", query);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Query: \"%s\"\n", sql);
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.db_mutex);
|
||||
@@ -337,66 +333,58 @@ static int save_cdr(const char* const table, const char* const template, const c
|
||||
if (!globals.db_online || PQstatus(globals.db_connection) != CONNECTION_OK) {
|
||||
globals.db_connection = PQconnectdb(globals.db_info);
|
||||
}
|
||||
|
||||
if (PQstatus(globals.db_connection) == CONNECTION_OK) {
|
||||
globals.db_online = 1;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Connection to database failed: %s", PQerrorMessage(globals.db_connection));
|
||||
PQfinish(globals.db_connection);
|
||||
globals.db_online = 0;
|
||||
switch_mutex_unlock(globals.db_mutex);
|
||||
free(query);
|
||||
return 0;
|
||||
goto error;
|
||||
}
|
||||
|
||||
res = PQexec(globals.db_connection, "BEGIN");
|
||||
res = PQexec(globals.db_connection, sql);
|
||||
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "BEGIN command failed: %s", PQerrorMessage(globals.db_connection));
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "INSERT command failed: %s", PQresultErrorMessage(res));
|
||||
PQclear(res);
|
||||
PQfinish(globals.db_connection);
|
||||
globals.db_online = 0;
|
||||
switch_mutex_unlock(globals.db_mutex);
|
||||
free(query);
|
||||
return 0;
|
||||
goto error;
|
||||
}
|
||||
PQclear(res);
|
||||
|
||||
res = PQexec(globals.db_connection, query);
|
||||
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "INSERT command failed: %s", PQerrorMessage(globals.db_connection));
|
||||
PQclear(res);
|
||||
PQfinish(globals.db_connection);
|
||||
globals.db_online = 0;
|
||||
switch_mutex_unlock(globals.db_mutex);
|
||||
free(query);
|
||||
return 0;
|
||||
}
|
||||
PQclear(res);
|
||||
|
||||
free(query);
|
||||
|
||||
res = PQexec(globals.db_connection, "END");
|
||||
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "END command failed: %s", PQerrorMessage(globals.db_connection));
|
||||
PQclear(res);
|
||||
PQfinish(globals.db_connection);
|
||||
globals.db_online = 0;
|
||||
switch_mutex_unlock(globals.db_mutex);
|
||||
return 0;
|
||||
}
|
||||
PQclear(res);
|
||||
switch_safe_free(sql);
|
||||
|
||||
switch_mutex_unlock(globals.db_mutex);
|
||||
|
||||
return 1;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
|
||||
error:
|
||||
|
||||
PQfinish(globals.db_connection);
|
||||
globals.db_online = 0;
|
||||
switch_mutex_unlock(globals.db_mutex);
|
||||
|
||||
/* SQL INSERT failed for whatever reason. Spool the attempted query to disk */
|
||||
if (!strcasecmp(globals.spool_format, "sql")) {
|
||||
path = switch_mprintf("%s%scdr-spool.sql", globals.log_dir, SWITCH_PATH_SEPARATOR);
|
||||
assert(path);
|
||||
spool_cdr(path, sql);
|
||||
} else {
|
||||
path = switch_mprintf("%s%scdr-spool.csv", globals.log_dir, SWITCH_PATH_SEPARATOR);
|
||||
assert(path);
|
||||
spool_cdr(path, cdr);
|
||||
}
|
||||
|
||||
switch_safe_free(path);
|
||||
switch_safe_free(sql);
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
static switch_status_t my_on_hangup(switch_core_session_t *session)
|
||||
static switch_status_t my_on_reporting(switch_core_session_t *session)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
const char *log_dir = NULL, *accountcode = NULL, *a_template_str = NULL, *g_template_str = NULL;
|
||||
char *log_line, *path = NULL;
|
||||
int saved = 0;
|
||||
const char *template_str = NULL;
|
||||
char *expanded_vars = NULL;
|
||||
|
||||
if (globals.shutdown) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
@@ -414,12 +402,8 @@ static switch_status_t my_on_hangup(switch_core_session_t *session)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(log_dir = switch_channel_get_variable(channel, "cdr_pg_csv_base"))) {
|
||||
log_dir = globals.log_dir;
|
||||
}
|
||||
|
||||
if (switch_dir_make_recursive(log_dir, SWITCH_DEFAULT_DIR_PERMS, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s\n", log_dir);
|
||||
if (switch_dir_make_recursive(globals.log_dir, SWITCH_DEFAULT_DIR_PERMS, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s\n", globals.log_dir);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
@@ -432,58 +416,27 @@ static switch_status_t my_on_hangup(switch_core_session_t *session)
|
||||
switch_assert(buf);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "CHANNEL_DATA:\n%s\n", buf);
|
||||
switch_event_destroy(&event);
|
||||
free(buf);
|
||||
switch_safe_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
g_template_str = (const char *) switch_core_hash_find(globals.template_hash, globals.default_template);
|
||||
template_str = (const char *) switch_core_hash_find(globals.template_hash, globals.default_template);
|
||||
|
||||
if ((accountcode = switch_channel_get_variable(channel, "ACCOUNTCODE"))) {
|
||||
a_template_str = (const char *) switch_core_hash_find(globals.template_hash, accountcode);
|
||||
if (!template_str) {
|
||||
template_str = default_template;
|
||||
}
|
||||
|
||||
if (!g_template_str) {
|
||||
g_template_str = "\"${accountcode}\",\"${caller_id_number}\",\"${destination_number}\",\"${context}\",\"${caller_id}\",\"${channel_name}\",\"${bridge_channel}\",\"${last_app}\",\"${last_arg}\",\"${start_stamp}\",\"${answer_stamp}\",\"${end_stamp}\",\"${duration}\",\"${billsec}\",\"${hangup_cause}\",\"${amaflags}\",\"${uuid}\",\"${userfield}\";";
|
||||
}
|
||||
expanded_vars = switch_channel_expand_variables(channel, template_str);
|
||||
|
||||
if (!a_template_str) {
|
||||
a_template_str = g_template_str;
|
||||
}
|
||||
|
||||
log_line = switch_channel_expand_variables(channel, a_template_str);
|
||||
|
||||
saved = 1; // save_cdr(globals.a_table, a_template_str, log_line);
|
||||
|
||||
if (!saved && accountcode) {
|
||||
path = switch_mprintf("%s%s%s.csv", log_dir, SWITCH_PATH_SEPARATOR, accountcode);
|
||||
assert(path);
|
||||
write_cdr(path, log_line);
|
||||
free(path);
|
||||
}
|
||||
|
||||
if (g_template_str != a_template_str) {
|
||||
if (log_line != a_template_str) {
|
||||
switch_safe_free(log_line);
|
||||
}
|
||||
log_line = switch_channel_expand_variables(channel, g_template_str);
|
||||
}
|
||||
|
||||
if (!log_line) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating cdr\n");
|
||||
if (!expanded_vars) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error expanding CDR variables.\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
saved = save_cdr(globals.g_table, g_template_str, log_line);
|
||||
insert_cdr(template_str, expanded_vars);
|
||||
|
||||
if (!saved) {
|
||||
path = switch_mprintf("%s%sMaster.csv", log_dir, SWITCH_PATH_SEPARATOR);
|
||||
assert(path);
|
||||
write_cdr(path, log_line);
|
||||
free(path);
|
||||
}
|
||||
|
||||
if (log_line != g_template_str) {
|
||||
free(log_line);
|
||||
if (expanded_vars != template_str) {
|
||||
switch_safe_free(expanded_vars);
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -513,7 +466,6 @@ static void event_handler(switch_event_t *event)
|
||||
PQfinish(globals.db_connection);
|
||||
globals.db_online = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,9 +474,14 @@ static switch_state_handler_table_t state_handlers = {
|
||||
/*.on_init */ NULL,
|
||||
/*.on_routing */ NULL,
|
||||
/*.on_execute */ NULL,
|
||||
/*.on_hangup */ my_on_hangup,
|
||||
/*.on_hangup */ NULL,
|
||||
/*.on_exchange_media */ NULL,
|
||||
/*.on_soft_execute */ NULL
|
||||
/*.on_soft_execute */ NULL,
|
||||
/*.on_consume_media */ NULL,
|
||||
/*.on_hibernate */ NULL,
|
||||
/*.on_reset */ NULL,
|
||||
/*.on_park */ NULL,
|
||||
/*.on_reporting */ my_on_reporting
|
||||
};
|
||||
|
||||
|
||||
@@ -574,14 +531,14 @@ static switch_status_t load_config(switch_memory_pool_t *pool)
|
||||
globals.log_dir = switch_core_sprintf(pool, "%s%scdr-pg-csv", val, SWITCH_PATH_SEPARATOR);
|
||||
} else if (!strcasecmp(var, "rotate-on-hup")) {
|
||||
globals.rotate = switch_true(val);
|
||||
} else if (!strcasecmp(var, "default-template")) {
|
||||
globals.default_template = switch_core_strdup(pool, val);
|
||||
} else if (!strcasecmp(var, "a-table")) {
|
||||
globals.a_table = switch_core_strdup(pool, val);
|
||||
} else if (!strcasecmp(var, "g-table")) {
|
||||
globals.g_table = switch_core_strdup(pool, val);
|
||||
} else if (!strcasecmp(var, "db-info")) {
|
||||
globals.db_info = switch_core_strdup(pool, val);
|
||||
} else if (!strcasecmp(var, "db-table") || !strcasecmp(var, "g-table")) {
|
||||
globals.db_table = switch_core_strdup(pool, val);
|
||||
} else if (!strcasecmp(var, "default-template")) {
|
||||
globals.default_template = switch_core_strdup(pool, val);
|
||||
} else if (!strcasecmp(var, "spool-format")) {
|
||||
globals.spool_format = switch_core_strdup(pool, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -591,13 +548,7 @@ static switch_status_t load_config(switch_memory_pool_t *pool)
|
||||
char *var = (char *) switch_xml_attr(param, "name");
|
||||
if (var) {
|
||||
char *tpl;
|
||||
size_t len = strlen(param->txt) + 2;
|
||||
if (end_of(param->txt) != '\n') {
|
||||
tpl = switch_core_alloc(pool, len);
|
||||
switch_snprintf(tpl, len, "%s\n", param->txt);
|
||||
} else {
|
||||
tpl = switch_core_strdup(pool, param->txt);
|
||||
}
|
||||
tpl = switch_core_strdup(pool, param->txt);
|
||||
|
||||
switch_core_hash_insert(globals.template_hash, var, tpl);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding template %s.\n", var);
|
||||
@@ -607,25 +558,24 @@ static switch_status_t load_config(switch_memory_pool_t *pool)
|
||||
switch_xml_free(xml);
|
||||
}
|
||||
|
||||
if (!globals.log_dir) {
|
||||
globals.log_dir = switch_core_sprintf(pool, "%s%scdr-pg-csv", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR);
|
||||
}
|
||||
|
||||
if (zstr(globals.db_info)) {
|
||||
globals.db_info = switch_core_strdup(pool, "dbname=cdr");
|
||||
}
|
||||
|
||||
if (zstr(globals.db_table)) {
|
||||
globals.db_table = switch_core_strdup(pool, "cdr");
|
||||
}
|
||||
|
||||
if (zstr(globals.default_template)) {
|
||||
globals.default_template = switch_core_strdup(pool, "default");
|
||||
}
|
||||
|
||||
if (!globals.log_dir) {
|
||||
globals.log_dir = switch_core_sprintf(pool, "%s%scdr-pg-csv", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR);
|
||||
}
|
||||
|
||||
if (zstr(globals.a_table)) {
|
||||
globals.a_table = switch_core_strdup(pool, "a");
|
||||
}
|
||||
|
||||
if (zstr(globals.g_table)) {
|
||||
globals.g_table = switch_core_strdup(pool, "g");
|
||||
}
|
||||
|
||||
if (zstr(globals.db_info)) {
|
||||
globals.db_info = switch_core_strdup(pool, "dbname = cdr");
|
||||
if (zstr(globals.spool_format)) {
|
||||
globals.spool_format = switch_core_strdup(pool, "csv");
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -636,19 +586,21 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_cdr_pg_csv_load)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
load_config(pool);
|
||||
|
||||
if ((status = switch_dir_make_recursive(globals.log_dir, SWITCH_DEFAULT_DIR_PERMS, pool)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s\n", globals.log_dir);
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((status = switch_event_bind(modname, SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, event_handler, NULL)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
return status;
|
||||
}
|
||||
|
||||
switch_core_add_state_handler(&state_handlers);
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
load_config(pool);
|
||||
|
||||
if ((status = switch_dir_make_recursive(globals.log_dir, SWITCH_DEFAULT_DIR_PERMS, pool)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s\n", globals.log_dir);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
include ../../../../build/modmake.rules
|
||||
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2010, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Daniel Swarbrick <daniel.swarbrick@seventhsignal.de>
|
||||
*
|
||||
* mod_cdr_sqlite.c -- SQLite CDR Module
|
||||
*
|
||||
* Derived from:
|
||||
* mod_cdr_csv.c -- Asterisk Compatible CDR Module
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
|
||||
typedef enum {
|
||||
CDR_LEG_A = (1 << 0),
|
||||
CDR_LEG_B = (1 << 1)
|
||||
} cdr_leg_t;
|
||||
|
||||
static char default_create_sql[] =
|
||||
"CREATE TABLE %s (\n"
|
||||
" caller_id_name VARCHAR,\n"
|
||||
" caller_id_number VARCHAR,\n"
|
||||
" destination_number VARCHAR,\n"
|
||||
" context VARCHAR,\n"
|
||||
" start_stamp DATETIME,\n"
|
||||
" answer_stamp DATETIME,\n"
|
||||
" end_stamp DATETIME,\n"
|
||||
" duration INTEGER,\n"
|
||||
" billsec INTEGER,\n"
|
||||
" hangup_cause VARCHAR,\n"
|
||||
" uuid VARCHAR,\n"
|
||||
" bleg_uuid VARCHAR,\n"
|
||||
" account_code VARCHAR\n"
|
||||
")\n";
|
||||
|
||||
const char *default_template =
|
||||
"\"${caller_id_name}\",\"${caller_id_number}\",\"${destination_number}\",\"${context}\","
|
||||
"\"${start_stamp}\",\"${answer_stamp}\",\"${end_stamp}\",${duration},${billsec},"
|
||||
"\"${hangup_cause}\",\"${uuid}\",\"${bleg_uuid}\",\"${accountcode}\"";
|
||||
|
||||
static struct {
|
||||
switch_memory_pool_t *pool;
|
||||
char *db_name;
|
||||
char *db_table;
|
||||
cdr_leg_t legs;
|
||||
int debug;
|
||||
switch_hash_t *template_hash;
|
||||
char *default_template;
|
||||
int shutdown;
|
||||
} globals;
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_cdr_sqlite_load);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_cdr_sqlite_shutdown);
|
||||
SWITCH_MODULE_DEFINITION(mod_cdr_sqlite, mod_cdr_sqlite_load, mod_cdr_sqlite_shutdown, NULL);
|
||||
|
||||
|
||||
switch_cache_db_handle_t *cdr_get_db_handle(void)
|
||||
{
|
||||
switch_cache_db_connection_options_t options = { {0} };
|
||||
switch_cache_db_handle_t *dbh = NULL;
|
||||
|
||||
options.core_db_options.db_path = globals.db_name;
|
||||
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_CORE_DB, &options) != SWITCH_STATUS_SUCCESS)
|
||||
dbh = NULL;
|
||||
return dbh;
|
||||
}
|
||||
|
||||
|
||||
static switch_status_t write_cdr(char *sql)
|
||||
{
|
||||
switch_cache_db_handle_t *dbh = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (!(dbh = cdr_get_db_handle())) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Writing SQL to DB: %s\n", sql);
|
||||
status = switch_cache_db_execute_sql(dbh, sql, NULL);
|
||||
|
||||
end:
|
||||
|
||||
switch_cache_db_release_db_handle(&dbh);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static switch_status_t my_on_reporting(switch_core_session_t *session)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
const char *template_str = NULL;
|
||||
char *expanded_vars = NULL, *sql = NULL;
|
||||
|
||||
if (globals.shutdown) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!((globals.legs & CDR_LEG_A) && (globals.legs & CDR_LEG_B))) {
|
||||
if ((globals.legs & CDR_LEG_A)) {
|
||||
if (switch_channel_get_originator_caller_profile(channel)) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
if (switch_channel_get_originatee_caller_profile(channel)) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (globals.debug) {
|
||||
switch_event_t *event;
|
||||
if (switch_event_create_plain(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) {
|
||||
char *buf;
|
||||
switch_channel_event_set_data(channel, event);
|
||||
switch_event_serialize(event, &buf, SWITCH_FALSE);
|
||||
switch_assert(buf);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "CHANNEL_DATA:\n%s\n", buf);
|
||||
switch_event_destroy(&event);
|
||||
switch_safe_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
template_str = (const char *) switch_core_hash_find(globals.template_hash, globals.default_template);
|
||||
|
||||
if (!template_str) {
|
||||
template_str = default_template;
|
||||
}
|
||||
|
||||
expanded_vars = switch_channel_expand_variables(channel, template_str);
|
||||
|
||||
if (!expanded_vars) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error expanding CDR variables.\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
sql = switch_mprintf("INSERT INTO %s VALUES (%s)", globals.db_table, expanded_vars);
|
||||
assert(sql);
|
||||
write_cdr(sql);
|
||||
switch_safe_free(sql);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static switch_state_handler_table_t state_handlers = {
|
||||
/*.on_init */ NULL,
|
||||
/*.on_routing */ NULL,
|
||||
/*.on_execute */ NULL,
|
||||
/*.on_hangup */ NULL,
|
||||
/*.on_exchange_media */ NULL,
|
||||
/*.on_soft_execute */ NULL,
|
||||
/*.on_consume_media */ NULL,
|
||||
/*.on_hibernate */ NULL,
|
||||
/*.on_reset */ NULL,
|
||||
/*.on_park */ NULL,
|
||||
/*.on_reporting */ my_on_reporting
|
||||
};
|
||||
|
||||
|
||||
static switch_status_t load_config(switch_memory_pool_t *pool)
|
||||
{
|
||||
char *cf = "cdr_sqlite.conf";
|
||||
switch_xml_t cfg, xml, settings, param;
|
||||
switch_cache_db_handle_t *dbh = NULL;
|
||||
char *select_sql = NULL, *create_sql = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
switch_core_hash_init(&globals.template_hash, pool);
|
||||
|
||||
globals.pool = pool;
|
||||
|
||||
switch_core_hash_insert(globals.template_hash, "default", default_template);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding default template.\n");
|
||||
globals.legs = CDR_LEG_A;
|
||||
|
||||
if ((xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
|
||||
|
||||
if ((settings = switch_xml_child(cfg, "settings"))) {
|
||||
for (param = switch_xml_child(settings, "param"); param; param = param->next) {
|
||||
char *var = (char *) switch_xml_attr_soft(param, "name");
|
||||
char *val = (char *) switch_xml_attr_soft(param, "value");
|
||||
if (!strcasecmp(var, "debug")) {
|
||||
globals.debug = switch_true(val);
|
||||
} else if (!strcasecmp(var, "db-name")) {
|
||||
globals.db_name = switch_core_strdup(pool, val);
|
||||
} else if (!strcasecmp(var, "db-table")) {
|
||||
globals.db_table = switch_core_strdup(pool, val);
|
||||
} else if (!strcasecmp(var, "legs")) {
|
||||
globals.legs = 0;
|
||||
|
||||
if (strchr(val, 'a')) {
|
||||
globals.legs |= CDR_LEG_A;
|
||||
}
|
||||
|
||||
if (strchr(val, 'b')) {
|
||||
globals.legs |= CDR_LEG_B;
|
||||
}
|
||||
} else if (!strcasecmp(var, "default-template")) {
|
||||
globals.default_template = switch_core_strdup(pool, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((settings = switch_xml_child(cfg, "templates"))) {
|
||||
for (param = switch_xml_child(settings, "template"); param; param = param->next) {
|
||||
char *var = (char *) switch_xml_attr(param, "name");
|
||||
if (var) {
|
||||
char *tpl;
|
||||
tpl = switch_core_strdup(pool, param->txt);
|
||||
|
||||
switch_core_hash_insert(globals.template_hash, var, tpl);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding template %s.\n", var);
|
||||
}
|
||||
}
|
||||
}
|
||||
switch_xml_free(xml);
|
||||
}
|
||||
|
||||
if (zstr(globals.db_name)) {
|
||||
globals.db_name = switch_core_strdup(pool, "cdr");
|
||||
}
|
||||
|
||||
if (zstr(globals.db_table)) {
|
||||
globals.db_table = switch_core_strdup(pool, "cdr");
|
||||
}
|
||||
|
||||
if (zstr(globals.default_template)) {
|
||||
globals.default_template = switch_core_strdup(pool, "default");
|
||||
}
|
||||
|
||||
dbh = cdr_get_db_handle();
|
||||
|
||||
if (dbh) {
|
||||
select_sql = switch_mprintf("SELECT * FROM %s LIMIT 1", globals.db_table);
|
||||
assert(select_sql);
|
||||
|
||||
create_sql = switch_mprintf(default_create_sql, globals.db_table);
|
||||
assert(create_sql);
|
||||
|
||||
/* Check if table exists (try SELECT FROM ...) and create table if query fails */
|
||||
switch_cache_db_test_reactive(dbh, select_sql, NULL, create_sql);
|
||||
switch_safe_free(select_sql);
|
||||
switch_safe_free(create_sql);
|
||||
|
||||
switch_cache_db_release_db_handle(&dbh);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_cdr_sqlite_load)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
load_config(pool);
|
||||
|
||||
switch_core_add_state_handler(&state_handlers);
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_cdr_sqlite_shutdown)
|
||||
{
|
||||
globals.shutdown = 1;
|
||||
switch_core_remove_state_handler(&state_handlers);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
|
||||
*/
|
||||
@@ -31,8 +31,8 @@
|
||||
*/
|
||||
#include <switch.h>
|
||||
#define CMD_BUFLEN 1024 * 1000
|
||||
#define MAX_QUEUE_LEN 5000
|
||||
#define MAX_MISSED 200
|
||||
#define MAX_QUEUE_LEN 25000
|
||||
#define MAX_MISSED 2000
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_event_socket_load);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_event_socket_shutdown);
|
||||
SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_socket_runtime);
|
||||
@@ -170,7 +170,7 @@ static switch_status_t socket_logger(const switch_log_node_t *node, switch_log_l
|
||||
if (switch_test_flag(l, LFLAG_LOG) && l->level >= node->level) {
|
||||
switch_log_node_t *dnode = switch_log_node_dup(node);
|
||||
|
||||
if (switch_queue_trypush(l->log_queue, dnode) == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_queue_push(l->log_queue, dnode) == SWITCH_STATUS_SUCCESS) {
|
||||
if (l->lost_logs) {
|
||||
int ll = l->lost_logs;
|
||||
switch_event_t *event;
|
||||
@@ -366,7 +366,7 @@ static void event_handler(switch_event_t *event)
|
||||
|
||||
if (send) {
|
||||
if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_queue_trypush(l->event_queue, clone) == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_queue_push(l->event_queue, clone) == SWITCH_STATUS_SUCCESS) {
|
||||
if (l->lost_events) {
|
||||
int le = l->lost_events;
|
||||
l->lost_events = 0;
|
||||
@@ -1233,7 +1233,7 @@ static switch_status_t read_packet(listener_t *listener, switch_event_t **event,
|
||||
if (switch_channel_get_state(chan) < CS_HANGUP && switch_channel_test_flag(chan, CF_DIVERT_EVENTS)) {
|
||||
switch_event_t *e = NULL;
|
||||
while (switch_core_session_dequeue_event(listener->session, &e, SWITCH_TRUE) == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_queue_trypush(listener->event_queue, e) != SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_queue_push(listener->event_queue, e) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_core_session_queue_event(listener->session, &e);
|
||||
break;
|
||||
}
|
||||
@@ -1452,7 +1452,7 @@ static switch_bool_t auth_api_command(listener_t *listener, const char *api_cmd,
|
||||
switch_bool_t ok = SWITCH_TRUE;
|
||||
|
||||
top:
|
||||
|
||||
|
||||
if (!switch_core_hash_find(listener->allowed_api_hash, check_cmd)) {
|
||||
ok = SWITCH_FALSE;
|
||||
goto end;
|
||||
@@ -1556,14 +1556,18 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t **even
|
||||
|
||||
user = cmd + 9;
|
||||
|
||||
if ((pass = strchr(user, ':'))) {
|
||||
*pass++ = '\0';
|
||||
}
|
||||
|
||||
if ((domain_name = strchr(user, '@'))) {
|
||||
*domain_name++ = '\0';
|
||||
}
|
||||
|
||||
if ((pass = strchr(domain_name, ':'))) {
|
||||
*pass++ = '\0';
|
||||
}
|
||||
|
||||
if ((pass = strchr(user, ':'))) {
|
||||
*pass++ = '\0';
|
||||
}
|
||||
|
||||
if (zstr(user) || zstr(domain_name)) {
|
||||
switch_snprintf(reply, reply_len, "-ERR invalid");
|
||||
switch_clear_flag_locked(listener, LFLAG_RUNNING);
|
||||
@@ -2044,21 +2048,31 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t **even
|
||||
char *arg = NULL;
|
||||
strip_cr(api_cmd);
|
||||
|
||||
if (!(acs.console_execute = switch_true(console_execute))) {
|
||||
if ((arg = strchr(api_cmd, ' '))) {
|
||||
*arg++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (listener->allowed_api_hash) {
|
||||
if (!auth_api_command(listener, api_cmd, arg)) {
|
||||
char *api_copy = strdup(api_cmd);
|
||||
char *arg_copy = NULL;
|
||||
int ok = 0;
|
||||
|
||||
if ((arg_copy = strchr(api_copy, ' '))) {
|
||||
*arg_copy++ = '\0';
|
||||
}
|
||||
|
||||
ok = auth_api_command(listener, api_copy, arg_copy);
|
||||
free(api_copy);
|
||||
|
||||
if (!ok) {
|
||||
switch_snprintf(reply, reply_len, "-ERR permission denied");
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!(acs.console_execute = switch_true(console_execute))) {
|
||||
if ((arg = strchr(api_cmd, ' '))) {
|
||||
*arg++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
acs.listener = listener;
|
||||
acs.api_cmd = api_cmd;
|
||||
acs.arg = arg;
|
||||
|
||||
@@ -116,6 +116,10 @@ public class CoreSession {
|
||||
return freeswitchJNI.CoreSession_voice_name_get(swigCPtr, this);
|
||||
}
|
||||
|
||||
public int insertFile(String file, String insert_file, int sample_point) {
|
||||
return freeswitchJNI.CoreSession_insertFile(swigCPtr, this, file, insert_file, sample_point);
|
||||
}
|
||||
|
||||
public int answer() {
|
||||
return freeswitchJNI.CoreSession_answer(swigCPtr, this);
|
||||
}
|
||||
|
||||
@@ -101,6 +101,7 @@ class freeswitchJNI {
|
||||
public final static native String CoreSession_tts_name_get(long jarg1, CoreSession jarg1_);
|
||||
public final static native void CoreSession_voice_name_set(long jarg1, CoreSession jarg1_, String jarg2);
|
||||
public final static native String CoreSession_voice_name_get(long jarg1, CoreSession jarg1_);
|
||||
public final static native int CoreSession_insertFile(long jarg1, CoreSession jarg1_, String jarg2, String jarg3, int jarg4);
|
||||
public final static native int CoreSession_answer(long jarg1, CoreSession jarg1_);
|
||||
public final static native int CoreSession_preAnswer(long jarg1, CoreSession jarg1_);
|
||||
public final static native void CoreSession_hangup(long jarg1, CoreSession jarg1_, String jarg2);
|
||||
|
||||
@@ -1866,6 +1866,37 @@ SWIGEXPORT jstring JNICALL Java_org_freeswitch_swig_freeswitchJNI_CoreSession_1v
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT jint JNICALL Java_org_freeswitch_swig_freeswitchJNI_CoreSession_1insertFile(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jstring jarg2, jstring jarg3, jint jarg4) {
|
||||
jint jresult = 0 ;
|
||||
CoreSession *arg1 = (CoreSession *) 0 ;
|
||||
char *arg2 = (char *) 0 ;
|
||||
char *arg3 = (char *) 0 ;
|
||||
int arg4 ;
|
||||
int result;
|
||||
|
||||
(void)jenv;
|
||||
(void)jcls;
|
||||
(void)jarg1_;
|
||||
arg1 = *(CoreSession **)&jarg1;
|
||||
arg2 = 0;
|
||||
if (jarg2) {
|
||||
arg2 = (char *)jenv->GetStringUTFChars(jarg2, 0);
|
||||
if (!arg2) return 0;
|
||||
}
|
||||
arg3 = 0;
|
||||
if (jarg3) {
|
||||
arg3 = (char *)jenv->GetStringUTFChars(jarg3, 0);
|
||||
if (!arg3) return 0;
|
||||
}
|
||||
arg4 = (int)jarg4;
|
||||
result = (int)(arg1)->insertFile((char const *)arg2,(char const *)arg3,arg4);
|
||||
jresult = (jint)result;
|
||||
if (arg2) jenv->ReleaseStringUTFChars(jarg2, (const char *)arg2);
|
||||
if (arg3) jenv->ReleaseStringUTFChars(jarg3, (const char *)arg3);
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT jint JNICALL Java_org_freeswitch_swig_freeswitchJNI_CoreSession_1answer(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_) {
|
||||
jint jresult = 0 ;
|
||||
CoreSession *arg1 = (CoreSession *) 0 ;
|
||||
|
||||
@@ -82,12 +82,13 @@ class Session : public CoreSession {
|
||||
class Dbh {
|
||||
private:
|
||||
switch_cache_db_handle_t *dbh;
|
||||
bool connected;
|
||||
bool m_connected;
|
||||
static int query_callback(void *pArg, int argc, char **argv, char **cargv);
|
||||
public:
|
||||
Dbh(char *dsn, char *user = NULL, char *pass = NULL);
|
||||
~Dbh();
|
||||
bool release();
|
||||
bool connected();
|
||||
bool query(char *sql, SWIGLUA_FN lua_fun);
|
||||
};
|
||||
|
||||
|
||||
@@ -318,9 +318,9 @@ Dbh::Dbh(char *dsn, char *user, char *pass)
|
||||
options.odbc_options.pass = pass;
|
||||
|
||||
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) == SWITCH_STATUS_SUCCESS) {
|
||||
connected = true;
|
||||
m_connected = true;
|
||||
} else {
|
||||
connected = false;
|
||||
m_connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,14 +331,19 @@ Dbh::~Dbh()
|
||||
|
||||
bool Dbh::release()
|
||||
{
|
||||
if (connected) {
|
||||
if (m_connected) {
|
||||
switch_cache_db_release_db_handle(&dbh);
|
||||
connected = false;
|
||||
m_connected = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Dbh::connected()
|
||||
{
|
||||
return m_connected;
|
||||
}
|
||||
|
||||
int Dbh::query_callback(void *pArg, int argc, char **argv, char **cargv)
|
||||
{
|
||||
SWIGLUA_FN *lua_fun = (SWIGLUA_FN *)pArg;
|
||||
@@ -366,7 +371,7 @@ int Dbh::query_callback(void *pArg, int argc, char **argv, char **cargv)
|
||||
|
||||
bool Dbh::query(char *sql, SWIGLUA_FN lua_fun)
|
||||
{
|
||||
if (connected) {
|
||||
if (m_connected) {
|
||||
if (lua_fun.L) {
|
||||
if (switch_cache_db_execute_sql_callback(dbh, sql, query_callback, &lua_fun, NULL) == SWITCH_STATUS_SUCCESS) {
|
||||
return true;
|
||||
|
||||
@@ -55,12 +55,13 @@ namespace LUA {
|
||||
class Dbh {
|
||||
protected:
|
||||
switch_cache_db_handle_t *dbh;
|
||||
bool connected;
|
||||
bool m_connected;
|
||||
static int query_callback(void *pArg, int argc, char **argv, char **cargv);
|
||||
public:
|
||||
Dbh(char *dsn, char *user = NULL, char *pass = NULL);
|
||||
~Dbh();
|
||||
bool release();
|
||||
bool connected();
|
||||
bool query(char *sql, SWIGLUA_FN lua_fun);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ SWITCH_STANDARD_API(lua_api_function)
|
||||
if (switch_event_get_header(stream->param_event, "http-host")) {
|
||||
stream->write_function(stream, "Content-Type: text/html\n\n<H2>Error Executing Script</H2>");
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR encounterd\n");
|
||||
stream->write_function(stream, "-ERR encountered\n");
|
||||
}
|
||||
}
|
||||
lua_uninit(L);
|
||||
|
||||
@@ -4287,6 +4287,40 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
static int _wrap_CoreSession_insertFile(lua_State* L) {
|
||||
int SWIG_arg = -1;
|
||||
CoreSession *arg1 = (CoreSession *) 0 ;
|
||||
char *arg2 = (char *) 0 ;
|
||||
char *arg3 = (char *) 0 ;
|
||||
int arg4 ;
|
||||
int result;
|
||||
|
||||
SWIG_check_num_args("insertFile",4,4)
|
||||
if(!SWIG_isptrtype(L,1)) SWIG_fail_arg("insertFile",1,"CoreSession *");
|
||||
if(!lua_isstring(L,2)) SWIG_fail_arg("insertFile",2,"char const *");
|
||||
if(!lua_isstring(L,3)) SWIG_fail_arg("insertFile",3,"char const *");
|
||||
if(!lua_isnumber(L,4)) SWIG_fail_arg("insertFile",4,"int");
|
||||
|
||||
if (!SWIG_IsOK(SWIG_ConvertPtr(L,1,(void**)&arg1,SWIGTYPE_p_CoreSession,0))){
|
||||
SWIG_fail_ptr("CoreSession_insertFile",1,SWIGTYPE_p_CoreSession);
|
||||
}
|
||||
|
||||
arg2 = (char *)lua_tostring(L, 2);
|
||||
arg3 = (char *)lua_tostring(L, 3);
|
||||
arg4 = (int)lua_tonumber(L, 4);
|
||||
result = (int)(arg1)->insertFile((char const *)arg2,(char const *)arg3,arg4);
|
||||
SWIG_arg=0;
|
||||
lua_pushnumber(L, (lua_Number) result); SWIG_arg++;
|
||||
return SWIG_arg;
|
||||
|
||||
if(0) SWIG_fail;
|
||||
|
||||
fail:
|
||||
lua_error(L);
|
||||
return SWIG_arg;
|
||||
}
|
||||
|
||||
|
||||
static int _wrap_CoreSession_answer(lua_State* L) {
|
||||
int SWIG_arg = -1;
|
||||
CoreSession *arg1 = (CoreSession *) 0 ;
|
||||
@@ -5864,6 +5898,7 @@ CoreSession *arg1 = (CoreSession *) obj;
|
||||
delete arg1;
|
||||
}
|
||||
static swig_lua_method swig_CoreSession_methods[] = {
|
||||
{"insertFile", _wrap_CoreSession_insertFile},
|
||||
{"answer", _wrap_CoreSession_answer},
|
||||
{"preAnswer", _wrap_CoreSession_preAnswer},
|
||||
{"hangup", _wrap_CoreSession_hangup},
|
||||
@@ -7194,6 +7229,31 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
static int _wrap_Dbh_connected(lua_State* L) {
|
||||
int SWIG_arg = -1;
|
||||
LUA::Dbh *arg1 = (LUA::Dbh *) 0 ;
|
||||
bool result;
|
||||
|
||||
SWIG_check_num_args("connected",1,1)
|
||||
if(!SWIG_isptrtype(L,1)) SWIG_fail_arg("connected",1,"LUA::Dbh *");
|
||||
|
||||
if (!SWIG_IsOK(SWIG_ConvertPtr(L,1,(void**)&arg1,SWIGTYPE_p_LUA__Dbh,0))){
|
||||
SWIG_fail_ptr("Dbh_connected",1,SWIGTYPE_p_LUA__Dbh);
|
||||
}
|
||||
|
||||
result = (bool)(arg1)->connected();
|
||||
SWIG_arg=0;
|
||||
lua_pushboolean(L,(int)(result==true)); SWIG_arg++;
|
||||
return SWIG_arg;
|
||||
|
||||
if(0) SWIG_fail;
|
||||
|
||||
fail:
|
||||
lua_error(L);
|
||||
return SWIG_arg;
|
||||
}
|
||||
|
||||
|
||||
static int _wrap_Dbh_query(lua_State* L) {
|
||||
int SWIG_arg = -1;
|
||||
LUA::Dbh *arg1 = (LUA::Dbh *) 0 ;
|
||||
@@ -7242,6 +7302,7 @@ delete arg1;
|
||||
}
|
||||
static swig_lua_method swig_LUA_Dbh_methods[] = {
|
||||
{"release", _wrap_Dbh_release},
|
||||
{"connected", _wrap_Dbh_connected},
|
||||
{"query", _wrap_Dbh_query},
|
||||
{0,0}
|
||||
};
|
||||
|
||||
@@ -6298,6 +6298,20 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_media_bug_remove_all(void * jarg1)
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_media_bug_enumerate(void * jarg1, void * jarg2) {
|
||||
int jresult ;
|
||||
switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
|
||||
switch_stream_handle_t *arg2 = (switch_stream_handle_t *) 0 ;
|
||||
switch_status_t result;
|
||||
|
||||
arg1 = (switch_core_session_t *)jarg1;
|
||||
arg2 = (switch_stream_handle_t *)jarg2;
|
||||
result = (switch_status_t)switch_core_media_bug_enumerate(arg1,arg2);
|
||||
jresult = result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_media_bug_read(void * jarg1, void * jarg2, int jarg3) {
|
||||
int jresult ;
|
||||
switch_media_bug_t *arg1 = (switch_media_bug_t *) 0 ;
|
||||
@@ -12406,13 +12420,15 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_is_number(char * jarg1) {
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT char * SWIGSTDCALL CSharp_switch_strip_spaces(char * jarg1) {
|
||||
SWIGEXPORT char * SWIGSTDCALL CSharp_switch_strip_spaces(char * jarg1, int jarg2) {
|
||||
char * jresult ;
|
||||
char *arg1 = (char *) 0 ;
|
||||
switch_bool_t arg2 ;
|
||||
char *result = 0 ;
|
||||
|
||||
arg1 = (char *)jarg1;
|
||||
result = (char *)switch_strip_spaces((char const *)arg1);
|
||||
arg2 = (switch_bool_t)jarg2;
|
||||
result = (char *)switch_strip_spaces(arg1,arg2);
|
||||
jresult = SWIG_csharp_string_callback((const char *)result);
|
||||
return jresult;
|
||||
}
|
||||
@@ -22969,6 +22985,16 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_set_caller_extension(void * ja
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_sort_cid(void * jarg1, int jarg2) {
|
||||
switch_channel_t *arg1 = (switch_channel_t *) 0 ;
|
||||
switch_bool_t arg2 ;
|
||||
|
||||
arg1 = (switch_channel_t *)jarg1;
|
||||
arg2 = (switch_bool_t)jarg2;
|
||||
switch_channel_sort_cid(arg1,arg2);
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT void * SWIGSTDCALL CSharp_switch_channel_get_caller_extension(void * jarg1) {
|
||||
void * jresult ;
|
||||
switch_channel_t *arg1 = (switch_channel_t *) 0 ;
|
||||
@@ -28290,15 +28316,47 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_rtcp(void * jarg1, int jar
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_jitter_buffer(void * jarg1, unsigned long jarg2) {
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_jitter_buffer(void * jarg1, unsigned long jarg2, unsigned long jarg3, unsigned long jarg4, unsigned long jarg5) {
|
||||
int jresult ;
|
||||
switch_rtp_t *arg1 = (switch_rtp_t *) 0 ;
|
||||
uint32_t arg2 ;
|
||||
uint32_t arg3 ;
|
||||
uint32_t arg4 ;
|
||||
uint32_t arg5 ;
|
||||
switch_status_t result;
|
||||
|
||||
arg1 = (switch_rtp_t *)jarg1;
|
||||
arg2 = (uint32_t)jarg2;
|
||||
result = (switch_status_t)switch_rtp_activate_jitter_buffer(arg1,arg2);
|
||||
arg3 = (uint32_t)jarg3;
|
||||
arg4 = (uint32_t)jarg4;
|
||||
arg5 = (uint32_t)jarg5;
|
||||
result = (switch_status_t)switch_rtp_activate_jitter_buffer(arg1,arg2,arg3,arg4,arg5);
|
||||
jresult = result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_debug_jitter_buffer(void * jarg1, char * jarg2) {
|
||||
int jresult ;
|
||||
switch_rtp_t *arg1 = (switch_rtp_t *) 0 ;
|
||||
char *arg2 = (char *) 0 ;
|
||||
switch_status_t result;
|
||||
|
||||
arg1 = (switch_rtp_t *)jarg1;
|
||||
arg2 = (char *)jarg2;
|
||||
result = (switch_status_t)switch_rtp_debug_jitter_buffer(arg1,(char const *)arg2);
|
||||
jresult = result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_deactivate_jitter_buffer(void * jarg1) {
|
||||
int jresult ;
|
||||
switch_rtp_t *arg1 = (switch_rtp_t *) 0 ;
|
||||
switch_status_t result;
|
||||
|
||||
arg1 = (switch_rtp_t *)jarg1;
|
||||
result = (switch_status_t)switch_rtp_deactivate_jitter_buffer(arg1);
|
||||
jresult = result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
@@ -6588,6 +6588,20 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_media_bug_remove_all(void * jarg1)
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_media_bug_enumerate(void * jarg1, void * jarg2) {
|
||||
int jresult ;
|
||||
switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
|
||||
switch_stream_handle_t *arg2 = (switch_stream_handle_t *) 0 ;
|
||||
switch_status_t result;
|
||||
|
||||
arg1 = (switch_core_session_t *)jarg1;
|
||||
arg2 = (switch_stream_handle_t *)jarg2;
|
||||
result = (switch_status_t)switch_core_media_bug_enumerate(arg1,arg2);
|
||||
jresult = result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_media_bug_read(void * jarg1, void * jarg2, int jarg3) {
|
||||
int jresult ;
|
||||
switch_media_bug_t *arg1 = (switch_media_bug_t *) 0 ;
|
||||
@@ -12726,13 +12740,15 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_is_number(char * jarg1) {
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT char * SWIGSTDCALL CSharp_switch_strip_spaces(char * jarg1) {
|
||||
SWIGEXPORT char * SWIGSTDCALL CSharp_switch_strip_spaces(char * jarg1, int jarg2) {
|
||||
char * jresult ;
|
||||
char *arg1 = (char *) 0 ;
|
||||
switch_bool_t arg2 ;
|
||||
char *result = 0 ;
|
||||
|
||||
arg1 = (char *)jarg1;
|
||||
result = (char *)switch_strip_spaces((char const *)arg1);
|
||||
arg2 = (switch_bool_t)jarg2;
|
||||
result = (char *)switch_strip_spaces(arg1,arg2);
|
||||
jresult = SWIG_csharp_string_callback((const char *)result);
|
||||
return jresult;
|
||||
}
|
||||
@@ -23624,6 +23640,16 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_set_caller_extension(void * ja
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_sort_cid(void * jarg1, int jarg2) {
|
||||
switch_channel_t *arg1 = (switch_channel_t *) 0 ;
|
||||
switch_bool_t arg2 ;
|
||||
|
||||
arg1 = (switch_channel_t *)jarg1;
|
||||
arg2 = (switch_bool_t)jarg2;
|
||||
switch_channel_sort_cid(arg1,arg2);
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT void * SWIGSTDCALL CSharp_switch_channel_get_caller_extension(void * jarg1) {
|
||||
void * jresult ;
|
||||
switch_channel_t *arg1 = (switch_channel_t *) 0 ;
|
||||
@@ -28993,15 +29019,47 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_rtcp(void * jarg1, int jar
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_jitter_buffer(void * jarg1, unsigned long jarg2) {
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_jitter_buffer(void * jarg1, unsigned long jarg2, unsigned long jarg3, unsigned long jarg4, unsigned long jarg5) {
|
||||
int jresult ;
|
||||
switch_rtp_t *arg1 = (switch_rtp_t *) 0 ;
|
||||
uint32_t arg2 ;
|
||||
uint32_t arg3 ;
|
||||
uint32_t arg4 ;
|
||||
uint32_t arg5 ;
|
||||
switch_status_t result;
|
||||
|
||||
arg1 = (switch_rtp_t *)jarg1;
|
||||
arg2 = (uint32_t)jarg2;
|
||||
result = (switch_status_t)switch_rtp_activate_jitter_buffer(arg1,arg2);
|
||||
arg3 = (uint32_t)jarg3;
|
||||
arg4 = (uint32_t)jarg4;
|
||||
arg5 = (uint32_t)jarg5;
|
||||
result = (switch_status_t)switch_rtp_activate_jitter_buffer(arg1,arg2,arg3,arg4,arg5);
|
||||
jresult = result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_debug_jitter_buffer(void * jarg1, char * jarg2) {
|
||||
int jresult ;
|
||||
switch_rtp_t *arg1 = (switch_rtp_t *) 0 ;
|
||||
char *arg2 = (char *) 0 ;
|
||||
switch_status_t result;
|
||||
|
||||
arg1 = (switch_rtp_t *)jarg1;
|
||||
arg2 = (char *)jarg2;
|
||||
result = (switch_status_t)switch_rtp_debug_jitter_buffer(arg1,(char const *)arg2);
|
||||
jresult = result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_deactivate_jitter_buffer(void * jarg1) {
|
||||
int jresult ;
|
||||
switch_rtp_t *arg1 = (switch_rtp_t *) 0 ;
|
||||
switch_status_t result;
|
||||
|
||||
arg1 = (switch_rtp_t *)jarg1;
|
||||
result = (switch_status_t)switch_rtp_deactivate_jitter_buffer(arg1);
|
||||
jresult = result;
|
||||
return jresult;
|
||||
}
|
||||
@@ -33979,6 +34037,24 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_CoreSession_voice_name_get(void * jarg1) {
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_CoreSession_insertFile(void * jarg1, char * jarg2, char * jarg3, int jarg4) {
|
||||
int jresult ;
|
||||
CoreSession *arg1 = (CoreSession *) 0 ;
|
||||
char *arg2 = (char *) 0 ;
|
||||
char *arg3 = (char *) 0 ;
|
||||
int arg4 ;
|
||||
int result;
|
||||
|
||||
arg1 = (CoreSession *)jarg1;
|
||||
arg2 = (char *)jarg2;
|
||||
arg3 = (char *)jarg3;
|
||||
arg4 = (int)jarg4;
|
||||
result = (int)(arg1)->insertFile((char const *)arg2,(char const *)arg3,arg4);
|
||||
jresult = result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_CoreSession_Answer(void * jarg1) {
|
||||
int jresult ;
|
||||
CoreSession *arg1 = (CoreSession *) 0 ;
|
||||
|
||||
@@ -1055,6 +1055,11 @@ public class freeswitch {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static switch_status_t switch_core_media_bug_enumerate(SWIGTYPE_p_switch_core_session session, switch_stream_handle stream) {
|
||||
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_media_bug_enumerate(SWIGTYPE_p_switch_core_session.getCPtr(session), switch_stream_handle.getCPtr(stream));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static switch_status_t switch_core_media_bug_read(SWIGTYPE_p_switch_media_bug bug, switch_frame frame, switch_bool_t fill) {
|
||||
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_media_bug_read(SWIGTYPE_p_switch_media_bug.getCPtr(bug), switch_frame.getCPtr(frame), (int)fill);
|
||||
return ret;
|
||||
@@ -2877,8 +2882,8 @@ public class freeswitch {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string switch_strip_spaces(string str) {
|
||||
string ret = freeswitchPINVOKE.switch_strip_spaces(str);
|
||||
public static string switch_strip_spaces(string str, switch_bool_t dup) {
|
||||
string ret = freeswitchPINVOKE.switch_strip_spaces(str, (int)dup);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3328,6 +3333,10 @@ public class freeswitch {
|
||||
freeswitchPINVOKE.switch_channel_set_caller_extension(SWIGTYPE_p_switch_channel.getCPtr(channel), switch_caller_extension.getCPtr(caller_extension));
|
||||
}
|
||||
|
||||
public static void switch_channel_sort_cid(SWIGTYPE_p_switch_channel channel, switch_bool_t arg1) {
|
||||
freeswitchPINVOKE.switch_channel_sort_cid(SWIGTYPE_p_switch_channel.getCPtr(channel), (int)arg1);
|
||||
}
|
||||
|
||||
public static switch_caller_extension switch_channel_get_caller_extension(SWIGTYPE_p_switch_channel channel) {
|
||||
IntPtr cPtr = freeswitchPINVOKE.switch_channel_get_caller_extension(SWIGTYPE_p_switch_channel.getCPtr(channel));
|
||||
switch_caller_extension ret = (cPtr == IntPtr.Zero) ? null : new switch_caller_extension(cPtr, false);
|
||||
@@ -4640,8 +4649,18 @@ public class freeswitch {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static switch_status_t switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session, uint queue_frames) {
|
||||
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), queue_frames);
|
||||
public static switch_status_t switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session, uint queue_frames, uint max_queue_frames, uint samples_per_packet, uint samples_per_second) {
|
||||
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), queue_frames, max_queue_frames, samples_per_packet, samples_per_second);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static switch_status_t switch_rtp_debug_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session, string name) {
|
||||
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_debug_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static switch_status_t switch_rtp_deactivate_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session) {
|
||||
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_deactivate_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -7269,6 +7288,9 @@ class freeswitchPINVOKE {
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_media_bug_remove_all")]
|
||||
public static extern int switch_core_media_bug_remove_all(HandleRef jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_media_bug_enumerate")]
|
||||
public static extern int switch_core_media_bug_enumerate(HandleRef jarg1, HandleRef jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_media_bug_read")]
|
||||
public static extern int switch_core_media_bug_read(HandleRef jarg1, HandleRef jarg2, int jarg3);
|
||||
|
||||
@@ -8656,7 +8678,7 @@ class freeswitchPINVOKE {
|
||||
public static extern int switch_is_number(string jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_strip_spaces")]
|
||||
public static extern string switch_strip_spaces(string jarg1);
|
||||
public static extern string switch_strip_spaces(string jarg1, int jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_strip_whitespace")]
|
||||
public static extern string switch_strip_whitespace(string jarg1);
|
||||
@@ -11322,6 +11344,9 @@ class freeswitchPINVOKE {
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_set_caller_extension")]
|
||||
public static extern void switch_channel_set_caller_extension(HandleRef jarg1, HandleRef jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_sort_cid")]
|
||||
public static extern void switch_channel_sort_cid(HandleRef jarg1, int jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_get_caller_extension")]
|
||||
public static extern IntPtr switch_channel_get_caller_extension(HandleRef jarg1);
|
||||
|
||||
@@ -12448,7 +12473,13 @@ class freeswitchPINVOKE {
|
||||
public static extern int switch_rtp_activate_rtcp(HandleRef jarg1, int jarg2, ushort jarg3);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_activate_jitter_buffer")]
|
||||
public static extern int switch_rtp_activate_jitter_buffer(HandleRef jarg1, uint jarg2);
|
||||
public static extern int switch_rtp_activate_jitter_buffer(HandleRef jarg1, uint jarg2, uint jarg3, uint jarg4, uint jarg5);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_debug_jitter_buffer")]
|
||||
public static extern int switch_rtp_debug_jitter_buffer(HandleRef jarg1, string jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_deactivate_jitter_buffer")]
|
||||
public static extern int switch_rtp_deactivate_jitter_buffer(HandleRef jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_set_flag")]
|
||||
public static extern void switch_rtp_set_flag(HandleRef jarg1, uint jarg2);
|
||||
@@ -21554,6 +21585,10 @@ public enum switch_channel_flag_t {
|
||||
CF_PASSTHRU_PTIME_MISMATCH,
|
||||
CF_BRIDGE_NOWRITE,
|
||||
CF_RECOVERED,
|
||||
CF_JITTERBUFFER,
|
||||
CF_DIALPLAN,
|
||||
CF_BLOCK_BROADCAST_UNTIL_MEDIA,
|
||||
CF_CNG_PLC,
|
||||
CF_FLAG_MAX
|
||||
}
|
||||
|
||||
@@ -23243,6 +23278,8 @@ public enum switch_core_session_message_types_t {
|
||||
SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION,
|
||||
SWITCH_MESSAGE_INDICATE_UDPTL_MODE,
|
||||
SWITCH_MESSAGE_INDICATE_CLEAR_PROGRESS,
|
||||
SWITCH_MESSAGE_INDICATE_JITTER_BUFFER,
|
||||
SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH,
|
||||
SWITCH_MESSAGE_INVALID
|
||||
}
|
||||
|
||||
|
||||
@@ -220,6 +220,11 @@ public class CoreSession : IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
public int insertFile(string file, string insert_file, int sample_point) {
|
||||
int ret = freeswitchPINVOKE.CoreSession_insertFile(swigCPtr, file, insert_file, sample_point);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int Answer() {
|
||||
int ret = freeswitchPINVOKE.CoreSession_Answer(swigCPtr);
|
||||
return ret;
|
||||
@@ -1045,6 +1050,11 @@ public class freeswitch {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static switch_status_t switch_core_media_bug_enumerate(SWIGTYPE_p_switch_core_session session, switch_stream_handle stream) {
|
||||
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_media_bug_enumerate(SWIGTYPE_p_switch_core_session.getCPtr(session), switch_stream_handle.getCPtr(stream));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static switch_status_t switch_core_media_bug_read(SWIGTYPE_p_switch_media_bug bug, switch_frame frame, switch_bool_t fill) {
|
||||
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_media_bug_read(SWIGTYPE_p_switch_media_bug.getCPtr(bug), switch_frame.getCPtr(frame), (int)fill);
|
||||
return ret;
|
||||
@@ -2867,8 +2877,8 @@ public class freeswitch {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string switch_strip_spaces(string str) {
|
||||
string ret = freeswitchPINVOKE.switch_strip_spaces(str);
|
||||
public static string switch_strip_spaces(string str, switch_bool_t dup) {
|
||||
string ret = freeswitchPINVOKE.switch_strip_spaces(str, (int)dup);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3318,6 +3328,10 @@ public class freeswitch {
|
||||
freeswitchPINVOKE.switch_channel_set_caller_extension(SWIGTYPE_p_switch_channel.getCPtr(channel), switch_caller_extension.getCPtr(caller_extension));
|
||||
}
|
||||
|
||||
public static void switch_channel_sort_cid(SWIGTYPE_p_switch_channel channel, switch_bool_t arg1) {
|
||||
freeswitchPINVOKE.switch_channel_sort_cid(SWIGTYPE_p_switch_channel.getCPtr(channel), (int)arg1);
|
||||
}
|
||||
|
||||
public static switch_caller_extension switch_channel_get_caller_extension(SWIGTYPE_p_switch_channel channel) {
|
||||
IntPtr cPtr = freeswitchPINVOKE.switch_channel_get_caller_extension(SWIGTYPE_p_switch_channel.getCPtr(channel));
|
||||
switch_caller_extension ret = (cPtr == IntPtr.Zero) ? null : new switch_caller_extension(cPtr, false);
|
||||
@@ -4630,8 +4644,18 @@ public class freeswitch {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static switch_status_t switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session, uint queue_frames) {
|
||||
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), queue_frames);
|
||||
public static switch_status_t switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session, uint queue_frames, uint max_queue_frames, uint samples_per_packet, uint samples_per_second) {
|
||||
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), queue_frames, max_queue_frames, samples_per_packet, samples_per_second);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static switch_status_t switch_rtp_debug_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session, string name) {
|
||||
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_debug_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static switch_status_t switch_rtp_deactivate_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session) {
|
||||
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_deactivate_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -7255,6 +7279,9 @@ class freeswitchPINVOKE {
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_media_bug_remove_all")]
|
||||
public static extern int switch_core_media_bug_remove_all(HandleRef jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_media_bug_enumerate")]
|
||||
public static extern int switch_core_media_bug_enumerate(HandleRef jarg1, HandleRef jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_media_bug_read")]
|
||||
public static extern int switch_core_media_bug_read(HandleRef jarg1, HandleRef jarg2, int jarg3);
|
||||
|
||||
@@ -8642,7 +8669,7 @@ class freeswitchPINVOKE {
|
||||
public static extern int switch_is_number(string jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_strip_spaces")]
|
||||
public static extern string switch_strip_spaces(string jarg1);
|
||||
public static extern string switch_strip_spaces(string jarg1, int jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_strip_whitespace")]
|
||||
public static extern string switch_strip_whitespace(string jarg1);
|
||||
@@ -11308,6 +11335,9 @@ class freeswitchPINVOKE {
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_set_caller_extension")]
|
||||
public static extern void switch_channel_set_caller_extension(HandleRef jarg1, HandleRef jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_sort_cid")]
|
||||
public static extern void switch_channel_sort_cid(HandleRef jarg1, int jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_get_caller_extension")]
|
||||
public static extern IntPtr switch_channel_get_caller_extension(HandleRef jarg1);
|
||||
|
||||
@@ -12434,7 +12464,13 @@ class freeswitchPINVOKE {
|
||||
public static extern int switch_rtp_activate_rtcp(HandleRef jarg1, int jarg2, ushort jarg3);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_activate_jitter_buffer")]
|
||||
public static extern int switch_rtp_activate_jitter_buffer(HandleRef jarg1, uint jarg2);
|
||||
public static extern int switch_rtp_activate_jitter_buffer(HandleRef jarg1, uint jarg2, uint jarg3, uint jarg4, uint jarg5);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_debug_jitter_buffer")]
|
||||
public static extern int switch_rtp_debug_jitter_buffer(HandleRef jarg1, string jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_deactivate_jitter_buffer")]
|
||||
public static extern int switch_rtp_deactivate_jitter_buffer(HandleRef jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_set_flag")]
|
||||
public static extern void switch_rtp_set_flag(HandleRef jarg1, uint jarg2);
|
||||
@@ -13627,6 +13663,9 @@ class freeswitchPINVOKE {
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_CoreSession_voice_name_get")]
|
||||
public static extern string CoreSession_voice_name_get(HandleRef jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_CoreSession_insertFile")]
|
||||
public static extern int CoreSession_insertFile(HandleRef jarg1, string jarg2, string jarg3, int jarg4);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_CoreSession_Answer")]
|
||||
public static extern int CoreSession_Answer(HandleRef jarg1);
|
||||
|
||||
@@ -21500,6 +21539,10 @@ public enum switch_channel_flag_t {
|
||||
CF_PASSTHRU_PTIME_MISMATCH,
|
||||
CF_BRIDGE_NOWRITE,
|
||||
CF_RECOVERED,
|
||||
CF_JITTERBUFFER,
|
||||
CF_DIALPLAN,
|
||||
CF_BLOCK_BROADCAST_UNTIL_MEDIA,
|
||||
CF_CNG_PLC,
|
||||
CF_FLAG_MAX
|
||||
}
|
||||
|
||||
@@ -23167,6 +23210,8 @@ public enum switch_core_session_message_types_t {
|
||||
SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION,
|
||||
SWITCH_MESSAGE_INDICATE_UDPTL_MODE,
|
||||
SWITCH_MESSAGE_INDICATE_CLEAR_PROGRESS,
|
||||
SWITCH_MESSAGE_INDICATE_JITTER_BUFFER,
|
||||
SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH,
|
||||
SWITCH_MESSAGE_INVALID
|
||||
}
|
||||
|
||||
|
||||
@@ -404,6 +404,7 @@ sub DESTROY {
|
||||
*swig_tts_name_set = *freeswitchc::CoreSession_tts_name_set;
|
||||
*swig_voice_name_get = *freeswitchc::CoreSession_voice_name_get;
|
||||
*swig_voice_name_set = *freeswitchc::CoreSession_voice_name_set;
|
||||
*insertFile = *freeswitchc::CoreSession_insertFile;
|
||||
*answer = *freeswitchc::CoreSession_answer;
|
||||
*preAnswer = *freeswitchc::CoreSession_preAnswer;
|
||||
*hangup = *freeswitchc::CoreSession_hangup;
|
||||
|
||||
@@ -5282,6 +5282,66 @@ XS(_wrap_CoreSession_voice_name_get) {
|
||||
}
|
||||
|
||||
|
||||
XS(_wrap_CoreSession_insertFile) {
|
||||
{
|
||||
CoreSession *arg1 = (CoreSession *) 0 ;
|
||||
char *arg2 = (char *) 0 ;
|
||||
char *arg3 = (char *) 0 ;
|
||||
int arg4 ;
|
||||
int result;
|
||||
void *argp1 = 0 ;
|
||||
int res1 = 0 ;
|
||||
int res2 ;
|
||||
char *buf2 = 0 ;
|
||||
int alloc2 = 0 ;
|
||||
int res3 ;
|
||||
char *buf3 = 0 ;
|
||||
int alloc3 = 0 ;
|
||||
int val4 ;
|
||||
int ecode4 = 0 ;
|
||||
int argvi = 0;
|
||||
dXSARGS;
|
||||
|
||||
if ((items < 4) || (items > 4)) {
|
||||
SWIG_croak("Usage: CoreSession_insertFile(self,file,insert_file,sample_point);");
|
||||
}
|
||||
res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_CoreSession, 0 | 0 );
|
||||
if (!SWIG_IsOK(res1)) {
|
||||
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "CoreSession_insertFile" "', argument " "1"" of type '" "CoreSession *""'");
|
||||
}
|
||||
arg1 = reinterpret_cast< CoreSession * >(argp1);
|
||||
res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
|
||||
if (!SWIG_IsOK(res2)) {
|
||||
SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "CoreSession_insertFile" "', argument " "2"" of type '" "char const *""'");
|
||||
}
|
||||
arg2 = reinterpret_cast< char * >(buf2);
|
||||
res3 = SWIG_AsCharPtrAndSize(ST(2), &buf3, NULL, &alloc3);
|
||||
if (!SWIG_IsOK(res3)) {
|
||||
SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "CoreSession_insertFile" "', argument " "3"" of type '" "char const *""'");
|
||||
}
|
||||
arg3 = reinterpret_cast< char * >(buf3);
|
||||
ecode4 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
|
||||
if (!SWIG_IsOK(ecode4)) {
|
||||
SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "CoreSession_insertFile" "', argument " "4"" of type '" "int""'");
|
||||
}
|
||||
arg4 = static_cast< int >(val4);
|
||||
result = (int)(arg1)->insertFile((char const *)arg2,(char const *)arg3,arg4);
|
||||
ST(argvi) = SWIG_From_int SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
|
||||
|
||||
if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
|
||||
if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
|
||||
|
||||
XSRETURN(argvi);
|
||||
fail:
|
||||
|
||||
if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
|
||||
if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
|
||||
|
||||
SWIG_croak_null();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
XS(_wrap_CoreSession_answer) {
|
||||
{
|
||||
CoreSession *arg1 = (CoreSession *) 0 ;
|
||||
@@ -9361,6 +9421,7 @@ static swig_command_info swig_commands[] = {
|
||||
{"freeswitchc::CoreSession_tts_name_get", _wrap_CoreSession_tts_name_get},
|
||||
{"freeswitchc::CoreSession_voice_name_set", _wrap_CoreSession_voice_name_set},
|
||||
{"freeswitchc::CoreSession_voice_name_get", _wrap_CoreSession_voice_name_get},
|
||||
{"freeswitchc::CoreSession_insertFile", _wrap_CoreSession_insertFile},
|
||||
{"freeswitchc::CoreSession_answer", _wrap_CoreSession_answer},
|
||||
{"freeswitchc::CoreSession_preAnswer", _wrap_CoreSession_preAnswer},
|
||||
{"freeswitchc::CoreSession_hangup", _wrap_CoreSession_hangup},
|
||||
|
||||
@@ -263,6 +263,7 @@ class CoreSession(_object):
|
||||
__swig_setmethods__["voice_name"] = _freeswitch.CoreSession_voice_name_set
|
||||
__swig_getmethods__["voice_name"] = _freeswitch.CoreSession_voice_name_get
|
||||
if _newclass:voice_name = _swig_property(_freeswitch.CoreSession_voice_name_get, _freeswitch.CoreSession_voice_name_set)
|
||||
def insertFile(*args): return _freeswitch.CoreSession_insertFile(*args)
|
||||
def answer(*args): return _freeswitch.CoreSession_answer(*args)
|
||||
def preAnswer(*args): return _freeswitch.CoreSession_preAnswer(*args)
|
||||
def hangup(*args): return _freeswitch.CoreSession_hangup(*args)
|
||||
|
||||
@@ -5892,6 +5892,61 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
SWIGINTERN PyObject *_wrap_CoreSession_insertFile(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
|
||||
PyObject *resultobj = 0;
|
||||
CoreSession *arg1 = (CoreSession *) 0 ;
|
||||
char *arg2 = (char *) 0 ;
|
||||
char *arg3 = (char *) 0 ;
|
||||
int arg4 ;
|
||||
int result;
|
||||
void *argp1 = 0 ;
|
||||
int res1 = 0 ;
|
||||
int res2 ;
|
||||
char *buf2 = 0 ;
|
||||
int alloc2 = 0 ;
|
||||
int res3 ;
|
||||
char *buf3 = 0 ;
|
||||
int alloc3 = 0 ;
|
||||
int val4 ;
|
||||
int ecode4 = 0 ;
|
||||
PyObject * obj0 = 0 ;
|
||||
PyObject * obj1 = 0 ;
|
||||
PyObject * obj2 = 0 ;
|
||||
PyObject * obj3 = 0 ;
|
||||
|
||||
if (!PyArg_ParseTuple(args,(char *)"OOOO:CoreSession_insertFile",&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
|
||||
res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_CoreSession, 0 | 0 );
|
||||
if (!SWIG_IsOK(res1)) {
|
||||
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "CoreSession_insertFile" "', argument " "1"" of type '" "CoreSession *""'");
|
||||
}
|
||||
arg1 = reinterpret_cast< CoreSession * >(argp1);
|
||||
res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
|
||||
if (!SWIG_IsOK(res2)) {
|
||||
SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "CoreSession_insertFile" "', argument " "2"" of type '" "char const *""'");
|
||||
}
|
||||
arg2 = reinterpret_cast< char * >(buf2);
|
||||
res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
|
||||
if (!SWIG_IsOK(res3)) {
|
||||
SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "CoreSession_insertFile" "', argument " "3"" of type '" "char const *""'");
|
||||
}
|
||||
arg3 = reinterpret_cast< char * >(buf3);
|
||||
ecode4 = SWIG_AsVal_int(obj3, &val4);
|
||||
if (!SWIG_IsOK(ecode4)) {
|
||||
SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "CoreSession_insertFile" "', argument " "4"" of type '" "int""'");
|
||||
}
|
||||
arg4 = static_cast< int >(val4);
|
||||
result = (int)(arg1)->insertFile((char const *)arg2,(char const *)arg3,arg4);
|
||||
resultobj = SWIG_From_int(static_cast< int >(result));
|
||||
if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
|
||||
if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
|
||||
return resultobj;
|
||||
fail:
|
||||
if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
|
||||
if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
SWIGINTERN PyObject *_wrap_CoreSession_answer(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
|
||||
PyObject *resultobj = 0;
|
||||
CoreSession *arg1 = (CoreSession *) 0 ;
|
||||
@@ -8915,6 +8970,7 @@ static PyMethodDef SwigMethods[] = {
|
||||
{ (char *)"CoreSession_tts_name_get", _wrap_CoreSession_tts_name_get, METH_VARARGS, NULL},
|
||||
{ (char *)"CoreSession_voice_name_set", _wrap_CoreSession_voice_name_set, METH_VARARGS, NULL},
|
||||
{ (char *)"CoreSession_voice_name_get", _wrap_CoreSession_voice_name_get, METH_VARARGS, NULL},
|
||||
{ (char *)"CoreSession_insertFile", _wrap_CoreSession_insertFile, METH_VARARGS, NULL},
|
||||
{ (char *)"CoreSession_answer", _wrap_CoreSession_answer, METH_VARARGS, NULL},
|
||||
{ (char *)"CoreSession_preAnswer", _wrap_CoreSession_preAnswer, METH_VARARGS, NULL},
|
||||
{ (char *)"CoreSession_hangup", _wrap_CoreSession_hangup, METH_VARARGS, NULL},
|
||||
|
||||
@@ -39,8 +39,9 @@
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Michael B. Murdock <mike@mmurdock.org>
|
||||
* François Delawarde <fdelawarde@wirelessmundi.com>
|
||||
*
|
||||
* mod_say_es.c -- Say for English
|
||||
* mod_say_es.c -- Say for Spanish
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -102,7 +103,7 @@ static switch_status_t play_group(switch_say_method_t method, int a, int b, int
|
||||
break;
|
||||
default:
|
||||
say_file("digits/%d.wav", a);
|
||||
say_file("digits/hundred.wav");
|
||||
say_file("digits/hundreds.wav");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -175,7 +176,12 @@ static switch_status_t es_say_general_count(switch_core_session_t *session, char
|
||||
switch (say_args->method) {
|
||||
case SSM_COUNTED:
|
||||
case SSM_PRONOUNCED:
|
||||
if ((status = play_group(SSM_PRONOUNCED, places[8], places[7], places[6], "digits/million.wav", session, args)) != SWITCH_STATUS_SUCCESS) {
|
||||
/* specific case, one million => un millón */
|
||||
if (!places[8] && !places[7] && (places[6] == 1)) {
|
||||
say_file("digits/un.wav");
|
||||
say_file("digits/million.wav");
|
||||
}
|
||||
else if ((status = play_group(SSM_PRONOUNCED, places[8], places[7], places[6], "digits/millions.wav", session, args)) != SWITCH_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
if ((status = play_group(SSM_PRONOUNCED, places[5], places[4], places[3], "digits/thousand.wav", session, args)) != SWITCH_STATUS_SUCCESS) {
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
BASE=../../../..
|
||||
include $(BASE)/build/modmake.rules
|
||||
@@ -0,0 +1,283 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="mod_say_pt"
|
||||
ProjectGUID="{7C22BDFF-CC09-400C-8A09-660733980028}"
|
||||
RootNamespace="mod_say_pt"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
<Platform
|
||||
Name="x64"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|x64"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|x64"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\mod_say_pt.c"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,131 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>mod_say_pt</ProjectName>
|
||||
<ProjectGuid>{7C22BDFF-CC09-400C-8A09-660733980028}</ProjectGuid>
|
||||
<RootNamespace>mod_say_pt</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_debug.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_debug.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mod_say_pt.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\w32\Library\FreeSwitchCore.2010.vcxproj">
|
||||
<Project>{202d7a4e-760d-4d0e-afa1-d7459ced30ff}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,548 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Michael B. Murdock <mike@mmurdock.org>
|
||||
* António Silva <asilva@wirelessmundi.com>
|
||||
*
|
||||
* mod_say_pt.c -- Say for Portuguese
|
||||
*
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_say_pt_load);
|
||||
SWITCH_MODULE_DEFINITION(mod_say_pt, mod_say_pt_load, NULL, NULL);
|
||||
|
||||
#define say_num(num, meth) { \
|
||||
char tmp[80]; \
|
||||
switch_status_t tstatus; \
|
||||
switch_say_method_t smeth = say_args->method; \
|
||||
switch_say_type_t stype = say_args->type; \
|
||||
say_args->type = SST_ITEMS; say_args->method = meth; \
|
||||
switch_snprintf(tmp, sizeof(tmp), "%u", (unsigned)num); \
|
||||
if ((tstatus = \
|
||||
pt_say_general_count(session, tmp, say_args, args)) \
|
||||
!= SWITCH_STATUS_SUCCESS) { \
|
||||
return tstatus; \
|
||||
} \
|
||||
say_args->method = smeth; say_args->type = stype; \
|
||||
} \
|
||||
|
||||
|
||||
#define say_file(...) { \
|
||||
char tmp[80]; \
|
||||
switch_status_t tstatus; \
|
||||
switch_snprintf(tmp, sizeof(tmp), __VA_ARGS__); \
|
||||
if ((tstatus = \
|
||||
switch_ivr_play_file(session, NULL, tmp, args)) \
|
||||
!= SWITCH_STATUS_SUCCESS){ \
|
||||
return tstatus; \
|
||||
} \
|
||||
if (!switch_channel_ready(switch_core_session_get_channel(session))) { \
|
||||
return SWITCH_STATUS_FALSE; \
|
||||
}} \
|
||||
|
||||
|
||||
static switch_status_t play_group(switch_say_method_t method, int a, int b, int c, char *what, switch_core_session_t *session, switch_input_args_t *args)
|
||||
{
|
||||
|
||||
/*a => 1xx-9xx*/
|
||||
if (a) {
|
||||
switch (a) {
|
||||
case 1:
|
||||
if (b || c) {
|
||||
say_file("digits/hundred.wav");
|
||||
} else {
|
||||
say_file("digits/100.wav");
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
say_file("digits/200.wav");
|
||||
break;
|
||||
case 3:
|
||||
say_file("digits/300.wav");
|
||||
break;
|
||||
case 5:
|
||||
say_file("digits/500.wav");
|
||||
break;
|
||||
default:
|
||||
say_file("digits/%d.wav", a);
|
||||
say_file("digits/hundreds.wav");
|
||||
break;
|
||||
}
|
||||
if (b || c) {
|
||||
say_file("currency/and.wav");
|
||||
}
|
||||
}
|
||||
/* b => 1x - 9x */
|
||||
if (b) {
|
||||
if (b > 1) {
|
||||
if (method == SSM_COUNTED) {
|
||||
say_file("digits/h-%d0.wav", b);
|
||||
} else {
|
||||
say_file("digits/%d0.wav", b);
|
||||
if (c > 0) {
|
||||
say_file("currency/and.wav");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
say_file("digits/%d%d.wav", b, c);
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
/* c => 0 - 9*/
|
||||
if (c) {
|
||||
if (method == SSM_COUNTED) {
|
||||
say_file("digits/h-%d.wav", c);
|
||||
} else {
|
||||
say_file("digits/%d.wav", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (what && (a || b || c)) {
|
||||
say_file(what);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t pt_say_general_count(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
|
||||
{
|
||||
int in;
|
||||
int x = 0;
|
||||
int places[9] = { 0 };
|
||||
char sbuf[128] = "";
|
||||
switch_status_t status;
|
||||
|
||||
if (say_args->method == SSM_ITERATED) {
|
||||
if ((tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)))) {
|
||||
char *p;
|
||||
for (p = tosay; p && *p; p++) {
|
||||
say_file("digits/%c.wav", *p);
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!(tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf))) || strlen(tosay) > 9) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
in = atoi(tosay);
|
||||
|
||||
if (in != 0) {
|
||||
for (x = 8; x >= 0; x--) {
|
||||
int num = (int) pow(10, x);
|
||||
if ((places[(uint32_t) x] = in / num)) {
|
||||
in -= places[(uint32_t) x] * num;
|
||||
}
|
||||
}
|
||||
|
||||
switch (say_args->method) {
|
||||
case SSM_COUNTED:
|
||||
case SSM_PRONOUNCED:
|
||||
/* specific case, one million => um milhão */
|
||||
if (!places[8] && !places[7] && (places[6] == 1)) {
|
||||
say_file("digits/1.wav");
|
||||
say_file("digits/million.wav");
|
||||
} else if ((status = play_group(SSM_PRONOUNCED, places[8], places[7], places[6], "digits/millions.wav", session, args)) != SWITCH_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
if ((status = play_group(SSM_PRONOUNCED, places[5], places[4], places[3], "digits/thousand.wav", session, args)) != SWITCH_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
if ((status = play_group(say_args->method, places[2], places[1], places[0], NULL, session, args)) != SWITCH_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
say_file("digits/0.wav");
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t pt_say_time(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
|
||||
{
|
||||
int32_t t;
|
||||
switch_time_t target = 0, target_now = 0;
|
||||
switch_time_exp_t tm, tm_now;
|
||||
uint8_t say_date = 0, say_time = 0, say_year = 0, say_month = 0, say_dow = 0, say_day = 0, say_yesterday = 0, say_today = 0;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
const char *tz = switch_channel_get_variable(channel, "timezone");
|
||||
|
||||
if (say_args->type == SST_TIME_MEASUREMENT) {
|
||||
int64_t hours = 0;
|
||||
int64_t minutes = 0;
|
||||
int64_t seconds = 0;
|
||||
int64_t r = 0;
|
||||
|
||||
if (strchr(tosay, ':')) {
|
||||
char *tme = switch_core_session_strdup(session, tosay);
|
||||
char *p;
|
||||
|
||||
if ((p = strrchr(tme, ':'))) {
|
||||
*p++ = '\0';
|
||||
seconds = atoi(p);
|
||||
if ((p = strchr(tme, ':'))) {
|
||||
*p++ = '\0';
|
||||
minutes = atoi(p);
|
||||
if (tme) {
|
||||
hours = atoi(tme);
|
||||
}
|
||||
} else {
|
||||
minutes = atoi(tme);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((seconds = atol(tosay)) <= 0) {
|
||||
seconds = (int64_t) switch_epoch_time_now(NULL);
|
||||
}
|
||||
|
||||
if (seconds >= 60) {
|
||||
minutes = seconds / 60;
|
||||
r = seconds % 60;
|
||||
seconds = r;
|
||||
}
|
||||
|
||||
if (minutes >= 60) {
|
||||
hours = minutes / 60;
|
||||
r = minutes % 60;
|
||||
minutes = r;
|
||||
}
|
||||
}
|
||||
|
||||
if (hours) {
|
||||
say_num(hours, SSM_PRONOUNCED);
|
||||
if (hours == 1) {
|
||||
say_file("time/hour.wav");
|
||||
} else {
|
||||
say_file("time/hours.wav");
|
||||
}
|
||||
} else {
|
||||
say_file("digits/0.wav");
|
||||
say_file("time/hours.wav");
|
||||
}
|
||||
|
||||
if (minutes) {
|
||||
say_num(minutes, SSM_PRONOUNCED);
|
||||
if (minutes == 1) {
|
||||
say_file("time/minute.wav");
|
||||
} else {
|
||||
say_file("time/minutes.wav");
|
||||
}
|
||||
} else {
|
||||
say_file("digits/0.wav");
|
||||
say_file("time/minutes.wav");
|
||||
}
|
||||
|
||||
if (seconds) {
|
||||
say_num(seconds, SSM_PRONOUNCED);
|
||||
if (seconds == 1) {
|
||||
say_file("time/second.wav");
|
||||
} else {
|
||||
say_file("time/seconds.wav");
|
||||
}
|
||||
} else {
|
||||
say_file("digits/0.wav");
|
||||
say_file("time/seconds.wav");
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if ((t = atol(tosay)) > 0) {
|
||||
target = switch_time_make(t, 0);
|
||||
target_now = switch_micro_time_now();
|
||||
} else {
|
||||
target = switch_micro_time_now();
|
||||
target_now = switch_micro_time_now();
|
||||
}
|
||||
|
||||
if (tz) {
|
||||
int check = atoi(tz);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Timezone is [%s]\n", tz);
|
||||
if (check) {
|
||||
switch_time_exp_tz(&tm, target, check);
|
||||
switch_time_exp_tz(&tm_now, target_now, check);
|
||||
} else {
|
||||
switch_time_exp_tz_name(tz, &tm, target);
|
||||
switch_time_exp_tz_name(tz, &tm_now, target_now);
|
||||
}
|
||||
} else {
|
||||
switch_time_exp_lt(&tm, target);
|
||||
switch_time_exp_lt(&tm_now, target_now);
|
||||
}
|
||||
|
||||
switch (say_args->type) {
|
||||
case SST_CURRENT_DATE_TIME:
|
||||
say_date = say_time = 1;
|
||||
break;
|
||||
case SST_CURRENT_DATE:
|
||||
say_date = 1;
|
||||
break;
|
||||
case SST_CURRENT_TIME:
|
||||
say_time = 1;
|
||||
break;
|
||||
case SST_SHORT_DATE_TIME:
|
||||
say_time = 1;
|
||||
if (tm.tm_year != tm_now.tm_year) {
|
||||
say_date = 1;
|
||||
break;
|
||||
}
|
||||
if (tm.tm_yday == tm_now.tm_yday) {
|
||||
say_today = 1;
|
||||
break;
|
||||
}
|
||||
if (tm.tm_yday == tm_now.tm_yday - 1) {
|
||||
say_yesterday = 1;
|
||||
break;
|
||||
}
|
||||
if (tm.tm_yday >= tm_now.tm_yday - 5) {
|
||||
say_dow = 1;
|
||||
break;
|
||||
}
|
||||
if (tm.tm_mon != tm_now.tm_mon) {
|
||||
say_month = say_day = say_dow = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
say_month = say_day = say_dow = 1;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (say_today) {
|
||||
say_file("time/today.wav");
|
||||
}
|
||||
if (say_yesterday) {
|
||||
say_file("time/yesterday.wav");
|
||||
}
|
||||
if (say_dow) {
|
||||
say_file("time/day-%d.wav", tm.tm_wday);
|
||||
}
|
||||
|
||||
if (say_date) {
|
||||
say_year = say_month = say_day = say_dow = 1;
|
||||
say_today = say_yesterday = 0;
|
||||
}
|
||||
|
||||
if (say_month) {
|
||||
say_file("time/mon-%d.wav", tm.tm_mon);
|
||||
}
|
||||
if (say_day) {
|
||||
say_num(tm.tm_mday, SSM_COUNTED);
|
||||
}
|
||||
if (say_year) {
|
||||
say_num(tm.tm_year + 1900, SSM_PRONOUNCED);
|
||||
}
|
||||
|
||||
if (say_time) {
|
||||
int32_t hour = tm.tm_hour, pm = 0;
|
||||
|
||||
if (say_date || say_today || say_yesterday || say_dow) {
|
||||
if (hour == 1) {
|
||||
say_file("time/at.wav");
|
||||
} else {
|
||||
say_file("time/ats.wav");
|
||||
}
|
||||
}
|
||||
|
||||
if (hour > 12) {
|
||||
hour -= 12;
|
||||
pm = 1;
|
||||
} else if (hour == 12) {
|
||||
pm = 1;
|
||||
} else if (hour == 0) {
|
||||
hour = 12;
|
||||
pm = 0;
|
||||
}
|
||||
|
||||
say_num(hour, SSM_PRONOUNCED);
|
||||
|
||||
if (tm.tm_min) {
|
||||
say_file("currency/and.wav");
|
||||
say_num(tm.tm_min, SSM_PRONOUNCED);
|
||||
} else {
|
||||
say_file("time/oclock.wav");
|
||||
}
|
||||
|
||||
say_file("time/%s.wav", pm ? "p-m" : "a-m");
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static switch_status_t pt_say_money(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
|
||||
{
|
||||
char sbuf[16] = ""; /* enough for 999,999,999,999.99 (w/o the commas or leading $) */
|
||||
char *dollars = NULL;
|
||||
char *cents = NULL;
|
||||
|
||||
if (strlen(tosay) > 15 || !(tosay = switch_strip_nonnumerics(tosay, sbuf, sizeof(sbuf)))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
dollars = sbuf;
|
||||
|
||||
if ((cents = strchr(sbuf, '.'))) {
|
||||
*cents++ = '\0';
|
||||
if (strlen(cents) > 2) {
|
||||
cents[2] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* If positive sign - skip over" */
|
||||
if (sbuf[0] == '+') {
|
||||
dollars++;
|
||||
}
|
||||
|
||||
/* If negative say "negative" */
|
||||
if (sbuf[0] == '-') {
|
||||
say_file("currency/negative.wav");
|
||||
dollars++;
|
||||
}
|
||||
|
||||
/* Say dollar amount */
|
||||
pt_say_general_count(session, dollars, say_args, args);
|
||||
if (atoi(dollars) == 1) {
|
||||
say_file("currency/dollar.wav");
|
||||
} else {
|
||||
say_file("currency/dollars.wav");
|
||||
}
|
||||
|
||||
/* Say "and" */
|
||||
say_file("currency/and.wav");
|
||||
|
||||
/* Say cents */
|
||||
if (cents) {
|
||||
pt_say_general_count(session, cents, say_args, args);
|
||||
if (atoi(cents) == 1) {
|
||||
say_file("currency/cent.wav");
|
||||
} else {
|
||||
say_file("currency/cents.wav");
|
||||
}
|
||||
} else {
|
||||
say_file("digits/0.wav");
|
||||
say_file("currency/cents.wav");
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static switch_status_t pt_say(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args)
|
||||
{
|
||||
|
||||
switch_say_callback_t say_cb = NULL;
|
||||
|
||||
switch (say_args->type) {
|
||||
case SST_NUMBER:
|
||||
case SST_ITEMS:
|
||||
case SST_PERSONS:
|
||||
case SST_MESSAGES:
|
||||
say_cb = pt_say_general_count;
|
||||
break;
|
||||
case SST_TIME_MEASUREMENT:
|
||||
case SST_CURRENT_DATE:
|
||||
case SST_CURRENT_TIME:
|
||||
case SST_CURRENT_DATE_TIME:
|
||||
case SST_SHORT_DATE_TIME:
|
||||
say_cb = pt_say_time;
|
||||
break;
|
||||
case SST_IP_ADDRESS:
|
||||
return switch_ivr_say_ip(session, tosay, pt_say_general_count, say_args, args);
|
||||
break;
|
||||
case SST_NAME_SPELLED:
|
||||
case SST_NAME_PHONETIC:
|
||||
return switch_ivr_say_spell(session, tosay, say_args, args);
|
||||
break;
|
||||
case SST_CURRENCY:
|
||||
say_cb = pt_say_money;
|
||||
break;
|
||||
default:
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown Say type=[%d]\n", say_args->type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (say_cb) {
|
||||
return say_cb(session, tosay, say_args, args);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_say_pt_load)
|
||||
{
|
||||
switch_say_interface_t *say_interface;
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
say_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_SAY_INTERFACE);
|
||||
say_interface->interface_name = "pt";
|
||||
say_interface->say_function = pt_say;
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
|
||||
*/
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="mod_say_pt"
|
||||
ProjectGUID="{7C22BDFF-CC09-400C-8A09-660733980028}"
|
||||
RootNamespace="mod_say_pt"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\mod_say_pt.c"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -742,6 +742,28 @@ SWITCH_DECLARE(switch_status_t) switch_socket_recv(switch_socket_t *sock, char *
|
||||
return apr_socket_recv(sock, buf, len);
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_sockaddr_create(switch_sockaddr_t **sa, switch_memory_pool_t *pool)
|
||||
{
|
||||
switch_sockaddr_t *new_sa;
|
||||
unsigned short family = APR_INET;
|
||||
|
||||
new_sa = apr_pcalloc(pool, sizeof(apr_sockaddr_t));
|
||||
switch_assert(new_sa);
|
||||
new_sa->pool = pool;
|
||||
memset(new_sa, 0, sizeof(new_sa));
|
||||
|
||||
new_sa->family = family;
|
||||
new_sa->sa.sin.sin_family = family;
|
||||
|
||||
new_sa->salen = sizeof(struct sockaddr_in);
|
||||
new_sa->addr_str_len = 16;
|
||||
new_sa->ipaddr_ptr = &(new_sa->sa.sin.sin_addr);
|
||||
new_sa->ipaddr_len = sizeof(struct in_addr);
|
||||
|
||||
*sa = new_sa;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_sockaddr_info_get(switch_sockaddr_t ** sa, const char *hostname, int32_t family,
|
||||
switch_port_t port, int32_t flags, switch_memory_pool_t *pool)
|
||||
{
|
||||
|
||||
+41
-3
@@ -2382,10 +2382,48 @@ SWITCH_DECLARE(switch_status_t) switch_channel_caller_extension_masquerade(switc
|
||||
return status;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_channel_sort_cid(switch_channel_t *channel, switch_bool_t in)
|
||||
{
|
||||
|
||||
if (in) {
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && !switch_channel_test_flag(channel, CF_DIALPLAN)) {
|
||||
switch_channel_set_flag(channel, CF_DIALPLAN);
|
||||
|
||||
switch_mutex_lock(channel->profile_mutex);
|
||||
if (channel->caller_profile->callee_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 (channel->caller_profile->callee_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;
|
||||
switch_mutex_unlock(channel->profile_mutex);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && switch_channel_test_flag(channel, CF_DIALPLAN)) {
|
||||
switch_channel_clear_flag(channel, CF_DIALPLAN);
|
||||
switch_mutex_lock(channel->profile_mutex);
|
||||
channel->caller_profile->callee_id_name = SWITCH_BLANK_STRING;
|
||||
channel->caller_profile->callee_id_number = SWITCH_BLANK_STRING;
|
||||
switch_mutex_unlock(channel->profile_mutex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(void) switch_channel_set_caller_extension(switch_channel_t *channel, switch_caller_extension_t *caller_extension)
|
||||
{
|
||||
switch_assert(channel != NULL);
|
||||
|
||||
switch_channel_sort_cid(channel, SWITCH_TRUE);
|
||||
|
||||
switch_mutex_lock(channel->profile_mutex);
|
||||
caller_extension->next = channel->caller_profile->caller_extension;
|
||||
channel->caller_profile->caller_extension = caller_extension;
|
||||
@@ -2622,7 +2660,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_pre_answer(switch_channel
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_PROGRESS;
|
||||
msg.from = channel->name;
|
||||
status = switch_core_session_perform_receive_message(channel->session, &msg, file, func, line);
|
||||
@@ -2657,7 +2695,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_ring_ready_value(switch_c
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_RINGING;
|
||||
msg.from = channel->name;
|
||||
msg.numeric_arg = rv;
|
||||
@@ -2800,7 +2838,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_answer(switch_channel_t *
|
||||
|
||||
switch_assert(channel != NULL);
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
+54
-11
@@ -235,7 +235,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
|
||||
|
||||
if (switch_test_flag(*frame, SFF_CNG)) {
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
if (!session->bugs) {
|
||||
if (!session->bugs && !session->plc) {
|
||||
goto done;
|
||||
}
|
||||
is_cng = 1;
|
||||
@@ -303,7 +303,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
|
||||
session->raw_read_frame.datalen = session->raw_read_frame.buflen;
|
||||
|
||||
if (is_cng) {
|
||||
memset(session->raw_read_frame.data, 255, read_frame->codec->implementation->decoded_bytes_per_packet);
|
||||
if (session->plc) {
|
||||
plc_fillin(session->plc, session->raw_read_frame.data, read_frame->codec->implementation->decoded_bytes_per_packet / 2);
|
||||
is_cng = 0;
|
||||
flag &= !SFF_CNG;
|
||||
} else {
|
||||
memset(session->raw_read_frame.data, 255, read_frame->codec->implementation->decoded_bytes_per_packet);
|
||||
}
|
||||
session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet;
|
||||
session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t);
|
||||
read_frame = &session->raw_read_frame;
|
||||
@@ -319,13 +325,38 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
|
||||
switch_thread_rwlock_unlock(session->bug_rwlock);
|
||||
}
|
||||
|
||||
status = switch_core_codec_decode(use_codec,
|
||||
session->read_codec,
|
||||
read_frame->data,
|
||||
read_frame->datalen,
|
||||
session->read_impl.actual_samples_per_second,
|
||||
session->raw_read_frame.data, &session->raw_read_frame.datalen, &session->raw_read_frame.rate,
|
||||
&read_frame->flags);
|
||||
if (switch_test_flag(read_frame, SFF_PLC)) {
|
||||
session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet;
|
||||
session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t);
|
||||
memset(session->raw_read_frame.data, 255, session->raw_read_frame.datalen);
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
status = switch_core_codec_decode(use_codec,
|
||||
session->read_codec,
|
||||
read_frame->data,
|
||||
read_frame->datalen,
|
||||
session->read_impl.actual_samples_per_second,
|
||||
session->raw_read_frame.data, &session->raw_read_frame.datalen, &session->raw_read_frame.rate,
|
||||
&read_frame->flags);
|
||||
}
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
if ((switch_channel_test_flag(session->channel, CF_JITTERBUFFER) || switch_channel_test_flag(session->channel, CF_CNG_PLC))
|
||||
&& !session->plc) {
|
||||
session->plc = plc_init(NULL);
|
||||
}
|
||||
|
||||
if (session->plc) {
|
||||
if (switch_test_flag(read_frame, SFF_PLC)) {
|
||||
plc_fillin(session->plc, session->raw_read_frame.data, session->raw_read_frame.datalen / 2);
|
||||
switch_clear_flag(read_frame, SFF_PLC);
|
||||
} else {
|
||||
plc_rx(session->plc, session->raw_read_frame.data, session->raw_read_frame.datalen / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (do_resample && ((status == SWITCH_STATUS_SUCCESS) || is_cng)) {
|
||||
@@ -361,6 +392,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
|
||||
session->raw_read_frame.seq = read_frame->seq;
|
||||
session->raw_read_frame.m = read_frame->m;
|
||||
session->raw_read_frame.payload = read_frame->payload;
|
||||
session->raw_read_frame.flags = 0;
|
||||
if (switch_test_flag(read_frame, SFF_PLC)) {
|
||||
session->raw_read_frame.flags |= SFF_PLC;
|
||||
}
|
||||
read_frame = &session->raw_read_frame;
|
||||
break;
|
||||
case SWITCH_STATUS_NOOP:
|
||||
@@ -383,6 +418,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
|
||||
session->raw_read_frame.seq = read_frame->seq;
|
||||
session->raw_read_frame.m = read_frame->m;
|
||||
session->raw_read_frame.payload = read_frame->payload;
|
||||
session->raw_read_frame.flags = 0;
|
||||
if (switch_test_flag(read_frame, SFF_PLC)) {
|
||||
session->raw_read_frame.flags |= SFF_PLC;
|
||||
}
|
||||
|
||||
read_frame = &session->raw_read_frame;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
break;
|
||||
@@ -462,7 +502,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
|
||||
read_frame->datalen = session->read_resampler->to_len * 2;
|
||||
read_frame->rate = session->read_resampler->to_rate;
|
||||
switch_mutex_unlock(session->resample_mutex);
|
||||
|
||||
}
|
||||
|
||||
if (read_frame->datalen == session->read_impl.decoded_bytes_per_packet) {
|
||||
@@ -481,7 +520,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (perfect || switch_buffer_inuse(session->raw_read_buffer) >= session->read_impl.decoded_bytes_per_packet) {
|
||||
if (perfect) {
|
||||
enc_frame = read_frame;
|
||||
@@ -810,6 +848,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
|
||||
session->raw_write_frame.ssrc = frame->ssrc;
|
||||
session->raw_write_frame.seq = frame->seq;
|
||||
session->raw_write_frame.payload = frame->payload;
|
||||
session->raw_write_frame.flags = 0;
|
||||
if (switch_test_flag(frame, SFF_PLC)) {
|
||||
session->raw_write_frame.flags |= SFF_PLC;
|
||||
}
|
||||
|
||||
write_frame = &session->raw_write_frame;
|
||||
break;
|
||||
case SWITCH_STATUS_BREAK:
|
||||
|
||||
@@ -392,6 +392,32 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_flush_all(switch_core_sess
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_enumerate(switch_core_session_t *session, switch_stream_handle_t *stream)
|
||||
{
|
||||
switch_media_bug_t *bp;
|
||||
|
||||
stream->write_function(stream, "<media-bugs>\n");
|
||||
|
||||
if (session->bugs) {
|
||||
switch_thread_rwlock_wrlock(session->bug_rwlock);
|
||||
for (bp = session->bugs; bp; bp = bp->next) {
|
||||
int thread_locked = (bp->thread_id && bp->thread_id == switch_thread_self());
|
||||
stream->write_function(stream,
|
||||
" <media-bug>\n"
|
||||
" <function>%s</function>\n"
|
||||
" <target>%s</target>\n"
|
||||
" <thread-locked>%d</thread-locked>\n"
|
||||
" </media-bug>\n",
|
||||
bp->function, bp->target, thread_locked);
|
||||
|
||||
}
|
||||
switch_thread_rwlock_unlock(session->bug_rwlock);
|
||||
}
|
||||
|
||||
stream->write_function(stream, "</media-bugs>\n");
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all(switch_core_session_t *session)
|
||||
{
|
||||
|
||||
@@ -1118,6 +1118,11 @@ SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t *
|
||||
}
|
||||
switch_mutex_unlock(runtime.session_hash_mutex);
|
||||
|
||||
if ((*session)->plc) {
|
||||
plc_free((*session)->plc);
|
||||
(*session)->plc = NULL;
|
||||
}
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_DESTROY) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_channel_event_set_data((*session)->channel, event);
|
||||
switch_event_fire(&event);
|
||||
@@ -1836,6 +1841,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_async(sw
|
||||
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", arg);
|
||||
}
|
||||
|
||||
if (!switch_channel_test_flag(session->channel, CF_PROXY_MODE)) {
|
||||
switch_channel_set_flag(session->channel, CF_BLOCK_BROADCAST_UNTIL_MEDIA);
|
||||
}
|
||||
|
||||
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true");
|
||||
switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE);
|
||||
|
||||
@@ -1886,9 +1895,19 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_get_flag
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
|
||||
"Cannot execute app '%s' media required on an outbound channel that does not have media established\n", app);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
uint32_t ready = 0, sanity = 2000;
|
||||
|
||||
do {
|
||||
sanity--;
|
||||
ready = switch_channel_media_ready(session->channel);
|
||||
switch_cond_next();
|
||||
} while(!ready && sanity);
|
||||
|
||||
if (!ready) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
|
||||
"Cannot execute app '%s' media required on an outbound channel that does not have media established\n", app);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1624,6 +1624,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
|
||||
runtime.odbc_dsn = NULL;
|
||||
runtime.odbc_user = NULL;
|
||||
runtime.odbc_pass = NULL;
|
||||
runtime.odbc_dbtype = DBTYPE_DEFAULT;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Falling back to core_db.\n");
|
||||
goto top;
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ static void switch_core_standard_on_routing(switch_core_session_t *session)
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
if (switch_channel_test_flag(session->channel, CF_OUTBOUND)) {
|
||||
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
if (switch_channel_test_flag(session->channel, CF_ANSWERED)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
|
||||
"No Dialplan on answered channel, changing state to HANGUP\n");
|
||||
|
||||
+10
-1
@@ -576,6 +576,15 @@ SWITCH_DECLARE(int) CoreSession::answer()
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(int) CoreSession::insertFile(const char *file, const char *insert_file, int sample_point)
|
||||
{
|
||||
switch_status_t status;
|
||||
this_check(-1);
|
||||
sanity_check(-1);
|
||||
status = switch_ivr_insert_file(session, file, insert_file, (switch_size_t)sample_point);
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(int) CoreSession::preAnswer()
|
||||
{
|
||||
switch_status_t status;
|
||||
@@ -1206,7 +1215,7 @@ SWITCH_DECLARE(void) bridge(CoreSession &session_a, CoreSession &session_b)
|
||||
|
||||
if (switch_channel_ready(channel_a) && switch_channel_ready(channel_b)) {
|
||||
session_a.begin_allow_threads();
|
||||
if (!switch_channel_test_flag(channel_a, CF_OUTBOUND) && !switch_channel_media_ready(channel_a)) {
|
||||
if (switch_channel_direction(channel_a) == SWITCH_CALL_DIRECTION_INBOUND && !switch_channel_media_ready(channel_a)) {
|
||||
switch_channel_pre_answer(channel_a);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -339,7 +339,7 @@ static void *SWITCH_THREAD_FUNC switch_event_thread(switch_thread_t *thread, voi
|
||||
launch_dispatch_threads(SOFT_MAX_DISPATCH + 1, DISPATCH_QUEUE_LEN, RUNTIME_POOL);
|
||||
switch_mutex_unlock(EVENT_QUEUE_MUTEX);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Out of threads!\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Out of event dispatch threads! Slowing things down.\n");
|
||||
switch_yield(1000000);
|
||||
}
|
||||
}
|
||||
|
||||
+16
-20
@@ -140,7 +140,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session,
|
||||
const char *var;
|
||||
|
||||
/*
|
||||
if (!switch_channel_test_flag(channel, CF_OUTBOUND) && !switch_channel_test_flag(channel, CF_PROXY_MODE) &&
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND && !switch_channel_test_flag(channel, CF_PROXY_MODE) &&
|
||||
!switch_channel_media_ready(channel) && !switch_channel_test_flag(channel, CF_SERVICE)) {
|
||||
if ((status = switch_channel_pre_answer(channel)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot establish media.\n");
|
||||
@@ -698,12 +698,23 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_messages(switch_core_sessio
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_events(switch_core_session_t *session)
|
||||
{
|
||||
int x = 0;
|
||||
|
||||
switch_channel_t *channel;
|
||||
|
||||
switch_ivr_parse_all_messages(session);
|
||||
|
||||
while (switch_ivr_parse_next_event(session) == SWITCH_STATUS_SUCCESS)
|
||||
channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (!switch_channel_test_flag(channel, CF_PROXY_MODE) && switch_channel_test_flag(channel, CF_BLOCK_BROADCAST_UNTIL_MEDIA)) {
|
||||
if (switch_channel_media_ready(channel)) {
|
||||
switch_channel_clear_flag(channel, CF_BLOCK_BROADCAST_UNTIL_MEDIA);
|
||||
} else {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
while (switch_ivr_parse_next_event(session) == SWITCH_STATUS_SUCCESS) {
|
||||
x++;
|
||||
}
|
||||
|
||||
if (x) {
|
||||
switch_ivr_sleep(session, 0, SWITCH_TRUE, NULL);
|
||||
@@ -1544,21 +1555,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_
|
||||
new_profile->destination_number = switch_core_strdup(new_profile->pool, extension);
|
||||
new_profile->rdnis = switch_core_strdup(new_profile->pool, profile->destination_number);
|
||||
|
||||
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
if (profile->callee_id_name) {
|
||||
switch_channel_set_variable(channel, "pre_transfer_caller_id_name", new_profile->caller_id_name);
|
||||
new_profile->caller_id_name = switch_core_strdup(new_profile->pool, profile->callee_id_name);
|
||||
profile->callee_id_name = SWITCH_BLANK_STRING;
|
||||
}
|
||||
|
||||
if (profile->callee_id_number) {
|
||||
switch_channel_set_variable(channel, "pre_transfer_caller_id_number", new_profile->caller_id_number);
|
||||
new_profile->caller_id_number = switch_core_strdup(new_profile->pool, profile->callee_id_number);
|
||||
profile->callee_id_number = SWITCH_BLANK_STRING;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch_channel_set_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE, NULL);
|
||||
|
||||
/* If HANGUP_AFTER_BRIDGE is set to 'true', SWITCH_SIGNAL_BRIDGE_VARIABLE
|
||||
@@ -2290,7 +2286,7 @@ SWITCH_DECLARE(void) switch_ivr_delay_echo(switch_core_session_t *session, uint3
|
||||
|
||||
qlen = delay_ms / (interval);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting delay to %dms (%d frames)\n", delay_ms, qlen);
|
||||
jb = stfu_n_init(qlen, 0);
|
||||
jb = stfu_n_init(qlen, qlen, read_impl.samples_per_packet, read_impl.samples_per_second);
|
||||
|
||||
write_frame.codec = switch_core_session_get_read_codec(session);
|
||||
|
||||
@@ -2300,7 +2296,7 @@ SWITCH_DECLARE(void) switch_ivr_delay_echo(switch_core_session_t *session, uint3
|
||||
break;
|
||||
}
|
||||
|
||||
stfu_n_eat(jb, ts, read_frame->payload, read_frame->data, read_frame->datalen);
|
||||
stfu_n_eat(jb, ts, read_frame->payload, read_frame->data, read_frame->datalen, 0);
|
||||
ts += interval;
|
||||
|
||||
if ((jb_frame = stfu_n_read_a_frame(jb))) {
|
||||
|
||||
@@ -282,9 +282,10 @@ static dm_match_t switch_ivr_dmachine_check_match(switch_ivr_dmachine_t *dmachin
|
||||
best = DM_MATCH_EXACT;
|
||||
exact_bp = bp;
|
||||
if (dmachine->cur_digit_len == dmachine->max_digit_len) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(both_bp && partial_bp) && !strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits))) {
|
||||
if (!(both_bp && partial_bp) && strlen(bp->digits) != strlen(dmachine->digits) &&
|
||||
!strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits))) {
|
||||
if (exact_bp) {
|
||||
best = DM_MATCH_BOTH;
|
||||
both_bp = bp;
|
||||
@@ -303,8 +304,6 @@ static dm_match_t switch_ivr_dmachine_check_match(switch_ivr_dmachine_t *dmachin
|
||||
if (is_timeout) {
|
||||
if (both_bp) {
|
||||
r_bp = exact_bp ? exact_bp : both_bp;
|
||||
} else if (partial_bp) {
|
||||
r_bp = partial_bp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ static void send_display(switch_core_session_t *session, switch_core_session_t *
|
||||
caller_channel = switch_core_session_get_channel(session);
|
||||
caller_profile = switch_channel_get_caller_profile(caller_channel);
|
||||
|
||||
if (switch_channel_direction(caller_channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
if (switch_channel_direction(caller_channel) == SWITCH_CALL_DIRECTION_OUTBOUND && !switch_channel_test_flag(caller_channel, CF_DIALPLAN)) {
|
||||
name = caller_profile->callee_id_name;
|
||||
number = caller_profile->callee_id_number;
|
||||
|
||||
@@ -435,8 +435,8 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
|
||||
switch_channel_t *un = ans_a ? chan_b : chan_a;
|
||||
switch_channel_t *a = un == chan_b ? chan_a : chan_b;
|
||||
|
||||
if (!switch_channel_test_flag(un, CF_OUTBOUND)) {
|
||||
if (switch_channel_test_flag(a, CF_OUTBOUND) || (un == chan_a && !originator)) {
|
||||
if (switch_channel_direction(un) == SWITCH_CALL_DIRECTION_INBOUND) {
|
||||
if (switch_channel_direction(a) == SWITCH_CALL_DIRECTION_OUTBOUND || (un == chan_a && !originator)) {
|
||||
switch_channel_pass_callee_id(a, un);
|
||||
}
|
||||
|
||||
|
||||
+18
-24
@@ -384,8 +384,9 @@ static void inherit_codec(switch_channel_t *caller_channel, switch_core_session_
|
||||
switch_codec_implementation_t video_impl = { 0 };
|
||||
char tmp[128] = "";
|
||||
|
||||
|
||||
if (switch_core_session_get_read_impl(session, &impl) == SWITCH_STATUS_SUCCESS) {
|
||||
const char *ep = switch_channel_get_variable(caller_channel, "ep_codec_string");
|
||||
|
||||
if (switch_core_session_get_video_read_impl(session, &video_impl) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_snprintf(tmp, sizeof(tmp), "%s@%uh@%ui,%s",
|
||||
impl.iananame, impl.samples_per_second, impl.microseconds_per_packet / 1000,
|
||||
@@ -394,9 +395,15 @@ static void inherit_codec(switch_channel_t *caller_channel, switch_core_session_
|
||||
switch_snprintf(tmp, sizeof(tmp), "%s@%uh@%ui",
|
||||
impl.iananame, impl.samples_per_second, impl.microseconds_per_packet / 1000);
|
||||
}
|
||||
switch_channel_set_variable(caller_channel, "absolute_codec_string", tmp);
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(caller_channel), SWITCH_LOG_DEBUG, "Setting codec string on %s to %s\n",
|
||||
switch_channel_get_name(caller_channel), tmp);
|
||||
|
||||
if (ep && switch_stristr(impl.iananame, ep)) {
|
||||
switch_channel_set_variable(caller_channel, "absolute_codec_string", tmp);
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(caller_channel), SWITCH_LOG_DEBUG, "Setting codec string on %s to %s\n",
|
||||
switch_channel_get_name(caller_channel), tmp);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(caller_channel), SWITCH_LOG_DEBUG, "Codec string %s not supported on %s, skipping inheritance\n",
|
||||
tmp, switch_channel_get_name(caller_channel));
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(caller_channel), SWITCH_LOG_WARNING,
|
||||
"Error inheriting codec. Channel %s has no read codec yet.\n",
|
||||
@@ -488,7 +495,7 @@ static uint8_t check_channel_status(originate_global_t *oglobals, originate_stat
|
||||
pindex = (uint32_t) i;
|
||||
} else if (!oglobals->sent_ring && oglobals->ignore_early_media == 2 && len == 1 && caller_channel && !oglobals->ignore_ring_ready) {
|
||||
switch_channel_pass_callee_id(originate_status[0].peer_channel, caller_channel);
|
||||
//switch_channel_ring_ready(caller_channel);
|
||||
switch_channel_ring_ready(caller_channel);
|
||||
oglobals->sent_ring = 1;
|
||||
}
|
||||
|
||||
@@ -1751,6 +1758,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
early_state_t early_state = { 0 };
|
||||
int read_packet = 0;
|
||||
int check_reject = 1;
|
||||
switch_codec_implementation_t read_impl = { 0 };
|
||||
|
||||
if (strstr(bridgeto, SWITCH_ENT_ORIGINATE_DELIM)) {
|
||||
return switch_ivr_enterprise_originate(session, bleg, cause, bridgeto, timelimit_sec, table, cid_name_override, cid_num_override,
|
||||
@@ -1777,6 +1785,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
switch_channel_set_flag(caller_channel, CF_ORIGINATOR);
|
||||
oglobals.session = session;
|
||||
|
||||
switch_core_session_get_read_impl(session, &read_impl);
|
||||
|
||||
if ((to_var = switch_channel_get_variable(caller_channel, SWITCH_CALL_TIMEOUT_VARIABLE))) {
|
||||
timelimit_sec = atoi(to_var);
|
||||
@@ -2381,24 +2390,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
new_profile->chan_name = SWITCH_BLANK_STRING;
|
||||
new_profile->destination_number = switch_core_strdup(new_profile->pool, chan_data);
|
||||
|
||||
if (switch_channel_direction(caller_channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
|
||||
const char *callee_id_name = new_profile->callee_id_name;
|
||||
const char *callee_id_number = new_profile->callee_id_number;
|
||||
|
||||
if (zstr(callee_id_number)) {
|
||||
callee_id_number = caller_caller_profile->destination_number;
|
||||
}
|
||||
|
||||
if (zstr(callee_id_name)) {
|
||||
callee_id_name = callee_id_number;
|
||||
}
|
||||
|
||||
new_profile->caller_id_name = callee_id_name;
|
||||
new_profile->caller_id_number = callee_id_number;
|
||||
new_profile->callee_id_name = SWITCH_BLANK_STRING;
|
||||
new_profile->callee_id_number = SWITCH_BLANK_STRING;
|
||||
}
|
||||
|
||||
if (cid_name_override) {
|
||||
new_profile->caller_id_name = switch_core_strdup(new_profile->pool, cid_name_override);
|
||||
}
|
||||
@@ -2426,6 +2417,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
}
|
||||
}
|
||||
|
||||
new_profile->callee_id_name = switch_core_strdup(new_profile->pool, "Outbound Call");
|
||||
new_profile->callee_id_number = switch_core_strdup(new_profile->pool, new_profile->destination_number);
|
||||
|
||||
originate_status[i].caller_profile = NULL;
|
||||
originate_status[i].peer_channel = NULL;
|
||||
originate_status[i].peer_session = NULL;
|
||||
@@ -3066,7 +3060,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
|
||||
if ((ringback.fh || silence || ringback.audio_buffer || oglobals.bridge_early_media > -1) && write_frame.codec && write_frame.datalen) {
|
||||
if (silence) {
|
||||
write_frame.datalen = write_frame.codec->implementation->decoded_bytes_per_packet;
|
||||
write_frame.datalen = read_impl.decoded_bytes_per_packet;
|
||||
switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.datalen / 2, silence);
|
||||
}
|
||||
|
||||
|
||||
@@ -1573,10 +1573,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "done playing file\n");
|
||||
|
||||
if (read_impl.samples_per_second) {
|
||||
switch_channel_set_variable_printf(channel, "playback_seconds", "%d", fh->samples_out / read_impl.samples_per_second);
|
||||
switch_channel_set_variable_printf(channel, "playback_ms", "%d", fh->samples_out / (read_impl.samples_per_second / 1000));
|
||||
switch_channel_set_variable_printf(channel, "playback_seconds", "%d", fh->samples_in / read_impl.samples_per_second);
|
||||
switch_channel_set_variable_printf(channel, "playback_ms", "%d", fh->samples_in / (read_impl.samples_per_second / 1000));
|
||||
}
|
||||
switch_channel_set_variable_printf(channel, "playback_samples", "%d", fh->samples_out);
|
||||
switch_channel_set_variable_printf(channel, "playback_samples", "%d", fh->samples_in);
|
||||
|
||||
switch_core_session_io_write_lock(session);
|
||||
switch_channel_set_private(channel, "__fh", NULL);
|
||||
@@ -1761,6 +1761,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_read(switch_core_session_t *session,
|
||||
|
||||
switch_assert(session);
|
||||
|
||||
if (!digit_timeout) {
|
||||
digit_timeout = timeout;
|
||||
}
|
||||
|
||||
if (max_digits < min_digits) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
|
||||
"Max digits %u is less than Min %u, forcing Max to %u\n", max_digits, min_digits, min_digits);
|
||||
@@ -1870,6 +1874,11 @@ SWITCH_DECLARE(switch_status_t) switch_play_and_get_digits(switch_core_session_t
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if ((min_digits == 0) && (strlen(digit_buffer) == 0) && switch_channel_get_variable(channel, SWITCH_READ_TERMINATOR_USED_VARIABLE) != 0)
|
||||
{
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!(status == SWITCH_STATUS_TOO_SMALL && strlen(digit_buffer) == 0)) {
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
if (!zstr(digit_buffer)) {
|
||||
|
||||
+131
-18
@@ -174,6 +174,8 @@ struct switch_rtp {
|
||||
void *private_data;
|
||||
uint32_t ts;
|
||||
uint32_t last_write_ts;
|
||||
uint32_t last_read_ts;
|
||||
uint32_t last_cng_ts;
|
||||
uint32_t last_write_samplecount;
|
||||
uint32_t next_write_samplecount;
|
||||
switch_time_t last_write_timestamp;
|
||||
@@ -229,7 +231,7 @@ struct switch_rtp {
|
||||
uint32_t sync_packets;
|
||||
int rtcp_interval;
|
||||
switch_bool_t rtcp_fresh_frame;
|
||||
|
||||
uint8_t checked_jb;
|
||||
#ifdef ENABLE_ZRTP
|
||||
zrtp_session_t *zrtp_session;
|
||||
zrtp_profile_t *zrtp_profile;
|
||||
@@ -1367,9 +1369,10 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
|
||||
switch_rtp_set_flag(rtp_session, flags);
|
||||
|
||||
/* for from address on recvfrom calls */
|
||||
switch_sockaddr_info_get(&rtp_session->from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool);
|
||||
switch_sockaddr_create(&rtp_session->from_addr, pool);
|
||||
|
||||
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {
|
||||
switch_sockaddr_info_get(&rtp_session->rtcp_from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool);
|
||||
switch_sockaddr_create(&rtp_session->rtcp_from_addr, pool);
|
||||
}
|
||||
rtp_session->seq = (uint16_t) rand();
|
||||
rtp_session->ssrc = (uint32_t) ((intptr_t) rtp_session + (uint32_t) switch_epoch_time_now(NULL));
|
||||
@@ -1618,14 +1621,94 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_stun_ping(switch_rtp_t *rtp_
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *rtp_session, uint32_t queue_frames)
|
||||
static void jb_callback(stfu_instance_t *i, void *udata)
|
||||
{
|
||||
switch_core_session_t *session = (switch_core_session_t *) udata;
|
||||
stfu_report_t r = { 0 };
|
||||
|
||||
stfu_n_report(i, &r);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1,
|
||||
"%s JB REPORT:\nlen: %u\nin: %u\nclean: %u\ngood: %u\nbad: %u\n",
|
||||
switch_core_session_get_name(session),
|
||||
r.qlen,
|
||||
r.packet_in_count,
|
||||
r.clean_count,
|
||||
r.consecutive_good_count,
|
||||
r.consecutive_bad_count
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_deactivate_jitter_buffer(switch_rtp_t *rtp_session)
|
||||
{
|
||||
|
||||
if (!switch_rtp_ready(rtp_session) || !rtp_session->jb) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
READ_INC(rtp_session);
|
||||
stfu_n_destroy(&rtp_session->jb);
|
||||
READ_DEC(rtp_session);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void jb_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
char *data;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = switch_vasprintf(&data, fmt, ap);
|
||||
if (ret != -1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_CONSOLE, "%s", data);
|
||||
free(data);
|
||||
}
|
||||
|
||||
//switch_log_printf(SWITCH_CHANNEL_ID_LOG_CLEAN, file, func, line, NULL, level, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_debug_jitter_buffer(switch_rtp_t *rtp_session, const char *name)
|
||||
{
|
||||
|
||||
rtp_session->jb = stfu_n_init(queue_frames, 0);
|
||||
stfu_n_debug(rtp_session->jb, name);
|
||||
stfu_global_set_logger(jb_logger);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *rtp_session,
|
||||
uint32_t queue_frames,
|
||||
uint32_t max_queue_frames,
|
||||
uint32_t samples_per_packet,
|
||||
uint32_t samples_per_second)
|
||||
{
|
||||
|
||||
if (!switch_rtp_ready(rtp_session)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
READ_INC(rtp_session);
|
||||
if (rtp_session->jb) {
|
||||
stfu_n_resize(rtp_session->jb, queue_frames);
|
||||
} else {
|
||||
rtp_session->jb = stfu_n_init(queue_frames, max_queue_frames ? max_queue_frames : 50, samples_per_packet, samples_per_second);
|
||||
}
|
||||
READ_DEC(rtp_session);
|
||||
|
||||
if (rtp_session->jb) {
|
||||
switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session");
|
||||
stfu_n_call_me(rtp_session->jb, jb_callback, session);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_session, int send_rate, switch_port_t remote_port)
|
||||
{
|
||||
const char *err = NULL;
|
||||
@@ -2016,14 +2099,18 @@ static void do_flush(switch_rtp_t *rtp_session)
|
||||
switch_size_t bytes;
|
||||
switch_status_t status;
|
||||
|
||||
if (!switch_rtp_ready(rtp_session) || switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA)) {
|
||||
if (!switch_rtp_ready(rtp_session) ||
|
||||
switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) ||
|
||||
switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
READ_INC(rtp_session);
|
||||
|
||||
if (switch_rtp_ready(rtp_session)) {
|
||||
|
||||
uint32_t flushed = 0;
|
||||
|
||||
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_DEBUG_RTP_READ)) {
|
||||
switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session");
|
||||
if (!session) {
|
||||
@@ -2047,6 +2134,9 @@ static void do_flush(switch_rtp_t *rtp_session)
|
||||
bytes = sizeof(rtp_msg_t);
|
||||
status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, &bytes);
|
||||
if (bytes) {
|
||||
|
||||
flushed++;
|
||||
|
||||
rtp_session->stats.inbound.raw_bytes += bytes;
|
||||
rtp_session->stats.inbound.flush_packet_count++;
|
||||
rtp_session->stats.inbound.packet_count++;
|
||||
@@ -2056,6 +2146,10 @@ static void do_flush(switch_rtp_t *rtp_session)
|
||||
}
|
||||
} while (bytes > 0);
|
||||
|
||||
if (rtp_session->jb && flushed) {
|
||||
stfu_n_sync(rtp_session->jb, flushed);
|
||||
}
|
||||
|
||||
if (was_blocking && switch_rtp_ready(rtp_session)) {
|
||||
switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_NOBLOCK);
|
||||
switch_socket_opt_set(rtp_session->sock_input, SWITCH_SO_NONBLOCK, FALSE);
|
||||
@@ -2071,11 +2165,20 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
stfu_frame_t *jb_frame;
|
||||
uint32_t ts;
|
||||
|
||||
switch_assert(bytes);
|
||||
|
||||
*bytes = sizeof(rtp_msg_t);
|
||||
status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, bytes);
|
||||
ts = ntohl(rtp_session->recv_msg.header.ts);
|
||||
|
||||
if (*bytes && (!rtp_session->recv_te || rtp_session->recv_msg.header.pt != rtp_session->recv_te) &&
|
||||
ts && !rtp_session->jb && ts == rtp_session->last_cng_ts) {
|
||||
/* we already sent this frame..... */
|
||||
*bytes = 0;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (*bytes) {
|
||||
rtp_session->stats.inbound.raw_bytes += *bytes;
|
||||
@@ -2091,12 +2194,15 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
|
||||
rtp_session->stats.inbound.packet_count++;
|
||||
}
|
||||
|
||||
|
||||
if ((rtp_session->recv_te && rtp_session->recv_msg.header.pt == rtp_session->recv_te) ||
|
||||
*bytes < rtp_header_len ||
|
||||
(*bytes < rtp_header_len && *bytes > 0) ||
|
||||
switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) || switch_test_flag(rtp_session, SWITCH_RTP_FLAG_UDPTL)) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
rtp_session->last_read_ts = ts;
|
||||
|
||||
if (rtp_session->jb && rtp_session->recv_msg.header.version == 2 && *bytes) {
|
||||
if (rtp_session->recv_msg.header.m && rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
|
||||
@@ -2104,26 +2210,29 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
|
||||
stfu_n_reset(rtp_session->jb);
|
||||
}
|
||||
|
||||
stfu_n_eat(rtp_session->jb, ntohl(rtp_session->recv_msg.header.ts), rtp_session->recv_msg.header.pt,
|
||||
rtp_session->recv_msg.body, *bytes - rtp_header_len);
|
||||
stfu_n_eat(rtp_session->jb, rtp_session->last_read_ts,
|
||||
rtp_session->recv_msg.header.pt,
|
||||
rtp_session->recv_msg.body, *bytes - rtp_header_len, rtp_session->timer.samplecount);
|
||||
*bytes = 0;
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (rtp_session->jb) {
|
||||
if (rtp_session->jb && !rtp_session->checked_jb) {
|
||||
if ((jb_frame = stfu_n_read_a_frame(rtp_session->jb))) {
|
||||
memcpy(rtp_session->recv_msg.body, jb_frame->data, jb_frame->dlen);
|
||||
|
||||
if (jb_frame->plc) {
|
||||
*flags |= SFF_PLC;
|
||||
(*flags) |= SFF_PLC;
|
||||
} else {
|
||||
rtp_session->stats.inbound.jb_packet_count++;
|
||||
}
|
||||
*bytes = jb_frame->dlen + rtp_header_len;
|
||||
rtp_session->recv_msg.header.ts = htonl(jb_frame->ts);
|
||||
rtp_session->recv_msg.header.pt = jb_frame->pt;
|
||||
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
rtp_session->checked_jb++;
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -2268,6 +2377,8 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
||||
|
||||
READ_INC(rtp_session);
|
||||
|
||||
rtp_session->checked_jb = 0;
|
||||
|
||||
while (switch_rtp_ready(rtp_session)) {
|
||||
int do_cng = 0;
|
||||
bytes = 0;
|
||||
@@ -2277,7 +2388,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
||||
rtp_session->read_pollfd) {
|
||||
if (switch_poll(rtp_session->read_pollfd, 1, &fdr, 0) == SWITCH_STATUS_SUCCESS) {
|
||||
rtp_session->hot_hits += rtp_session->samples_per_interval;
|
||||
|
||||
|
||||
if (rtp_session->hot_hits >= rtp_session->samples_per_second * 5) {
|
||||
switch_set_flag(rtp_session, SWITCH_RTP_FLAG_FLUSH);
|
||||
hot_socket = 1;
|
||||
@@ -2819,10 +2930,11 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
||||
|
||||
if (do_cng) {
|
||||
uint8_t *data = (uint8_t *) rtp_session->recv_msg.body;
|
||||
int fdr;
|
||||
|
||||
if ((poll_status = switch_poll(rtp_session->read_pollfd, 1, &fdr, 0)) == SWITCH_STATUS_SUCCESS) {
|
||||
goto recvfrom;
|
||||
if (rtp_session->last_cng_ts == rtp_session->last_read_ts + rtp_session->samples_per_interval) {
|
||||
rtp_session->last_cng_ts = 0;
|
||||
} else {
|
||||
rtp_session->last_cng_ts = rtp_session->last_read_ts + rtp_session->samples_per_interval;
|
||||
}
|
||||
|
||||
memset(data, 0, 2);
|
||||
@@ -3053,6 +3165,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp
|
||||
frame->packet = &rtp_session->recv_msg;
|
||||
frame->packetlen = bytes;
|
||||
frame->source = __FILE__;
|
||||
|
||||
switch_set_flag(frame, SFF_RAW_RTP);
|
||||
if (frame->payload == rtp_session->recv_te) {
|
||||
switch_set_flag(frame, SFF_RFC2833);
|
||||
|
||||
+5
-1
@@ -213,9 +213,13 @@ SWITCH_DECLARE(void) switch_time_calibrate_clock(void)
|
||||
}
|
||||
|
||||
if (res > 1500) {
|
||||
STEP_MS = res / 1000;
|
||||
STEP_MIC = res;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||
"Timer resolution of %ld microseconds detected!\n"
|
||||
"Do you have your kernel timer frequency set to lower than 1,000Hz? You may experience audio problems.\n", ts.tv_nsec / 1000);
|
||||
"Do you have your kernel timer frequency set to lower than 1,000Hz? "
|
||||
"You may experience audio problems. Step MS %d\n", ts.tv_nsec / 1000, STEP_MS);
|
||||
do_sleep(5000000);
|
||||
switch_time_set_cond_yield(SWITCH_TRUE);
|
||||
return;
|
||||
|
||||
+7
-3
@@ -831,9 +831,9 @@ SWITCH_DECLARE(char *) switch_strip_whitespace(const char *str)
|
||||
return s;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(char *) switch_strip_spaces(const char *str)
|
||||
SWITCH_DECLARE(char *) switch_strip_spaces(char *str, switch_bool_t dup)
|
||||
{
|
||||
const char *sp = str;
|
||||
char *sp = str;
|
||||
char *p, *s = NULL;
|
||||
|
||||
if (!sp)
|
||||
@@ -843,7 +843,11 @@ SWITCH_DECLARE(char *) switch_strip_spaces(const char *str)
|
||||
sp++;
|
||||
}
|
||||
|
||||
s = strdup(sp);
|
||||
if (dup) {
|
||||
s = strdup(sp);
|
||||
} else {
|
||||
s = sp;
|
||||
}
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
Reference in new issue
Block a user