mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-23 04:31:50 +00:00
Merge branch 'master' into v1.4.beta
Conflicts: configure.in
This commit is contained in:
+12
-4
@@ -3,9 +3,17 @@ SUBDIRS = . src
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
NAME = freeswitch
|
||||
|
||||
AM_LIBAPR_CFLAGS := $(shell ./libs/apr/apr-1-config --cflags)
|
||||
AM_LIBAPR_CPPFLAGS := $(shell ./libs/apr/apr-1-config --cppflags --includes)
|
||||
AM_LIBAPR_LDFLAGS := $(shell ./libs/apr/apr-1-config --ldflags)
|
||||
AM_LIBAPR_LIBS := $(subst $(CURDIR)/,,$(shell ./libs/apr/apr-1-config \--link-libtool \--libs))
|
||||
AM_LIBAPU_CPPFLAGS := $(shell ./libs/apr-util/apu-1-config --includes)
|
||||
AM_LIBAPU_LDFLAGS := $(shell ./libs/apr-util/apu-1-config --ldflags)
|
||||
AM_LIBAPU_LIBS := $(subst $(CURDIR)/,,$(shell ./libs/apr-util/apu-1-config \--link-libtool \--libs))
|
||||
|
||||
AM_CFLAGS = $(SWITCH_AM_CFLAGS) $(SWITCH_ANSI_CFLAGS)
|
||||
AM_CPPFLAGS = $(SWITCH_AM_CXXFLAGS) -Ilibs/sofia-sip/libsofia-sip-ua/sdp -Ilibs/sofia-sip/libsofia-sip-ua/su
|
||||
AM_LDFLAGS = $(SWITCH_AM_LDFLAGS)
|
||||
AM_LDFLAGS = $(SWITCH_AM_LDFLAGS) $(AM_LIBAPR_LDFLAGS) $(AM_LIBAPU_LDFLAGS)
|
||||
|
||||
DEFAULT_SOUNDS=en-us-callie-8000
|
||||
|
||||
@@ -101,8 +109,8 @@ $(RECURSIVE_TARGETS): freeswitch
|
||||
exit 1; \
|
||||
fi ;
|
||||
|
||||
CORE_CFLAGS = `$(switch_builddir)/libs/apr/apr-1-config --cflags --cppflags --includes`
|
||||
CORE_CFLAGS += `$(switch_builddir)/libs/apr-util/apu-1-config --includes`
|
||||
CORE_CFLAGS = $(AM_LIBAPR_CFLAGS) $(AM_LIBAPR_CPPFLAGS)
|
||||
CORE_CFLAGS += $(AM_LIBAPU_CPPFLAGS)
|
||||
CORE_CFLAGS += -I$(switch_srcdir)/libs/libtpl-1.5/src
|
||||
CORE_CFLAGS += -I$(switch_srcdir)/libs/stfu
|
||||
CORE_CFLAGS += -I$(switch_builddir)/libs/sqlite
|
||||
@@ -112,7 +120,7 @@ CORE_CFLAGS += -I$(switch_srcdir)/libs/srtp/include
|
||||
CORE_CFLAGS += -I$(switch_srcdir)/libs/srtp/crypto/include -Ilibs/srtp/crypto/include
|
||||
CORE_CFLAGS += -I$(switch_srcdir)/libs/spandsp/src -I$(switch_srcdir)/libs/tiff-4.0.2/libtiff
|
||||
|
||||
CORE_LIBS = libs/apr-util/libaprutil-1.la libs/apr/libapr-1.la
|
||||
CORE_LIBS = $(AM_LIBAPU_LIBS) $(AM_LIBAPR_LIBS)
|
||||
CORE_LIBS += libs/sqlite/libsqlite3.la libs/pcre/libpcre.la libs/speex/libspeex/libspeexdsp.la
|
||||
|
||||
if ENABLE_SRTP
|
||||
|
||||
@@ -6,7 +6,6 @@ m4_include([build/config/ac_gcc_archflag.m4])
|
||||
m4_include([build/config/ac_gcc_x86_cpuid.m4])
|
||||
m4_include([build/config/ax_lib_mysql.m4])
|
||||
m4_include([build/config/ax_check_java.m4])
|
||||
m4_include([build/config/uuid.m4])
|
||||
m4_include([build/config/erlang.m4])
|
||||
m4_include([build/config/odbc.m4])
|
||||
m4_include([build/config/sched_setaffinity.m4])
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
AC_DEFUN([CHECK_LIBUUID],
|
||||
[
|
||||
PKG_CHECK_MODULES([LIBUUID], [uuid >= 1.41.2],
|
||||
[LIBUUID_FOUND=yes], [LIBUUID_FOUND=no])
|
||||
if test "$LIBUUID_FOUND" = "no" ; then
|
||||
PKG_CHECK_MODULES([LIBUUID], [uuid],
|
||||
[LIBUUID_FOUND=yes], [LIBUUID_FOUND=no])
|
||||
if test "$LIBUUID_FOUND" = "no" ; then
|
||||
AC_MSG_WARN([libuuid development package highly recommended!])
|
||||
else
|
||||
LIBUUID_INCLUDEDIR=$(pkg-config --variable=includedir uuid)
|
||||
LIBUUID_CFLAGS+=" -I$LIBUUID_INCLUDEDIR/uuid "
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([LIBUUID_CFLAGS])
|
||||
AC_SUBST([LIBUUID_LIBS])
|
||||
])
|
||||
@@ -16,6 +16,12 @@
|
||||
<param name="default-recognizer" value="pocketsphinx"/>
|
||||
</input>
|
||||
|
||||
<!-- receivefax component params -->
|
||||
<receivefax>
|
||||
<!-- where to store incoming faxes -->
|
||||
<param name="file-prefix" value="/tmp/"/>
|
||||
</receivefax>
|
||||
|
||||
<!-- XMPP server domain -->
|
||||
<domain name="$${rayo_domain_name}" shared-secret="ClueCon">
|
||||
<!-- use this instead if you want secure XMPP client to server connections. Put .crt and .key file in freeswitch/certs -->
|
||||
@@ -65,6 +71,7 @@
|
||||
<alias name="speed-down" target="output"><![CDATA[<speed-down xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
|
||||
<alias name="volume-up" target="output"><![CDATA[<volume-up xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
|
||||
<alias name="volume-down" target="output"><![CDATA[<volume-down xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
|
||||
<alias name="receivefax" target="call"><![CDATA[<receivefax xmlns="urn:xmpp:rayo:fax:1"/>]]></alias>
|
||||
<alias name="record" target="call"><![CDATA[<record xmlns="urn:xmpp:rayo:record:1"/>]]></alias>
|
||||
<alias name="record_pause" target="record"><![CDATA[<pause xmlns="urn:xmpp:rayo:record:1"/>]]></alias>
|
||||
<alias name="record_resume" target="record"><![CDATA[<resume xmlns="urn:xmpp:rayo:record:1"/>]]></alias>
|
||||
|
||||
@@ -412,10 +412,6 @@ if test "x$enable_core_odbc_support" != "xno"; then
|
||||
AC_CHECK_LIB([odbc], [SQLDisconnect],, AC_MSG_ERROR([no usable libodbc; please install unixodbc devel package or equivalent]))
|
||||
fi
|
||||
|
||||
CHECK_LIBUUID
|
||||
SWITCH_AM_LDFLAGS="$LIBUUID_LIBS $SWITCH_AM_LDFLAGS"
|
||||
SWITCH_AM_CFLAGS="$LIBUUID_CFLAGS $SWITCH_AM_CFLAGS"
|
||||
|
||||
AC_ARG_ENABLE(core-pgsql-support,
|
||||
[AS_HELP_STRING([--enable-core-pgsql-support], [Compile with PGSQL Support])],,[enable_core_pgsql_support="no"])
|
||||
AC_ARG_ENABLE(core-pgsql-pkgconfig,
|
||||
|
||||
@@ -789,11 +789,16 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
|
||||
len = tech_pvt->read_frame.buflen;
|
||||
if (ftdm_channel_read(tech_pvt->ftdmchan, tech_pvt->read_frame.data, &len) != FTDM_SUCCESS) {
|
||||
if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Failed to read from dead channel %s device %d:%d\n", name, span_id, chan_id);
|
||||
goto normal_failure;
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_WARNING, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
if (++tech_pvt->read_error > FTDM_MAX_READ_WRITE_ERRORS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "too many I/O read errors on channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
} else {
|
||||
tech_pvt->read_error = 0;
|
||||
}
|
||||
@@ -822,6 +827,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
|
||||
fail:
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "clearing IO in channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
normal_failure:
|
||||
switch_clear_flag_locked(tech_pvt, TFLAG_IO);
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
@@ -291,13 +291,23 @@ static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(analog_em_set_channel_sig_status)
|
||||
return FTDM_FAIL;
|
||||
case FTDM_SIG_STATE_SUSPENDED:
|
||||
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) {
|
||||
int cas_bits = 0xFF;
|
||||
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED);
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_CAS_BITS, &cas_bits);
|
||||
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
|
||||
}
|
||||
ftdm_analog_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_SUSPENDED);
|
||||
}
|
||||
break;
|
||||
case FTDM_SIG_STATE_UP:
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) {
|
||||
int cas_bits = 0x00;
|
||||
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED);
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_CAS_BITS, &cas_bits);
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
|
||||
}
|
||||
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) {
|
||||
ftdm_analog_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP);
|
||||
}
|
||||
@@ -643,7 +653,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||
case FTDM_CHANNEL_STATE_RING:
|
||||
{
|
||||
ftdm_sleep(interval);
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_UP && cas_answer) {
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_UP) {
|
||||
cas_bits = 0;
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_CAS_BITS, &cas_bits);
|
||||
if (!(state_counter % 5000)) {
|
||||
|
||||
@@ -951,6 +951,21 @@ static FIO_GET_ALARMS_FUNCTION(zt_get_alarms)
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
#define ftdm_zt_set_event_pending(fchan) \
|
||||
do { \
|
||||
ftdm_set_io_flag(fchan, FTDM_CHANNEL_IO_EVENT); \
|
||||
fchan->last_event_time = ftdm_current_time_in_ms(); \
|
||||
} while (0);
|
||||
|
||||
#define ftdm_zt_store_chan_event(fchan, revent) \
|
||||
do { \
|
||||
if (fchan->io_data) { \
|
||||
ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Dropping event %d, not retrieved on time\n", revent); \
|
||||
} \
|
||||
fchan->io_data = (void *)zt_event_id; \
|
||||
ftdm_zt_set_event_pending(fchan); \
|
||||
} while (0);
|
||||
|
||||
/**
|
||||
* \brief Waits for an event on a Zaptel/DAHDI channel
|
||||
* \param ftdmchan Channel to open
|
||||
@@ -1015,7 +1030,7 @@ pollagain:
|
||||
*flags |= FTDM_WRITE;
|
||||
}
|
||||
|
||||
if (inflags & POLLPRI) {
|
||||
if ((inflags & POLLPRI) || (ftdmchan->io_data && (*flags & FTDM_EVENTS))) {
|
||||
*flags |= FTDM_EVENTS;
|
||||
}
|
||||
|
||||
@@ -1044,19 +1059,28 @@ FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
|
||||
j++;
|
||||
}
|
||||
|
||||
r = poll(pfds, j, ms);
|
||||
r = poll(pfds, j, ms);
|
||||
|
||||
if (r == 0) {
|
||||
return FTDM_TIMEOUT;
|
||||
} else if (r < 0 || (pfds[i-1].revents & POLLERR)) {
|
||||
} else if (r < 0) {
|
||||
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
for(i = 1; i <= span->chan_count; i++) {
|
||||
if (pfds[i-1].revents & POLLPRI) {
|
||||
ftdm_set_io_flag(span->channels[i], FTDM_CHANNEL_IO_EVENT);
|
||||
span->channels[i]->last_event_time = ftdm_current_time_in_ms();
|
||||
|
||||
ftdm_channel_lock(span->channels[i]);
|
||||
|
||||
if (pfds[i-1].revents & POLLERR) {
|
||||
ftdm_log_chan(span->channels[i], FTDM_LOG_ERROR, "POLLERR, flags=%d\n", pfds[i-1].events);
|
||||
|
||||
ftdm_channel_unlock(span->channels[i]);
|
||||
|
||||
continue;
|
||||
}
|
||||
if ((pfds[i-1].revents & POLLPRI) || (span->channels[i]->io_data)) {
|
||||
ftdm_zt_set_event_pending(span->channels[i]);
|
||||
k++;
|
||||
}
|
||||
if (pfds[i-1].revents & POLLIN) {
|
||||
@@ -1065,6 +1089,9 @@ FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
|
||||
if (pfds[i-1].revents & POLLOUT) {
|
||||
ftdm_set_io_flag(span->channels[i], FTDM_CHANNEL_IO_WRITE);
|
||||
}
|
||||
|
||||
ftdm_channel_unlock(span->channels[i]);
|
||||
|
||||
}
|
||||
|
||||
if (!k) {
|
||||
@@ -1243,7 +1270,10 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event)
|
||||
ftdm_clear_io_flag(ftdmchan, FTDM_CHANNEL_IO_EVENT);
|
||||
}
|
||||
|
||||
if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
|
||||
if (ftdmchan->io_data) {
|
||||
zt_event_id = (zt_event_t)ftdmchan->io_data;
|
||||
ftdmchan->io_data = NULL;
|
||||
} else if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event from channel: %s\n",
|
||||
strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
@@ -1274,30 +1304,48 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
|
||||
uint32_t i, event_id = FTDM_OOB_INVALID;
|
||||
zt_event_t zt_event_id = 0;
|
||||
|
||||
for(i = 1; i <= span->chan_count; i++) {
|
||||
for (i = 1; i <= span->chan_count; i++) {
|
||||
ftdm_channel_t *fchan = span->channels[i];
|
||||
if (ftdm_test_io_flag(fchan, FTDM_CHANNEL_IO_EVENT)) {
|
||||
ftdm_clear_io_flag(fchan, FTDM_CHANNEL_IO_EVENT);
|
||||
if (ioctl(fchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
|
||||
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
ftdm_channel_lock(fchan);
|
||||
if ((zt_channel_process_event(fchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to process DAHDI event %d from channel\n", zt_event_id);
|
||||
ftdm_channel_unlock(fchan);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
ftdm_channel_lock(fchan);
|
||||
|
||||
if (!ftdm_test_io_flag(fchan, FTDM_CHANNEL_IO_EVENT)) {
|
||||
|
||||
ftdm_channel_unlock(fchan);
|
||||
|
||||
fchan->last_event_time = 0;
|
||||
span->event_header.e_type = FTDM_EVENT_OOB;
|
||||
span->event_header.enum_id = event_id;
|
||||
span->event_header.channel = fchan;
|
||||
*event = &span->event_header;
|
||||
return FTDM_SUCCESS;
|
||||
continue;
|
||||
}
|
||||
|
||||
ftdm_clear_io_flag(fchan, FTDM_CHANNEL_IO_EVENT);
|
||||
|
||||
if (fchan->io_data) {
|
||||
zt_event_id = (zt_event_t)fchan->io_data;
|
||||
fchan->io_data = NULL;
|
||||
} else if (ioctl(fchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to retrieve DAHDI event from channel: %s\n", strerror(errno));
|
||||
|
||||
ftdm_channel_unlock(fchan);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((zt_channel_process_event(fchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to process DAHDI event %d from channel\n", zt_event_id);
|
||||
|
||||
ftdm_channel_unlock(fchan);
|
||||
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
fchan->last_event_time = 0;
|
||||
span->event_header.e_type = FTDM_EVENT_OOB;
|
||||
span->event_header.enum_id = event_id;
|
||||
span->event_header.channel = fchan;
|
||||
*event = &span->event_header;
|
||||
|
||||
ftdm_channel_unlock(fchan);
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
return FTDM_FAIL;
|
||||
@@ -1348,11 +1396,13 @@ static FIO_READ_FUNCTION(zt_read)
|
||||
}
|
||||
|
||||
if (handle_dtmf_event(ftdmchan, zt_event_id)) {
|
||||
/* we should enqueue this event somewhere so it can be retrieved by the user, for now, dropping it to see what it is! */
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Event %d is not dmtf related. Skipping one media read cycle\n", zt_event_id);
|
||||
/* Enqueue this event for later */
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Deferring event %d to be able to read data\n", zt_event_id);
|
||||
ftdm_zt_store_chan_event(ftdmchan, zt_event_id);
|
||||
} else {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Skipping one IO read cycle due to DTMF event processing\n");
|
||||
}
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Skipping one IO read cycle due to events pending in the driver queue\n");
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read error, keep going unless to many errors force us to abort ...*/
|
||||
@@ -1405,8 +1455,9 @@ tryagain:
|
||||
}
|
||||
|
||||
if (handle_dtmf_event(ftdmchan, zt_event_id)) {
|
||||
/* we should enqueue this event somewhere so it can be retrieved by the user, for now, dropping it to see what it is! */
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dropping event %d to be able to write data\n", zt_event_id);
|
||||
/* Enqueue this event for later */
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Deferring event %d to be able to write data\n", zt_event_id);
|
||||
ftdm_zt_store_chan_event(ftdmchan, zt_event_id);
|
||||
}
|
||||
|
||||
goto tryagain;
|
||||
|
||||
@@ -71,7 +71,7 @@ AC_PROG_GCC_TRADITIONAL
|
||||
#AC_FUNC_REALLOC
|
||||
AC_TYPE_SIGNAL
|
||||
AC_FUNC_STAT
|
||||
AC_CHECK_FUNCS([endpwent isascii memchr memset re_comp regcomp strcasecmp strchr strcspn strdup strerror strrchr strstr strtol issetugid])
|
||||
AC_CHECK_FUNCS([endpwent isascii memchr memset re_comp regcomp strcasecmp strchr strlcat strlcpy strcspn strdup strerror strrchr strstr strtol issetugid])
|
||||
EL_GETPW_R_POSIX
|
||||
EL_GETPW_R_DRAFT
|
||||
|
||||
|
||||
@@ -178,6 +178,7 @@ struct switch_core_session {
|
||||
switch_size_t recur_buffer_len;
|
||||
|
||||
switch_media_handle_t *media_handle;
|
||||
uint32_t decoder_errors;
|
||||
};
|
||||
|
||||
struct switch_media_bug {
|
||||
|
||||
@@ -68,7 +68,6 @@ typedef enum {
|
||||
SCMF_RUNNING,
|
||||
SCMF_DISABLE_TRANSCODING,
|
||||
SCMF_AUTOFIX_TIMING,
|
||||
SCMF_AUTOFIX_PT,
|
||||
SCMF_CODEC_GREEDY,
|
||||
SCMF_CODEC_SCROOGE,
|
||||
SCMF_DISABLE_HOLD,
|
||||
@@ -81,6 +80,8 @@ typedef enum {
|
||||
SCMF_AUTOFLUSH,
|
||||
SCMF_REWRITE_TIMESTAMPS,
|
||||
SCMF_RTP_AUTOFLUSH_DURING_BRIDGE,
|
||||
SCMF_MULTI_ANSWER_AUDIO,
|
||||
SCMF_MULTI_ANSWER_VIDEO,
|
||||
SCMF_MAX
|
||||
} switch_core_media_flag_t;
|
||||
|
||||
@@ -156,6 +157,53 @@ typedef struct switch_core_media_params_s {
|
||||
|
||||
} switch_core_media_params_t;
|
||||
|
||||
typedef struct xpayload_map_s {
|
||||
uint32_t pt;
|
||||
uint32_t send_pt;
|
||||
uint32_t rate;
|
||||
uint32_t ptime;
|
||||
switch_media_type_t type;
|
||||
uint8_t negotiated;
|
||||
char *name;
|
||||
switch_sdp_type_t sdp_type;
|
||||
unsigned long hash;
|
||||
struct xpayload_map_s *next;
|
||||
} xpayload_map_t;
|
||||
|
||||
typedef struct payload_map_s {
|
||||
switch_media_type_t type;
|
||||
switch_sdp_type_t sdp_type;
|
||||
uint32_t ptime;
|
||||
uint32_t rate;
|
||||
uint8_t allocated;
|
||||
uint8_t negotiated;
|
||||
unsigned long hash;
|
||||
|
||||
char *rm_encoding;
|
||||
char *iananame;
|
||||
switch_payload_t pt;
|
||||
unsigned long rm_rate;
|
||||
unsigned long adv_rm_rate;
|
||||
uint32_t codec_ms;
|
||||
uint32_t bitrate;
|
||||
|
||||
char *rm_fmtp;
|
||||
|
||||
switch_payload_t agreed_pt;
|
||||
switch_payload_t recv_pt;
|
||||
|
||||
char *fmtp_out;
|
||||
|
||||
char *remote_sdp_ip;
|
||||
switch_port_t remote_sdp_port;
|
||||
|
||||
int channels;
|
||||
int adv_channels;
|
||||
|
||||
struct payload_map_s *next;
|
||||
|
||||
} payload_map_t;
|
||||
|
||||
static inline const char *switch_media_type2str(switch_media_type_t type)
|
||||
{
|
||||
switch(type) {
|
||||
@@ -216,7 +264,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_media_ext_address_lookup(switch_core_session_t *session, char **ip, switch_port_t *port, const char *sourceip);
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_media_process_t38_passthru(switch_core_session_t *session,
|
||||
switch_core_session_t *other_session, switch_t38_options_t *t38_options);
|
||||
SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *session, const char *ip, switch_port_t port, const char *sr, int force);
|
||||
SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *session, switch_sdp_type_t sdp_type,
|
||||
const char *ip, switch_port_t port, const char *sr, int force);
|
||||
SWITCH_DECLARE(void)switch_core_media_set_local_sdp(switch_core_session_t *session, const char *sdp_str, switch_bool_t dup);
|
||||
SWITCH_DECLARE(void) switch_core_media_patch_sdp(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(void) switch_core_media_set_udptl_image_sdp(switch_core_session_t *session, switch_t38_options_t *t38_options, int insist);
|
||||
@@ -232,7 +281,6 @@ SWITCH_DECLARE(void) switch_core_media_kill_socket(switch_core_session_t *sessio
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_media_queue_rfc2833(switch_core_session_t *session, switch_media_type_t type, const switch_dtmf_t *dtmf);
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_media_queue_rfc2833_in(switch_core_session_t *session, switch_media_type_t type, const switch_dtmf_t *dtmf);
|
||||
SWITCH_DECLARE(uint8_t) switch_core_media_ready(switch_core_session_t *session, switch_media_type_t type);
|
||||
SWITCH_DECLARE(void) switch_core_media_set_recv_pt(switch_core_session_t *session, switch_media_type_t type, switch_payload_t pt);
|
||||
SWITCH_DECLARE(void) switch_core_media_set_telephony_event(switch_core_session_t *session, switch_media_type_t type, switch_payload_t te);
|
||||
SWITCH_DECLARE(void) switch_core_media_set_telephony_recv_event(switch_core_session_t *session, switch_media_type_t type, switch_payload_t te);
|
||||
SWITCH_DECLARE(switch_rtp_stats_t *) switch_core_media_stats(switch_core_session_t *session, switch_media_type_t type, switch_memory_pool_t *pool);
|
||||
@@ -257,6 +305,14 @@ SWITCH_DECLARE(void) switch_core_media_deinit(void);
|
||||
SWITCH_DECLARE(void) switch_core_media_set_stats(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(void) switch_core_session_wake_video_thread(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(void) switch_core_session_clear_crypto(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_session_t *session,
|
||||
switch_media_type_t type,
|
||||
const char *name,
|
||||
switch_sdp_type_t sdp_type,
|
||||
uint32_t pt,
|
||||
uint32_t rate,
|
||||
uint32_t ptime,
|
||||
uint8_t negotiated);
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#endif
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#define SWITCH_FRAME_H
|
||||
|
||||
#include <switch.h>
|
||||
#include <switch_core_media.h>
|
||||
|
||||
SWITCH_BEGIN_EXTERN_C
|
||||
/*! \brief An abstraction of a data frame */
|
||||
@@ -71,6 +72,7 @@ SWITCH_BEGIN_EXTERN_C
|
||||
/*! frame flags */
|
||||
switch_frame_flag_t flags;
|
||||
void *user_data;
|
||||
payload_map_t *pmap;
|
||||
};
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
|
||||
@@ -485,7 +485,6 @@ SWITCH_DECLARE(void) switch_rtp_set_private(switch_rtp_t *rtp_session, void *pri
|
||||
*/
|
||||
SWITCH_DECLARE(void) switch_rtp_set_telephony_event(switch_rtp_t *rtp_session, switch_payload_t te);
|
||||
SWITCH_DECLARE(void) switch_rtp_set_telephony_recv_event(switch_rtp_t *rtp_session, switch_payload_t te);
|
||||
SWITCH_DECLARE(void) switch_rtp_set_recv_pt(switch_rtp_t *rtp_session, switch_payload_t pt);
|
||||
|
||||
/*!
|
||||
\brief Set the payload type for comfort noise
|
||||
@@ -500,7 +499,7 @@ SWITCH_DECLARE(void) switch_rtp_set_cng_pt(switch_rtp_t *rtp_session, switch_pay
|
||||
\return the pointer to the private data
|
||||
*/
|
||||
SWITCH_DECLARE(void *) switch_rtp_get_private(switch_rtp_t *rtp_session);
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_set_payload_map(switch_rtp_t *rtp_session, payload_map_t **pmap);
|
||||
SWITCH_DECLARE(void) switch_rtp_intentional_bugs(switch_rtp_t *rtp_session, switch_rtp_bug_flag_t bugs);
|
||||
|
||||
SWITCH_DECLARE(switch_rtp_stats_t *) switch_rtp_get_stats(switch_rtp_t *rtp_session, switch_memory_pool_t *pool);
|
||||
|
||||
@@ -1929,40 +1929,91 @@ SWITCH_STANDARD_API(cond_function)
|
||||
}
|
||||
|
||||
a = argv[0];
|
||||
while(*a == ' ' || *a == '\t') a++;
|
||||
|
||||
if ((expr = strchr(a, '!'))) {
|
||||
*expr++ = '\0';
|
||||
if (*expr == '=') {
|
||||
o = O_NE;
|
||||
}
|
||||
} else if ((expr = strchr(a, '>'))) {
|
||||
if (*(expr + 1) == '=') {
|
||||
if (*a == '\'') {
|
||||
if ((expr = switch_find_end_paren(a, '\'', '\''))) {
|
||||
a++;
|
||||
*expr++ = '\0';
|
||||
o = O_GE;
|
||||
} else {
|
||||
o = O_GT;
|
||||
goto error;
|
||||
}
|
||||
} else if ((expr = strchr(a, '<'))) {
|
||||
if (*(expr + 1) == '=') {
|
||||
} else {
|
||||
if ((expr = strchr(a, ' '))) {
|
||||
*expr++ = '\0';
|
||||
o = O_LE;
|
||||
} else {
|
||||
o = O_LT;
|
||||
}
|
||||
} else if ((expr = strchr(a, '='))) {
|
||||
*expr++ = '\0';
|
||||
if (*expr == '=') {
|
||||
o = O_EQ;
|
||||
expr = a;
|
||||
}
|
||||
}
|
||||
|
||||
while(expr && *expr) {
|
||||
switch(*expr) {
|
||||
case '!':
|
||||
case '<':
|
||||
case '>':
|
||||
case '=':
|
||||
goto done;
|
||||
default:
|
||||
expr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
switch(*expr) {
|
||||
case '!':
|
||||
*expr++ = '\0';
|
||||
if (*expr == '=') {
|
||||
o = O_NE;
|
||||
*expr++ = '\0';
|
||||
}
|
||||
break;
|
||||
|
||||
case '>':
|
||||
*expr++ = '\0';
|
||||
if (*expr == '=') {
|
||||
o = O_GE;
|
||||
*expr++ = '\0';
|
||||
} else {
|
||||
o = O_GT;
|
||||
}
|
||||
break;
|
||||
|
||||
case '<':
|
||||
*expr++ = '\0';
|
||||
if (*expr == '=') {
|
||||
o = O_LE;
|
||||
*expr++ = '\0';
|
||||
} else {
|
||||
o = O_LT;
|
||||
}
|
||||
break;
|
||||
|
||||
case '=':
|
||||
*expr++ = '\0';
|
||||
if (*expr == '=') {
|
||||
o = O_EQ;
|
||||
*expr++ = '\0';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
if (o) {
|
||||
char *s_a = NULL, *s_b = NULL;
|
||||
int a_is_num, b_is_num;
|
||||
*expr++ = '\0';
|
||||
|
||||
expr++;
|
||||
b = expr;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -184,7 +184,8 @@ typedef enum {
|
||||
MFLAG_NOMOH = (1 << 19),
|
||||
MFLAG_VIDEO_BRIDGE = (1 << 20),
|
||||
MFLAG_INDICATE_MUTE_DETECT = (1 << 21),
|
||||
MFLAG_PAUSE_RECORDING = (1 << 22)
|
||||
MFLAG_PAUSE_RECORDING = (1 << 22),
|
||||
MFLAG_ACK_VIDEO = (1 << 23)
|
||||
} member_flag_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -1796,6 +1797,10 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
|
||||
|
||||
channel = switch_core_session_get_channel(member->session);
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_VIDEO)) {
|
||||
switch_set_flag_locked(member, MFLAG_ACK_VIDEO);
|
||||
}
|
||||
|
||||
switch_channel_set_variable_printf(channel, "conference_member_id", "%d", member->id);
|
||||
switch_channel_set_variable_printf(channel, "conference_moderator", "%s", switch_test_flag(member, MFLAG_MOD) ? "true" : "false");
|
||||
switch_channel_set_variable(channel, "conference_recording", conference->record_filename);
|
||||
@@ -2595,6 +2600,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
|
||||
char *rfile = switch_channel_expand_variables(channel, conference->auto_record);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Auto recording file: %s\n", rfile);
|
||||
launch_conference_record_thread(conference, rfile, SWITCH_TRUE);
|
||||
|
||||
if (rfile != conference->auto_record) {
|
||||
conference->record_filename = switch_core_strdup(conference->pool, rfile);
|
||||
switch_safe_free(rfile);
|
||||
@@ -3639,6 +3645,12 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
|
||||
break;
|
||||
}
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_VIDEO) && !switch_test_flag(member, MFLAG_ACK_VIDEO)) {
|
||||
switch_set_flag_locked(member, MFLAG_ACK_VIDEO);
|
||||
switch_channel_clear_flag(channel, CF_VIDEO_ECHO);
|
||||
switch_core_session_refresh_video(member->session);
|
||||
}
|
||||
|
||||
/* if we have caller digits, feed them to the parser to find an action */
|
||||
if (switch_channel_has_dtmf(channel)) {
|
||||
char dtmf[128] = "";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
BASE=../../../..
|
||||
|
||||
MONGO_CXX_DRIVER_VERSION=v1.8
|
||||
MONGO_CXX_DRIVER_VERSION=v2.4
|
||||
MONGO_CXX_DRIVER_URL=http://downloads.mongodb.org/cxx-driver
|
||||
MONGO_CXX_DRIVER_TARBALL=mongodb-linux-x86_64-$(MONGO_CXX_DRIVER_VERSION)-latest.tgz
|
||||
MONGO_CXX_DRIVER_SRC=$(BASE)/libs/mongo-cxx-driver-$(MONGO_CXX_DRIVER_VERSION)
|
||||
@@ -9,7 +9,7 @@ LIBMONGOCLIENT_A =$(MONGO_CXX_DRIVER_SRC)/libmongoclient.a
|
||||
LOCAL_SOURCES=mongo_conn.cpp
|
||||
LOCAL_OBJS=mongo_conn.o
|
||||
|
||||
LOCAL_CFLAGS=-I$(MONGO_CXX_DRIVER_SRC)/mongo
|
||||
LOCAL_CFLAGS=-I$(MONGO_CXX_DRIVER_SRC)/src
|
||||
LOCAL_LIBADD=$(LIBMONGOCLIENT_A)
|
||||
LOCAL_LDFLAGS=-lboost_thread -lboost_filesystem-mt -lboost_system-mt
|
||||
MODDIR=$(shell pwd)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
--- SConstruct.orig 2011-04-28 19:00:36.000000000 +0200
|
||||
+++ SConstruct 2011-04-28 19:01:19.000000000 +0200
|
||||
@@ -45,7 +45,7 @@
|
||||
linux = True
|
||||
--- SConstruct 2013-10-30 17:18:51.160645496 -0400
|
||||
+++ new 2013-10-30 17:22:18.790072856 -0400
|
||||
@@ -78,7 +78,7 @@
|
||||
env['DIST_ARCHIVE_SUFFIX'] = '.tgz'
|
||||
|
||||
if nix:
|
||||
- env.Append( CPPFLAGS=" -O3" )
|
||||
+ env.Append( CPPFLAGS=" -I../pcre -fPIC -O3" )
|
||||
env.Append( LIBS=["pthread"] )
|
||||
- env.Append(CCFLAGS=["-O3", "-pthread"])
|
||||
+ env.Append(CCFLAGS=["-I../pcre", "-fPIC", "-O3", "-pthread"])
|
||||
if linux:
|
||||
env.Append( LINKFLAGS=" -Wl,--as-needed -Wl,-zdefs " )
|
||||
env.Append(LINKFLAGS=["-pthread"])
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Copyright (C) 2005-2013, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
@@ -22,7 +22,7 @@
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
*
|
||||
* Tamas Cseke <cstomi.levlist@gmail.com>
|
||||
*
|
||||
* mod_mongo.cpp -- API for MongoDB
|
||||
@@ -53,7 +53,7 @@ SWITCH_STANDARD_API(mongo_mapreduce_function)
|
||||
switch_assert(ns != NULL);
|
||||
|
||||
if ((json_query = strchr(ns, DELIMITER))) {
|
||||
*json_query++ = '\0';
|
||||
*json_query++ = '\0';
|
||||
}
|
||||
|
||||
if (!zstr(ns) && !zstr(json_query)) {
|
||||
@@ -62,7 +62,7 @@ SWITCH_STANDARD_API(mongo_mapreduce_function)
|
||||
BSONObj out;
|
||||
BSONObjBuilder cmd;
|
||||
|
||||
cmd.append("mapreduce", conn->nsGetCollection(ns));
|
||||
cmd.append("mapreduce", nsGetCollection(ns));
|
||||
if (!zstr(globals.map)) {
|
||||
cmd.appendCode("map", globals.map);
|
||||
}
|
||||
@@ -79,10 +79,10 @@ SWITCH_STANDARD_API(mongo_mapreduce_function)
|
||||
|
||||
conn = mongo_connection_pool_get(globals.conn_pool);
|
||||
if (conn) {
|
||||
conn->runCommand(conn->nsGetDB(ns), cmd.done(), out);
|
||||
conn->runCommand(nsGetDB(ns), cmd.done(), out);
|
||||
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_FALSE);
|
||||
|
||||
stream->write_function(stream, "-OK\n%s\n", out.toString().c_str());
|
||||
stream->write_function(stream, "-OK\n%s\n", out.jsonString().c_str());
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR\nNo connection\n");
|
||||
}
|
||||
@@ -93,7 +93,7 @@ SWITCH_STANDARD_API(mongo_mapreduce_function)
|
||||
stream->write_function(stream, "-ERR\n%s\n", e.toString().c_str());
|
||||
}
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR\n%s\n", MAPREDUCE_SYNTAX);
|
||||
stream->write_function(stream, "-ERR\n%s\n", MAPREDUCE_SYNTAX);
|
||||
}
|
||||
|
||||
switch_safe_free(ns);
|
||||
@@ -104,50 +104,50 @@ SWITCH_STANDARD_API(mongo_mapreduce_function)
|
||||
|
||||
SWITCH_STANDARD_API(mongo_find_one_function)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
char *ns = NULL, *json_query = NULL, *json_fields = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
char *ns = NULL, *json_query = NULL, *json_fields = NULL;
|
||||
|
||||
ns = strdup(cmd);
|
||||
switch_assert(ns != NULL);
|
||||
ns = strdup(cmd);
|
||||
switch_assert(ns != NULL);
|
||||
|
||||
if ((json_query = strchr(ns, DELIMITER))) {
|
||||
*json_query++ = '\0';
|
||||
if ((json_fields = strchr(json_query, DELIMITER))) {
|
||||
*json_fields++ = '\0';
|
||||
}
|
||||
}
|
||||
if ((json_query = strchr(ns, DELIMITER))) {
|
||||
*json_query++ = '\0';
|
||||
if ((json_fields = strchr(json_query, DELIMITER))) {
|
||||
*json_fields++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (!zstr(ns) && !zstr(json_query) && !zstr(json_fields)) {
|
||||
if (!zstr(ns) && !zstr(json_query) && !zstr(json_fields)) {
|
||||
|
||||
DBClientBase *conn = NULL;
|
||||
DBClientBase *conn = NULL;
|
||||
|
||||
try {
|
||||
BSONObj query = fromjson(json_query);
|
||||
BSONObj fields = fromjson(json_fields);
|
||||
try {
|
||||
BSONObj query = fromjson(json_query);
|
||||
BSONObj fields = fromjson(json_fields);
|
||||
|
||||
conn = mongo_connection_pool_get(globals.conn_pool);
|
||||
if (conn) {
|
||||
BSONObj res = conn->findOne(ns, Query(query), &fields);
|
||||
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_FALSE);
|
||||
conn = mongo_connection_pool_get(globals.conn_pool);
|
||||
if (conn) {
|
||||
BSONObj res = conn->findOne(ns, Query(query), &fields);
|
||||
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_FALSE);
|
||||
|
||||
stream->write_function(stream, "-OK\n%s\n", res.toString().c_str());
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR\nNo connection\n");
|
||||
}
|
||||
} catch (DBException &e) {
|
||||
if (conn) {
|
||||
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_TRUE);
|
||||
}
|
||||
stream->write_function(stream, "-ERR\n%s\n", e.toString().c_str());
|
||||
}
|
||||
stream->write_function(stream, "-OK\n%s\n", res.jsonString().c_str());
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR\nNo connection\n");
|
||||
}
|
||||
} catch (DBException &e) {
|
||||
if (conn) {
|
||||
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_TRUE);
|
||||
}
|
||||
stream->write_function(stream, "-ERR\n%s\n", e.toString().c_str());
|
||||
}
|
||||
|
||||
} else {
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR\n%s\n", FIND_ONE_SYNTAX);
|
||||
}
|
||||
}
|
||||
|
||||
switch_safe_free(ns);
|
||||
switch_safe_free(ns);
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
static switch_status_t config(void)
|
||||
@@ -214,21 +214,21 @@ SWITCH_MODULE_DEFINITION(mod_mongo, mod_mongo_load, mod_mongo_shutdown, NULL);
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_mongo_load)
|
||||
{
|
||||
switch_api_interface_t *api_interface;
|
||||
switch_application_interface_t *app_interface;
|
||||
switch_api_interface_t *api_interface;
|
||||
switch_application_interface_t *app_interface;
|
||||
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
|
||||
if (config() != SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
|
||||
SWITCH_ADD_API(api_interface, "mongo_find_one", "findOne", mongo_find_one_function, FIND_ONE_SYNTAX);
|
||||
SWITCH_ADD_API(api_interface, "mongo_mapreduce", "Map/Reduce", mongo_mapreduce_function, MAPREDUCE_SYNTAX);
|
||||
if (config() != SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
SWITCH_ADD_API(api_interface, "mongo_find_one", "findOne", mongo_find_one_function, FIND_ONE_SYNTAX);
|
||||
SWITCH_ADD_API(api_interface, "mongo_mapreduce", "Map/Reduce", mongo_mapreduce_function, MAPREDUCE_SYNTAX);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_mongo_shutdown)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Copyright (C) 2005-2013, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
@@ -32,22 +32,19 @@
|
||||
#ifndef MOD_MONGO_H
|
||||
#define MOD_MONGO_H
|
||||
|
||||
#include <client/dbclient.h>
|
||||
#include <client/connpool.h>
|
||||
#include <db/json.h>
|
||||
#include <bson/bson.h>
|
||||
#include <mongo/client/dbclient.h>
|
||||
|
||||
using namespace mongo;
|
||||
|
||||
typedef struct {
|
||||
char *conn_str;
|
||||
char *conn_str;
|
||||
|
||||
switch_size_t min_connections;
|
||||
switch_size_t max_connections;
|
||||
switch_size_t size;
|
||||
switch_queue_t *connections;
|
||||
switch_mutex_t *mutex;
|
||||
switch_memory_pool_t *pool;
|
||||
switch_size_t min_connections;
|
||||
switch_size_t max_connections;
|
||||
switch_size_t size;
|
||||
switch_queue_t *connections;
|
||||
switch_mutex_t *mutex;
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
} mongo_connection_pool_t;
|
||||
|
||||
@@ -56,7 +53,7 @@ switch_status_t mongo_connection_create(DBClientBase **connection, const char *c
|
||||
void mongo_connection_destroy(DBClientBase **conn);
|
||||
|
||||
switch_status_t mongo_connection_pool_create(mongo_connection_pool_t **conn_pool, switch_size_t min_connections, switch_size_t max_connections,
|
||||
const char *conn_str);
|
||||
const char *conn_str);
|
||||
void mongo_connection_pool_destroy(mongo_connection_pool_t **conn_pool);
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Copyright (C) 2005-2013, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
@@ -42,162 +42,161 @@
|
||||
|
||||
switch_status_t mongo_connection_create(DBClientBase **connection, const char *conn_str)
|
||||
{
|
||||
DBClientBase *conn = NULL;
|
||||
string conn_string(conn_str), err_msg;
|
||||
ConnectionString cs = ConnectionString::parse(conn_string, err_msg);
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (!cs.isValid()) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't parse url: %s\n", err_msg.c_str());
|
||||
return status;
|
||||
}
|
||||
DBClientBase *conn = NULL;
|
||||
string conn_string(conn_str), err_msg;
|
||||
ConnectionString cs = ConnectionString::parse(conn_string, err_msg);
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
try {
|
||||
conn = cs.connect(err_msg);
|
||||
} catch (DBException &e) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't connect to mongo [%s]: %s\n", conn_str, err_msg.c_str());
|
||||
return status;
|
||||
}
|
||||
if (!cs.isValid()) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't parse url: %s\n", err_msg.c_str());
|
||||
return status;
|
||||
}
|
||||
|
||||
if (conn) {
|
||||
*connection = conn;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Connected to mongo [%s]\n", conn_str);
|
||||
}
|
||||
try {
|
||||
conn = cs.connect(err_msg);
|
||||
} catch (DBException &e) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't connect to mongo [%s]: %s\n", conn_str, err_msg.c_str());
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
if (conn) {
|
||||
*connection = conn;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Connected to mongo [%s]\n", conn_str);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void mongo_connection_destroy(DBClientBase **conn)
|
||||
{
|
||||
switch_assert(*conn != NULL);
|
||||
delete *conn;
|
||||
switch_assert(*conn != NULL);
|
||||
delete *conn;
|
||||
|
||||
*conn = NULL;
|
||||
*conn = NULL;
|
||||
}
|
||||
|
||||
switch_status_t mongo_connection_pool_create(mongo_connection_pool_t **conn_pool, switch_size_t min_connections, switch_size_t max_connections,
|
||||
const char *conn_str)
|
||||
const char *conn_str)
|
||||
{
|
||||
switch_memory_pool_t *pool = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
mongo_connection_pool_t *cpool = NULL;
|
||||
DBClientBase *conn = NULL;
|
||||
switch_memory_pool_t *pool = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
mongo_connection_pool_t *cpool = NULL;
|
||||
DBClientBase *conn = NULL;
|
||||
|
||||
if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!(cpool = (mongo_connection_pool_t *)switch_core_alloc(pool, sizeof(mongo_connection_pool_t)))) {
|
||||
switch_goto_status(SWITCH_STATUS_MEMERR, done);
|
||||
}
|
||||
if (!(cpool = (mongo_connection_pool_t *)switch_core_alloc(pool, sizeof(mongo_connection_pool_t)))) {
|
||||
switch_goto_status(SWITCH_STATUS_MEMERR, done);
|
||||
}
|
||||
|
||||
if ((status = switch_mutex_init(&cpool->mutex, SWITCH_MUTEX_NESTED, pool)) != SWITCH_STATUS_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
if ((status = switch_mutex_init(&cpool->mutex, SWITCH_MUTEX_NESTED, pool)) != SWITCH_STATUS_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((status = switch_queue_create(&cpool->connections, max_connections, pool)) != SWITCH_STATUS_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
if ((status = switch_queue_create(&cpool->connections, max_connections, pool)) != SWITCH_STATUS_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
cpool->min_connections = min_connections;
|
||||
cpool->max_connections = max_connections;
|
||||
cpool->conn_str = switch_core_strdup(pool, conn_str);
|
||||
|
||||
cpool->pool = pool;
|
||||
cpool->min_connections = min_connections;
|
||||
cpool->max_connections = max_connections;
|
||||
cpool->conn_str = switch_core_strdup(pool, conn_str);
|
||||
cpool->pool = pool;
|
||||
|
||||
for (cpool->size = 0; cpool->size < min_connections; cpool->size++) {
|
||||
for (cpool->size = 0; cpool->size < min_connections; cpool->size++) {
|
||||
|
||||
if (mongo_connection_create(&conn, conn_str) == SWITCH_STATUS_SUCCESS) {
|
||||
mongo_connection_pool_put(cpool, conn, SWITCH_FALSE);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mongo_connection_create(&conn, conn_str) == SWITCH_STATUS_SUCCESS) {
|
||||
mongo_connection_pool_put(cpool, conn, SWITCH_FALSE);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
*conn_pool = cpool;
|
||||
} else {
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
}
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
*conn_pool = cpool;
|
||||
} else {
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
}
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
void mongo_connection_pool_destroy(mongo_connection_pool_t **conn_pool)
|
||||
{
|
||||
mongo_connection_pool_t *cpool = *conn_pool;
|
||||
void *data = NULL;
|
||||
mongo_connection_pool_t *cpool = *conn_pool;
|
||||
void *data = NULL;
|
||||
|
||||
switch_assert(cpool != NULL);
|
||||
switch_assert(cpool != NULL);
|
||||
|
||||
while (switch_queue_trypop(cpool->connections, &data) == SWITCH_STATUS_SUCCESS) {
|
||||
mongo_connection_destroy((DBClientBase **)&data);
|
||||
}
|
||||
while (switch_queue_trypop(cpool->connections, &data) == SWITCH_STATUS_SUCCESS) {
|
||||
mongo_connection_destroy((DBClientBase **)&data);
|
||||
}
|
||||
|
||||
switch_mutex_destroy(cpool->mutex);
|
||||
switch_core_destroy_memory_pool(&cpool->pool);
|
||||
switch_mutex_destroy(cpool->mutex);
|
||||
switch_core_destroy_memory_pool(&cpool->pool);
|
||||
|
||||
*conn_pool = NULL;
|
||||
*conn_pool = NULL;
|
||||
}
|
||||
|
||||
|
||||
DBClientBase *mongo_connection_pool_get(mongo_connection_pool_t *conn_pool)
|
||||
{
|
||||
DBClientBase *conn = NULL;
|
||||
void *data = NULL;
|
||||
DBClientBase *conn = NULL;
|
||||
void *data = NULL;
|
||||
|
||||
switch_assert(conn_pool != NULL);
|
||||
switch_assert(conn_pool != NULL);
|
||||
|
||||
switch_mutex_lock(conn_pool->mutex);
|
||||
switch_mutex_lock(conn_pool->mutex);
|
||||
|
||||
if (switch_queue_trypop(conn_pool->connections, &data) == SWITCH_STATUS_SUCCESS) {
|
||||
conn = (DBClientBase *) data;
|
||||
} else if (mongo_connection_create(&conn, conn_pool->conn_str) == SWITCH_STATUS_SUCCESS) {
|
||||
if (++conn_pool->size > conn_pool->max_connections) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Connection pool is empty. You may want to increase 'max-connections'\n");
|
||||
}
|
||||
}
|
||||
if (switch_queue_trypop(conn_pool->connections, &data) == SWITCH_STATUS_SUCCESS) {
|
||||
conn = (DBClientBase *) data;
|
||||
} else if (mongo_connection_create(&conn, conn_pool->conn_str) == SWITCH_STATUS_SUCCESS) {
|
||||
if (++conn_pool->size > conn_pool->max_connections) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Connection pool is empty. You may want to increase 'max-connections'\n");
|
||||
}
|
||||
}
|
||||
|
||||
switch_mutex_unlock(conn_pool->mutex);
|
||||
switch_mutex_unlock(conn_pool->mutex);
|
||||
|
||||
#ifdef MONGO_POOL_DEBUG
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL get: size %d conn: %p\n", (int) switch_queue_size(conn_pool->connections), conn);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL get: size %d conn: %p\n", (int) switch_queue_size(conn_pool->connections), conn);
|
||||
#endif
|
||||
|
||||
return conn;
|
||||
return conn;
|
||||
}
|
||||
|
||||
switch_status_t mongo_connection_pool_put(mongo_connection_pool_t *conn_pool, DBClientBase *conn, switch_bool_t destroy)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
switch_assert(conn_pool != NULL);
|
||||
switch_assert(conn != NULL);
|
||||
switch_assert(conn_pool != NULL);
|
||||
switch_assert(conn != NULL);
|
||||
|
||||
switch_mutex_lock(conn_pool->mutex);
|
||||
if (destroy || conn_pool->size > conn_pool->max_connections) {
|
||||
switch_mutex_lock(conn_pool->mutex);
|
||||
if (destroy || conn_pool->size > conn_pool->max_connections) {
|
||||
#ifdef MONGO_POOL_DEBUG
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: Destroy connection %p\n", conn);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: Destroy connection %p\n", conn);
|
||||
#endif
|
||||
mongo_connection_destroy(&conn);
|
||||
conn_pool->size--;
|
||||
} else {
|
||||
mongo_connection_destroy(&conn);
|
||||
conn_pool->size--;
|
||||
} else {
|
||||
#ifdef MONGO_POOL_DEBUG
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: push connection %p\n", conn);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: push connection %p\n", conn);
|
||||
#endif
|
||||
status = switch_queue_push(conn_pool->connections, conn);
|
||||
}
|
||||
status = switch_queue_push(conn_pool->connections, conn);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(conn_pool->mutex);
|
||||
switch_mutex_unlock(conn_pool->mutex);
|
||||
|
||||
#ifdef MONGO_POOL_DEBUG
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: put size %d conn: %p\n", (int) switch_queue_size(conn_pool->connections), conn);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: put size %d conn: %p\n", (int) switch_queue_size(conn_pool->connections), conn);
|
||||
#endif
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
|
||||
@@ -36,35 +36,229 @@
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load);
|
||||
SWITCH_MODULE_DEFINITION(mod_opus, mod_opus_load, NULL, NULL);
|
||||
|
||||
/*! \brief Various codec settings */
|
||||
struct opus_codec_settings {
|
||||
int useinbandfec;
|
||||
int usedtx;
|
||||
int maxaveragebitrate;
|
||||
int stereo;
|
||||
int cbr;
|
||||
int sprop_maxcapturerate;
|
||||
int sprop_stereo;
|
||||
int maxptime;
|
||||
int minptime;
|
||||
int ptime;
|
||||
int samplerate;
|
||||
};
|
||||
typedef struct opus_codec_settings opus_codec_settings_t;
|
||||
|
||||
static opus_codec_settings_t default_codec_settings = {
|
||||
/*.useinbandfec */ 1,
|
||||
/*.usedtx */ 1,
|
||||
/*.maxaveragebitrate */ 30000,
|
||||
/*.stereo*/ 0,
|
||||
/*.cbr*/ 0,
|
||||
/*.sprop_maxcapturerate*/ 0,
|
||||
/*.sprop_stereo*/ 0,
|
||||
/*.maxptime*/ 0,
|
||||
/*.minptime*/ 0,
|
||||
/*.ptime*/ 0,
|
||||
/*.samplerate*/ 0
|
||||
};
|
||||
|
||||
struct opus_context {
|
||||
OpusEncoder *encoder_object;
|
||||
OpusDecoder *decoder_object;
|
||||
int frame_size;
|
||||
};
|
||||
|
||||
static switch_status_t switch_opus_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
|
||||
{
|
||||
if (codec_fmtp) {
|
||||
opus_codec_settings_t local_settings = { 0 };
|
||||
opus_codec_settings_t *codec_settings = &local_settings;
|
||||
|
||||
if (codec_fmtp->private_info) {
|
||||
codec_settings = codec_fmtp->private_info;
|
||||
if (zstr(fmtp)) {
|
||||
memcpy(codec_settings, &default_codec_settings, sizeof(*codec_settings));
|
||||
}
|
||||
}
|
||||
|
||||
if (fmtp) {
|
||||
int x, argc;
|
||||
char *argv[10];
|
||||
char *fmtp_dup = strdup(fmtp);
|
||||
|
||||
switch_assert(fmtp_dup);
|
||||
|
||||
argc = switch_separate_string(fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
for (x = 0; x < argc; x++) {
|
||||
char *data = argv[x];
|
||||
char *arg;
|
||||
switch_assert(data);
|
||||
while (*data == ' ') {
|
||||
data++;
|
||||
}
|
||||
|
||||
|
||||
if ((arg = strchr(data, '='))) {
|
||||
*arg++ = '\0';
|
||||
|
||||
if (codec_settings) {
|
||||
if (!strcasecmp(data, "useinbandfec")) {
|
||||
codec_settings->useinbandfec = switch_true(arg);
|
||||
}
|
||||
|
||||
if (!strcasecmp(data, "usedtx")) {
|
||||
codec_settings->usedtx = switch_true(arg);
|
||||
}
|
||||
|
||||
if (!strcasecmp(data, "sprop-maxcapturerate")) {
|
||||
codec_settings->sprop_maxcapturerate = atoi(arg);
|
||||
}
|
||||
|
||||
if (!strcasecmp(data, "maxptime")) {
|
||||
codec_settings->maxptime = atoi(arg);
|
||||
}
|
||||
|
||||
if (!strcasecmp(data, "minptime")) {
|
||||
codec_settings->minptime = atoi(arg);
|
||||
}
|
||||
|
||||
if (!strcasecmp(data, "ptime")) {
|
||||
codec_settings->ptime = atoi(arg);
|
||||
codec_fmtp->microseconds_per_packet = codec_settings->ptime * 1000;
|
||||
}
|
||||
|
||||
if (!strcasecmp(data, "samplerate")) {
|
||||
codec_settings->samplerate = atoi(arg);
|
||||
codec_fmtp->actual_samples_per_second = codec_settings->samplerate;
|
||||
}
|
||||
|
||||
if (!strcasecmp(data, "maxaveragebitrate")) {
|
||||
codec_settings->maxaveragebitrate = atoi(arg);
|
||||
switch(codec_fmtp->actual_samples_per_second) {
|
||||
case 8000:
|
||||
{
|
||||
if(codec_settings->maxaveragebitrate < 6000 || codec_settings->maxaveragebitrate > 20000) {
|
||||
codec_settings->maxaveragebitrate = 20000;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 12000:
|
||||
{
|
||||
if(codec_settings->maxaveragebitrate < 7000 || codec_settings->maxaveragebitrate > 25000) {
|
||||
codec_settings->maxaveragebitrate = 25000;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 16000:
|
||||
{
|
||||
if(codec_settings->maxaveragebitrate < 8000 || codec_settings->maxaveragebitrate > 30000) {
|
||||
codec_settings->maxaveragebitrate = 30000;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 24000:
|
||||
{
|
||||
if(codec_settings->maxaveragebitrate < 12000 || codec_settings->maxaveragebitrate > 40000) {
|
||||
codec_settings->maxaveragebitrate = 40000;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
/* this should never happen but 20000 is common among all rates */
|
||||
codec_settings->maxaveragebitrate = 20000;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
codec_fmtp->bits_per_second = codec_settings->maxaveragebitrate;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
free(fmtp_dup);
|
||||
}
|
||||
//codec_fmtp->bits_per_second = bit_rate;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
static char *gen_fmtp(opus_codec_settings_t *settings, switch_memory_pool_t *pool)
|
||||
{
|
||||
char buf[256] = "";
|
||||
|
||||
if (settings->useinbandfec) {
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "useinbandfec=1;");
|
||||
}
|
||||
|
||||
if (settings->usedtx) {
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "usedtx=1;");
|
||||
}
|
||||
|
||||
if (settings->maxaveragebitrate) {
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxaveragebitrate=%d;", settings->maxaveragebitrate);
|
||||
|
||||
}
|
||||
|
||||
if (settings->ptime) {
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "ptime=%d;", settings->ptime);
|
||||
}
|
||||
|
||||
if (settings->minptime) {
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "minptime=%d;", settings->minptime);
|
||||
}
|
||||
|
||||
if (settings->maxptime) {
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxptime=%d;", settings->maxptime);
|
||||
}
|
||||
|
||||
if (settings->samplerate) {
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "samplerate=%d;", settings->samplerate);
|
||||
}
|
||||
|
||||
if (end_of(buf) == ';') {
|
||||
end_of(buf) = '\0';
|
||||
}
|
||||
|
||||
return switch_core_strdup(pool, buf);
|
||||
|
||||
}
|
||||
|
||||
static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
|
||||
{
|
||||
struct opus_context *context = NULL;
|
||||
int encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
|
||||
int decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
|
||||
switch_codec_fmtp_t codec_fmtp;
|
||||
opus_codec_settings_t opus_codec_settings = { 0 };
|
||||
|
||||
if (!(encoding || decoding) || (!(context = switch_core_alloc(codec->memory_pool, sizeof(*context))))) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
context->frame_size = codec->implementation->samples_per_packet;
|
||||
|
||||
|
||||
memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
|
||||
codec_fmtp.private_info = &opus_codec_settings;
|
||||
switch_opus_fmtp_parse(codec->fmtp_in, &codec_fmtp);
|
||||
|
||||
codec->fmtp_out = gen_fmtp(&opus_codec_settings, codec->memory_pool);
|
||||
|
||||
if (encoding) {
|
||||
/* come up with a way to specify these */
|
||||
int bitrate_bps = codec->implementation->bits_per_second;
|
||||
int bitrate_bps = OPUS_AUTO;
|
||||
int use_vbr = 1;
|
||||
int complexity = 10;
|
||||
int use_inbandfec = 1;
|
||||
int use_dtx = 1;
|
||||
int bandwidth = OPUS_BANDWIDTH_FULLBAND;
|
||||
int err;
|
||||
int samplerate = opus_codec_settings.samplerate ? opus_codec_settings.samplerate : codec->implementation->actual_samples_per_second;
|
||||
|
||||
context->encoder_object = opus_encoder_create(codec->implementation->actual_samples_per_second,
|
||||
context->encoder_object = opus_encoder_create(samplerate,
|
||||
codec->implementation->number_of_channels,
|
||||
OPUS_APPLICATION_VOIP, &err);
|
||||
|
||||
@@ -74,12 +268,24 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag
|
||||
}
|
||||
|
||||
opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(bitrate_bps));
|
||||
opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(bandwidth));
|
||||
|
||||
if (codec->implementation->actual_samples_per_second == 8000) {
|
||||
opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
|
||||
opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
|
||||
} else {
|
||||
opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
|
||||
}
|
||||
|
||||
opus_encoder_ctl(context->encoder_object, OPUS_SET_VBR(use_vbr));
|
||||
opus_encoder_ctl(context->encoder_object, OPUS_SET_COMPLEXITY(complexity));
|
||||
opus_encoder_ctl(context->encoder_object, OPUS_SET_INBAND_FEC(use_inbandfec));
|
||||
opus_encoder_ctl(context->encoder_object, OPUS_SET_DTX(use_dtx));
|
||||
|
||||
if (opus_codec_settings.useinbandfec) {
|
||||
opus_encoder_ctl(context->encoder_object, OPUS_SET_INBAND_FEC(opus_codec_settings.useinbandfec));
|
||||
}
|
||||
|
||||
if (opus_codec_settings.usedtx) {
|
||||
opus_encoder_ctl(context->encoder_object, OPUS_SET_DTX(opus_codec_settings.usedtx));
|
||||
}
|
||||
}
|
||||
|
||||
if (decoding) {
|
||||
@@ -187,19 +393,33 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load)
|
||||
int mss = 10000;
|
||||
int x = 0;
|
||||
int rate = 48000;
|
||||
int bits = 32000;
|
||||
int bits = 0;
|
||||
char *dft_fmtp = NULL;
|
||||
opus_codec_settings_t settings = { 0 };
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
SWITCH_ADD_CODEC(codec_interface, "OPUS (STANDARD)");
|
||||
|
||||
codec_interface->parse_fmtp = switch_opus_fmtp_parse;
|
||||
|
||||
settings = default_codec_settings;
|
||||
|
||||
|
||||
for (x = 0; x < 3; x++) {
|
||||
|
||||
settings.ptime = mss / 1000;
|
||||
settings.maxptime = settings.ptime;
|
||||
settings.minptime = settings.ptime;
|
||||
settings.samplerate = rate;
|
||||
dft_fmtp = gen_fmtp(&settings, pool);
|
||||
|
||||
switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
|
||||
116, /* the IANA code number */
|
||||
"opus",/* the IANA code name */
|
||||
NULL, /* default fmtp to send (can be overridden by the init function) */
|
||||
rate, /* samples transferred per second */
|
||||
dft_fmtp, /* default fmtp to send (can be overridden by the init function) */
|
||||
48000, /* samples transferred per second */
|
||||
rate, /* actual samples transferred per second */
|
||||
bits, /* bits transferred per second */
|
||||
mss, /* number of microseconds per frame */
|
||||
@@ -219,6 +439,44 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load)
|
||||
|
||||
}
|
||||
|
||||
|
||||
samples = 80;
|
||||
bytes = 160;
|
||||
mss = 10000;
|
||||
rate = 8000;
|
||||
|
||||
for (x = 0; x < 3; x++) {
|
||||
|
||||
settings.ptime = mss / 1000;
|
||||
settings.maxptime = settings.ptime;
|
||||
settings.minptime = settings.ptime;
|
||||
settings.samplerate = rate;
|
||||
dft_fmtp = gen_fmtp(&settings, pool);
|
||||
|
||||
switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
|
||||
116, /* the IANA code number */
|
||||
"opus",/* the IANA code name */
|
||||
dft_fmtp, /* default fmtp to send (can be overridden by the init function) */
|
||||
48000, /* samples transferred per second */
|
||||
rate, /* actual samples transferred per second */
|
||||
bits, /* bits transferred per second */
|
||||
mss, /* number of microseconds per frame */
|
||||
samples, /* number of samples per frame */
|
||||
bytes, /* number of bytes per frame decompressed */
|
||||
0, /* number of bytes per frame compressed */
|
||||
1,/* number of channels represented */
|
||||
1, /* number of frames per network packet */
|
||||
switch_opus_init, /* function to initialize a codec handle using this implementation */
|
||||
switch_opus_encode, /* function to encode raw data into encoded data */
|
||||
switch_opus_decode, /* function to decode encoded data into raw data */
|
||||
switch_opus_destroy); /* deinitalize a codec handle using this implementation */
|
||||
|
||||
bytes += 160;
|
||||
samples += 80;
|
||||
mss += 10000;
|
||||
|
||||
}
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -83,9 +83,21 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_vp8_load)
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
SWITCH_ADD_CODEC(codec_interface, "VP8 Video (passthru)");
|
||||
|
||||
switch_core_codec_add_implementation(pool, codec_interface,
|
||||
SWITCH_CODEC_TYPE_VIDEO, 99, "VP8", NULL, 90000, 90000, 0,
|
||||
0, 0, 0, 0, 1, 1, switch_vp8_init, switch_vp8_encode, switch_vp8_decode, switch_vp8_destroy);
|
||||
|
||||
SWITCH_ADD_CODEC(codec_interface, "red Video (passthru)");
|
||||
switch_core_codec_add_implementation(pool, codec_interface,
|
||||
SWITCH_CODEC_TYPE_VIDEO, 103, "red", NULL, 90000, 90000, 0,
|
||||
0, 0, 0, 0, 1, 1, switch_vp8_init, switch_vp8_encode, switch_vp8_decode, switch_vp8_destroy);
|
||||
|
||||
SWITCH_ADD_CODEC(codec_interface, "ulpfec Video (passthru)");
|
||||
switch_core_codec_add_implementation(pool, codec_interface,
|
||||
SWITCH_CODEC_TYPE_VIDEO, 104, "ulpfec", NULL, 90000, 90000, 0,
|
||||
0, 0, 0, 0, 1, 1, switch_vp8_init, switch_vp8_encode, switch_vp8_decode, switch_vp8_destroy);
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -626,13 +626,14 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY nomedia - sending ack\n");
|
||||
nua_ack(tech_pvt->nh,
|
||||
TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
|
||||
SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
|
||||
SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
|
||||
SOATAG_REUSE_REJECTED(1),
|
||||
SOATAG_RTP_SELECT(1), SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"),
|
||||
TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)),
|
||||
TAG_END());
|
||||
TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
|
||||
SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
|
||||
SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
|
||||
SOATAG_REUSE_REJECTED(1),
|
||||
SOATAG_RTP_SELECT(1),
|
||||
SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"),
|
||||
TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)),
|
||||
TAG_END());
|
||||
sofia_clear_flag(tech_pvt, TFLAG_3PCC_INVITE); // all done
|
||||
sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
|
||||
sofia_set_flag_locked(tech_pvt, TFLAG_SDP);
|
||||
@@ -667,7 +668,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
|
||||
tech_pvt->mparams.local_sdp_str = NULL;
|
||||
|
||||
switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0);
|
||||
switch_core_media_gen_local_sdp(session, NULL, 0, NULL, 0);
|
||||
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
|
||||
} else {
|
||||
switch_core_media_set_local_sdp(session, b_sdp, SWITCH_TRUE);
|
||||
|
||||
@@ -683,12 +684,14 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
|
||||
if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
|
||||
char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_RESPONSE_HEADER_PREFIX);
|
||||
if (sofia_use_soa(tech_pvt)) {
|
||||
|
||||
nua_respond(tech_pvt->nh, SIP_200_OK,
|
||||
TAG_IF(is_proxy, NUTAG_AUTOANSWER(0)),
|
||||
SIPTAG_CONTACT_STR(tech_pvt->profile->url),
|
||||
SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
|
||||
TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
|
||||
SOATAG_REUSE_REJECTED(1), TAG_IF(is_proxy, SOATAG_RTP_SELECT(1)),
|
||||
SOATAG_REUSE_REJECTED(1),
|
||||
SOATAG_RTP_SELECT(1),
|
||||
SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1),
|
||||
TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
|
||||
TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote),
|
||||
@@ -762,7 +765,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
|
||||
return status;
|
||||
}
|
||||
|
||||
switch_core_media_gen_local_sdp(session, NULL, 0, NULL, 0);
|
||||
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
|
||||
if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
||||
}
|
||||
@@ -834,7 +837,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
|
||||
SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
|
||||
SOATAG_REUSE_REJECTED(1), SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"),
|
||||
TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)),
|
||||
TAG_IF(is_proxy, SOATAG_RTP_SELECT(1)),
|
||||
SOATAG_RTP_SELECT(1),
|
||||
TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
|
||||
TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote),
|
||||
SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END());
|
||||
@@ -1221,7 +1224,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
switch_channel_set_flag(tech_pvt->channel, CF_SECURE);
|
||||
}
|
||||
|
||||
if (sofia_test_media_flag(tech_pvt->profile, SCMF_AUTOFIX_TIMING) || sofia_test_media_flag(tech_pvt->profile, SCMF_AUTOFIX_PT)) {
|
||||
if (sofia_test_media_flag(tech_pvt->profile, SCMF_AUTOFIX_TIMING)) {
|
||||
switch_core_media_reset_autofix(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO);
|
||||
}
|
||||
}
|
||||
@@ -1264,7 +1267,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
ip = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE);
|
||||
port = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE);
|
||||
if (ip && port) {
|
||||
switch_core_media_gen_local_sdp(session, ip, (switch_port_t)atoi(port), msg->string_arg, 1);
|
||||
switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, ip, (switch_port_t)atoi(port), msg->string_arg, 1);
|
||||
}
|
||||
|
||||
if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
|
||||
@@ -1397,7 +1400,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
goto end_lock;
|
||||
}
|
||||
}
|
||||
switch_core_media_gen_local_sdp(session, NULL, 0, NULL, 1);
|
||||
switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 1);
|
||||
|
||||
if (send_invite) {
|
||||
if (!switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
|
||||
@@ -2081,7 +2084,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
||||
goto end_lock;
|
||||
}
|
||||
switch_core_media_gen_local_sdp(session, NULL, 0, NULL, 0);
|
||||
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
|
||||
if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
||||
}
|
||||
|
||||
@@ -513,7 +513,7 @@ static switch_status_t channel_receive_event(switch_core_session_t *session, swi
|
||||
}
|
||||
|
||||
switch_rtp_set_default_payload(tech_pvt->rtp_session, pt);
|
||||
switch_rtp_set_recv_pt(tech_pvt->rtp_session, pt);
|
||||
//switch_rtp_set_recv_pt(tech_pvt->rtp_session, pt);
|
||||
}
|
||||
|
||||
if (compare_var(event, channel, kRFC2833PT)) {
|
||||
|
||||
@@ -1492,8 +1492,8 @@ static void our_sofia_event_callback(nua_event_t event,
|
||||
|
||||
|
||||
sofia_reg_check_socket(profile, sofia_private->call_id, sofia_private->network_ip, sofia_private->network_port);
|
||||
nua_handle_destroy(nh);
|
||||
}
|
||||
nua_handle_destroy(nh);
|
||||
}
|
||||
break;
|
||||
case nua_r_authenticate:
|
||||
@@ -3743,7 +3743,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
|
||||
sofia_set_pflag(profile, PFLAG_DISABLE_100REL);
|
||||
profile->auto_restart = 1;
|
||||
sofia_set_media_flag(profile, SCMF_AUTOFIX_TIMING);
|
||||
sofia_set_media_flag(profile, SCMF_AUTOFIX_PT);
|
||||
sofia_set_media_flag(profile, SCMF_RENEG_ON_REINVITE);
|
||||
sofia_set_media_flag(profile, SCMF_RTP_AUTOFLUSH_DURING_BRIDGE);
|
||||
profile->contact_user = SOFIA_DEFAULT_CONTACT_USER;
|
||||
sofia_set_pflag(profile, PFLAG_PASS_CALLEE_ID);
|
||||
@@ -4381,12 +4381,6 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
|
||||
} else {
|
||||
sofia_clear_media_flag(profile, SCMF_AUTOFIX_TIMING);
|
||||
}
|
||||
} else if (!strcasecmp(var, "rtp-autofix-pt")) {
|
||||
if (switch_true(val)) {
|
||||
sofia_set_media_flag(profile, SCMF_AUTOFIX_PT);
|
||||
} else {
|
||||
sofia_clear_media_flag(profile, SCMF_AUTOFIX_PT);
|
||||
}
|
||||
} else if (!strcasecmp(var, "contact-user")) {
|
||||
profile->contact_user = switch_core_strdup(profile->pool, val);
|
||||
} else if (!strcasecmp(var, "nat-options-ping")) {
|
||||
@@ -5250,7 +5244,7 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status
|
||||
|
||||
sofia_update_callee_id(session, profile, sip, SWITCH_FALSE);
|
||||
|
||||
if (sofia_test_media_flag(tech_pvt->profile, SCMF_AUTOFIX_TIMING) || sofia_test_media_flag(tech_pvt->profile, SCMF_AUTOFIX_PT)) {
|
||||
if (sofia_test_media_flag(tech_pvt->profile, SCMF_AUTOFIX_TIMING)) {
|
||||
switch_core_media_reset_autofix(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO);
|
||||
}
|
||||
|
||||
@@ -6204,7 +6198,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
} else {
|
||||
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP");
|
||||
switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0);
|
||||
switch_core_media_gen_local_sdp(session, NULL, 0, NULL, 0);
|
||||
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
|
||||
sofia_set_flag_locked(tech_pvt, TFLAG_3PCC);
|
||||
switch_channel_set_state(channel, CS_HIBERNATE);
|
||||
if (sofia_use_soa(tech_pvt)) {
|
||||
@@ -6321,7 +6315,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
switch_core_media_gen_local_sdp(session, NULL, 0, NULL, 1);
|
||||
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 1);
|
||||
|
||||
if (sofia_use_soa(tech_pvt)) {
|
||||
nua_respond(tech_pvt->nh, SIP_200_OK,
|
||||
@@ -6427,7 +6421,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_core_media_gen_local_sdp(session, NULL, 0, NULL, 0);
|
||||
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
|
||||
|
||||
if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Reinvite RTP Error!\n");
|
||||
@@ -6446,7 +6440,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
if (is_ok) {
|
||||
|
||||
if (switch_core_session_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) {
|
||||
switch_core_media_gen_local_sdp(session, NULL, 0, NULL, 0);
|
||||
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
|
||||
}
|
||||
if (sofia_use_soa(tech_pvt)) {
|
||||
nua_respond(tech_pvt->nh, SIP_200_OK,
|
||||
@@ -6486,7 +6480,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
if (switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0) != SWITCH_STATUS_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
switch_core_media_gen_local_sdp(session, NULL, 0, NULL, 0);
|
||||
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Processing updated SDP\n");
|
||||
switch_channel_set_flag(tech_pvt->channel, CF_REINVITE);
|
||||
|
||||
@@ -752,7 +752,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
|
||||
}
|
||||
|
||||
if (!switch_channel_get_private(tech_pvt->channel, "t38_options") || zstr(tech_pvt->mparams.local_sdp_str)) {
|
||||
switch_core_media_gen_local_sdp(session, NULL, 0, NULL, 0);
|
||||
switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
sofia_set_flag_locked(tech_pvt, TFLAG_READY);
|
||||
|
||||
@@ -11,6 +11,7 @@ LOCAL_OBJS= $(IKS_LA) \
|
||||
nlsml.o \
|
||||
rayo_components.o \
|
||||
rayo_elements.o \
|
||||
rayo_fax_components.o \
|
||||
rayo_input_component.o \
|
||||
rayo_output_component.o \
|
||||
rayo_prompt_component.o \
|
||||
@@ -23,6 +24,7 @@ LOCAL_SOURCES= \
|
||||
nlsml.c \
|
||||
rayo_components.c \
|
||||
rayo_elements.c \
|
||||
rayo_fax_components.c \
|
||||
rayo_input_component.c \
|
||||
rayo_output_component.c \
|
||||
rayo_prompt_component.c \
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
<param name="default-recognizer" value="pocketsphinx"/>
|
||||
</input>
|
||||
|
||||
<!-- send/receivefax component params -->
|
||||
<fax>
|
||||
<!-- where to store incoming faxes -->
|
||||
<param name="receivefax-file-prefix" value="/tmp/"/>
|
||||
</fax>
|
||||
|
||||
<!-- XMPP server domain -->
|
||||
<domain name="$${rayo_domain_name}" shared-secret="ClueCon">
|
||||
<!-- use this instead if you want secure XMPP client to server connections. Put .crt and .key file in freeswitch/certs -->
|
||||
@@ -65,6 +71,7 @@
|
||||
<alias name="speed-down" target="output"><![CDATA[<speed-down xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
|
||||
<alias name="volume-up" target="output"><![CDATA[<volume-up xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
|
||||
<alias name="volume-down" target="output"><![CDATA[<volume-down xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
|
||||
<alias name="receivefax" target="call"><![CDATA[<receivefax xmlns="urn:xmpp:rayo:fax:1"/>]]></alias>
|
||||
<alias name="record" target="call"><![CDATA[<record xmlns="urn:xmpp:rayo:record:1"/>]]></alias>
|
||||
<alias name="record_pause" target="record"><![CDATA[<pause xmlns="urn:xmpp:rayo:record:1"/>]]></alias>
|
||||
<alias name="record_resume" target="record"><![CDATA[<resume xmlns="urn:xmpp:rayo:record:1"/>]]></alias>
|
||||
|
||||
@@ -126,6 +126,8 @@ struct rayo_call {
|
||||
switch_hash_t *pcps;
|
||||
/** current idle start time */
|
||||
switch_time_t idle_start_time;
|
||||
/** true if fax is in progress */
|
||||
int faxing;
|
||||
/** 1 if joined to call, 2 if joined to mixer */
|
||||
int joined;
|
||||
/** pending join */
|
||||
@@ -950,6 +952,7 @@ static void rayo_call_cleanup(struct rayo_actor *actor)
|
||||
|
||||
iks_delete(revent);
|
||||
switch_event_destroy(&event);
|
||||
switch_core_hash_destroy(&call->pcps);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -963,11 +966,30 @@ const char *rayo_call_get_dcp_jid(struct rayo_call *call)
|
||||
|
||||
/**
|
||||
* @param call the Rayo call
|
||||
* @return true if joined
|
||||
* @return true if joined (or a join is in progress)
|
||||
*/
|
||||
static int rayo_call_is_joined(struct rayo_call *call)
|
||||
int rayo_call_is_joined(struct rayo_call *call)
|
||||
{
|
||||
return call->joined;
|
||||
return call->joined || call->pending_join_request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param call to check if faxing
|
||||
* @return true if faxing is in progress
|
||||
*/
|
||||
int rayo_call_is_faxing(struct rayo_call *call)
|
||||
{
|
||||
return call->faxing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set faxing flag
|
||||
* @param call the call to flag
|
||||
* @param faxing true if faxing is in progress
|
||||
*/
|
||||
void rayo_call_set_faxing(struct rayo_call *call, int faxing)
|
||||
{
|
||||
call->faxing = faxing;
|
||||
}
|
||||
|
||||
#define RAYO_MIXER_LOCATE(mixer_name) rayo_mixer_locate(mixer_name, __FILE__, __LINE__)
|
||||
@@ -1104,13 +1126,23 @@ static struct rayo_call *_rayo_call_create(const char *uuid, const char *file, i
|
||||
return rayo_call_init(call, pool, uuid, file, line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixer destructor
|
||||
*/
|
||||
static void rayo_mixer_cleanup(struct rayo_actor *actor)
|
||||
{
|
||||
struct rayo_mixer *mixer = RAYO_MIXER(actor);
|
||||
switch_core_hash_destroy(&mixer->members);
|
||||
switch_core_hash_destroy(&mixer->subscribers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize mixer
|
||||
*/
|
||||
static struct rayo_mixer *rayo_mixer_init(struct rayo_mixer *mixer, switch_memory_pool_t *pool, const char *name, const char *file, int line)
|
||||
{
|
||||
char *mixer_jid = switch_mprintf("%s@%s", name, RAYO_JID(globals.server));
|
||||
rayo_actor_init(RAYO_ACTOR(mixer), pool, RAT_MIXER, "", name, mixer_jid, NULL, rayo_mixer_send, file, line);
|
||||
rayo_actor_init(RAYO_ACTOR(mixer), pool, RAT_MIXER, "", name, mixer_jid, rayo_mixer_cleanup, rayo_mixer_send, file, line);
|
||||
switch_core_hash_init(&mixer->members, pool);
|
||||
switch_core_hash_init(&mixer->subscribers, pool);
|
||||
switch_safe_free(mixer_jid);
|
||||
@@ -1281,6 +1313,7 @@ static void rayo_peer_server_cleanup(struct rayo_actor *actor)
|
||||
RAYO_UNLOCK(client);
|
||||
RAYO_DESTROY(client);
|
||||
}
|
||||
switch_core_hash_destroy(&rserver->clients);
|
||||
switch_mutex_unlock(globals.clients_mutex);
|
||||
}
|
||||
|
||||
@@ -1942,6 +1975,12 @@ static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rayo_call_is_faxing(RAYO_CALL(call))) {
|
||||
/* can't join a call while it's faxing */
|
||||
response = iks_new_error_detailed(msg->payload, STANZA_ERROR_UNEXPECTED_REQUEST, "fax is in progress");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (RAYO_CALL(call)->pending_join_request) {
|
||||
/* don't allow concurrent join requests */
|
||||
response = iks_new_error_detailed(msg->payload, STANZA_ERROR_UNEXPECTED_REQUEST, "(un)join request is pending");
|
||||
@@ -2339,11 +2378,14 @@ static iks *on_iq_get_xmpp_disco(struct rayo_actor *server, struct rayo_message
|
||||
iks *node = msg->payload;
|
||||
iks *response = NULL;
|
||||
iks *x;
|
||||
iks *feature;
|
||||
response = iks_new_iq_result(node);
|
||||
x = iks_insert(response, "query");
|
||||
iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_DISCO);
|
||||
x = iks_insert(x, "feature");
|
||||
iks_insert_attrib(x, "var", RAYO_NS);
|
||||
feature = iks_insert(x, "feature");
|
||||
iks_insert_attrib(feature, "var", RAYO_NS);
|
||||
feature = iks_insert(x, "feature");
|
||||
iks_insert_attrib(feature, "var", RAYO_FAX_NS);
|
||||
|
||||
/* TODO The response MUST also include features for the application formats and transport methods supported by
|
||||
* the responding entity, as described in the relevant specifications.
|
||||
@@ -3074,12 +3116,22 @@ static switch_status_t rayo_call_on_read_frame(switch_core_session_t *session, s
|
||||
switch_time_t idle_start = call->idle_start_time;
|
||||
int idle_duration_ms = (now - idle_start) / 1000;
|
||||
/* detect idle session (rayo-client has stopped controlling call) and terminate call */
|
||||
if (rayo_call_is_joined(call)) {
|
||||
if (rayo_call_is_joined(call) || rayo_call_is_faxing(call)) {
|
||||
call->idle_start_time = now;
|
||||
} else if (idle_duration_ms > globals.max_idle_ms) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Ending abandoned call. idle_duration_ms = %i ms\n", idle_duration_ms);
|
||||
switch_channel_hangup(channel, RAYO_CAUSE_HANGUP);
|
||||
}
|
||||
|
||||
/* check for break request */
|
||||
{
|
||||
const char *break_jid = switch_channel_get_variable(channel, "rayo_read_frame_interrupt");
|
||||
struct rayo_actor *actor;
|
||||
if (break_jid && (actor = RAYO_LOCATE(break_jid))) {
|
||||
RAYO_UNLOCK(actor);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -3117,18 +3169,17 @@ SWITCH_STANDARD_APP(rayo_app)
|
||||
}
|
||||
}
|
||||
if (!call) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Missing rayo call!!\n");
|
||||
goto done;
|
||||
/* this scenario can only happen if a call was originated through a mechanism other than <dial>
|
||||
and then the rayo APP was executed to offer control */
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Outbound call that wasn't created with <dial>, will try to offer control\n");
|
||||
}
|
||||
ok = 1;
|
||||
} else {
|
||||
/* inbound call - offer control */
|
||||
}
|
||||
|
||||
if (!call) {
|
||||
/* offer control */
|
||||
switch_hash_index_t *hi = NULL;
|
||||
iks *offer = NULL;
|
||||
if (call) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Call is already under Rayo 3PCC!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
call = rayo_call_create(switch_core_session_get_uuid(session));
|
||||
switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_call_jid", RAYO_JID(call));
|
||||
@@ -3161,6 +3212,7 @@ SWITCH_STANDARD_APP(rayo_app)
|
||||
|
||||
/* nobody to offer to */
|
||||
if (!ok) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Rejecting rayo call - there are no online rayo clients to offer call to\n");
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,6 +153,9 @@ extern void rayo_actor_destroy(struct rayo_actor *actor, const char *file, int l
|
||||
#define RAYO_DESTROY(x) rayo_actor_destroy(RAYO_ACTOR(x), __FILE__, __LINE__)
|
||||
#define RAYO_SEQ_NEXT(x) rayo_actor_seq_next(RAYO_ACTOR(x))
|
||||
|
||||
extern int rayo_call_is_joined(struct rayo_call *call);
|
||||
extern int rayo_call_is_faxing(struct rayo_call *call);
|
||||
extern void rayo_call_set_faxing(struct rayo_call *call, int faxing);
|
||||
extern const char *rayo_call_get_dcp_jid(struct rayo_call *call);
|
||||
|
||||
#define rayo_mixer_get_name(mixer) RAYO_ID(mixer)
|
||||
|
||||
@@ -226,7 +226,8 @@ switch_status_t rayo_components_load(switch_loadable_module_interface_t **module
|
||||
if (rayo_input_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS ||
|
||||
rayo_output_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS ||
|
||||
rayo_prompt_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS ||
|
||||
rayo_record_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS) {
|
||||
rayo_record_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS ||
|
||||
rayo_fax_components_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
@@ -241,6 +242,7 @@ switch_status_t rayo_components_shutdown(void)
|
||||
rayo_output_component_shutdown();
|
||||
rayo_prompt_component_shutdown();
|
||||
rayo_record_component_shutdown();
|
||||
rayo_fax_components_shutdown();
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
#define RAYO_PROMPT_NS RAYO_BASE "prompt:" RAYO_VERSION
|
||||
#define RAYO_PROMPT_COMPLETE_NS RAYO_BASE "prompt:complete:" RAYO_VERSION
|
||||
|
||||
#define RAYO_FAX_NS RAYO_BASE "fax:" RAYO_VERSION
|
||||
#define RAYO_FAX_COMPLETE_NS RAYO_BASE "fax:complete:" RAYO_VERSION
|
||||
|
||||
#define COMPONENT_COMPLETE_STOP "stop", RAYO_EXT_COMPLETE_NS
|
||||
#define COMPONENT_COMPLETE_ERROR "error", RAYO_EXT_COMPLETE_NS
|
||||
#define COMPONENT_COMPLETE_HANGUP "hangup", RAYO_EXT_COMPLETE_NS
|
||||
@@ -58,12 +61,14 @@ extern switch_status_t rayo_input_component_load(switch_loadable_module_interfac
|
||||
extern switch_status_t rayo_output_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
|
||||
extern switch_status_t rayo_prompt_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
|
||||
extern switch_status_t rayo_record_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
|
||||
extern switch_status_t rayo_fax_components_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
|
||||
|
||||
extern switch_status_t rayo_components_shutdown(void);
|
||||
extern switch_status_t rayo_input_component_shutdown(void);
|
||||
extern switch_status_t rayo_output_component_shutdown(void);
|
||||
extern switch_status_t rayo_prompt_component_shutdown(void);
|
||||
extern switch_status_t rayo_record_component_shutdown(void);
|
||||
extern switch_status_t rayo_fax_components_shutdown(void);
|
||||
|
||||
extern void rayo_component_send_start(struct rayo_component *component, iks *iq);
|
||||
extern void rayo_component_send_iq_error(struct rayo_component *component, iks *iq, const char *error_name, const char *error_type);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
* <input> component validation
|
||||
*/
|
||||
ELEMENT(RAYO_INPUT)
|
||||
ATTRIB(xmlns,, any)
|
||||
STRING_ATTRIB(mode, any, "any,dtmf,voice")
|
||||
OPTIONAL_ATTRIB(terminator,, dtmf_digit)
|
||||
ATTRIB(recognizer,, any)
|
||||
@@ -48,10 +49,22 @@ ELEMENT(RAYO_INPUT)
|
||||
ATTRIB(start-timers, true, bool)
|
||||
ELEMENT_END
|
||||
|
||||
/**
|
||||
* <join> command validation
|
||||
*/
|
||||
ELEMENT(RAYO_JOIN)
|
||||
ATTRIB(xmlns,, any)
|
||||
STRING_ATTRIB(direction, duplex, "send,recv,duplex")
|
||||
STRING_ATTRIB(media, bridge, "bridge,direct")
|
||||
ATTRIB(call-uri,, any)
|
||||
ATTRIB(mixer-name,, any)
|
||||
ELEMENT_END
|
||||
|
||||
/**
|
||||
* <output> component validation
|
||||
*/
|
||||
ELEMENT(RAYO_OUTPUT)
|
||||
ATTRIB(xmlns,, any)
|
||||
ATTRIB(start-offset, 0, not_negative)
|
||||
ATTRIB(start-paused, false, bool)
|
||||
ATTRIB(repeat-interval, 0, not_negative)
|
||||
@@ -65,6 +78,7 @@ ELEMENT_END
|
||||
* <output><seek> validation
|
||||
*/
|
||||
ELEMENT(RAYO_OUTPUT_SEEK)
|
||||
ATTRIB(xmlns,, any)
|
||||
STRING_ATTRIB(direction,, "forward,back")
|
||||
ATTRIB(amount,-1, positive)
|
||||
ELEMENT_END
|
||||
@@ -73,14 +87,23 @@ ELEMENT_END
|
||||
* <prompt> component validation
|
||||
*/
|
||||
ELEMENT(RAYO_PROMPT)
|
||||
ATTRIB(xmlns,, any)
|
||||
ATTRIB(barge-in, true, bool)
|
||||
ELEMENT_END
|
||||
|
||||
/**
|
||||
* <receivefax> command validation
|
||||
*/
|
||||
ELEMENT(RAYO_RECEIVEFAX)
|
||||
ATTRIB(xmlns,, any)
|
||||
ELEMENT_END
|
||||
|
||||
/**
|
||||
* <record> component validation
|
||||
*/
|
||||
ELEMENT(RAYO_RECORD)
|
||||
ATTRIB(format, mp3, any)
|
||||
ATTRIB(xmlns,, any)
|
||||
ATTRIB(format, wav, any)
|
||||
ATTRIB(start-beep, false, bool)
|
||||
ATTRIB(stop-beep, false, bool)
|
||||
ATTRIB(start-paused, false, bool)
|
||||
@@ -92,13 +115,10 @@ ELEMENT(RAYO_RECORD)
|
||||
ELEMENT_END
|
||||
|
||||
/**
|
||||
* <join> command validation
|
||||
* <sendfax> command validation
|
||||
*/
|
||||
ELEMENT(RAYO_JOIN)
|
||||
STRING_ATTRIB(direction, duplex, "send,recv,duplex")
|
||||
STRING_ATTRIB(media, bridge, "bridge,direct")
|
||||
ATTRIB(call-uri,, any)
|
||||
ATTRIB(mixer-name,, any)
|
||||
ELEMENT(RAYO_SENDFAX)
|
||||
ATTRIB(xmlns,, any)
|
||||
ELEMENT_END
|
||||
|
||||
|
||||
|
||||
@@ -32,11 +32,13 @@
|
||||
#include "iks_helpers.h"
|
||||
|
||||
ELEMENT_DECL(RAYO_INPUT)
|
||||
ELEMENT_DECL(RAYO_JOIN)
|
||||
ELEMENT_DECL(RAYO_OUTPUT)
|
||||
ELEMENT_DECL(RAYO_OUTPUT_SEEK)
|
||||
ELEMENT_DECL(RAYO_PROMPT)
|
||||
ELEMENT_DECL(RAYO_RECEIVEFAX)
|
||||
ELEMENT_DECL(RAYO_RECORD)
|
||||
ELEMENT_DECL(RAYO_JOIN)
|
||||
ELEMENT_DECL(RAYO_SENDFAX)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2013, Grasshopper
|
||||
*
|
||||
* 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 mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is Grasshopper
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Rienzo <chris.rienzo@grasshopper.com>
|
||||
*
|
||||
* rayo_fax_components.c -- Rayo receivefax and sendfax components implementation
|
||||
*
|
||||
*/
|
||||
#include "rayo_components.h"
|
||||
#include "rayo_elements.h"
|
||||
|
||||
/**
|
||||
* settings
|
||||
*/
|
||||
static struct {
|
||||
const char *file_prefix;
|
||||
} globals;
|
||||
|
||||
struct fax_component {
|
||||
/** component base class */
|
||||
struct rayo_component base;
|
||||
/** Flag to stop fax */
|
||||
int stop;
|
||||
};
|
||||
|
||||
#define FAX_COMPONENT(x) ((struct fax_component *)x)
|
||||
|
||||
struct receivefax_component {
|
||||
/** fax component base class */
|
||||
struct fax_component base;
|
||||
/** true if HTTP PUT needs to be done after fax is received */
|
||||
int http_put_after_receive;
|
||||
/** fax stored on local filesystem */
|
||||
const char *local_filename;
|
||||
/** fax final target (may be same as local filename) */
|
||||
const char *filename;
|
||||
};
|
||||
|
||||
#define RECEIVEFAX_COMPONENT(x) ((struct receivefax_component *)x)
|
||||
|
||||
#define FAX_FINISH "finish", RAYO_FAX_COMPLETE_NS
|
||||
|
||||
/**
|
||||
* Start execution of call sendfax component
|
||||
* @param call the call to send fax to
|
||||
* @param msg the original request
|
||||
* @param session_data the call's session
|
||||
*/
|
||||
static iks *start_sendfax_component(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
|
||||
{
|
||||
iks *iq = msg->payload;
|
||||
switch_core_session_t *session = (switch_core_session_t *)session_data;
|
||||
struct fax_component *sendfax_component = NULL;
|
||||
iks *sendfax = iks_find(iq, "sendfax");
|
||||
iks *response = NULL;
|
||||
switch_event_t *execute_event = NULL;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_memory_pool_t *pool;
|
||||
iks *document;
|
||||
const char *fax_document;
|
||||
const char *fax_header;
|
||||
const char *fax_identity;
|
||||
const char *pages;
|
||||
|
||||
/* validate attributes */
|
||||
if (!VALIDATE_RAYO_SENDFAX(sendfax)) {
|
||||
return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST);
|
||||
}
|
||||
|
||||
/* fax is only allowed if the call is not currently joined */
|
||||
if (rayo_call_is_joined(RAYO_CALL(call))) {
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "can't send fax on a joined call");
|
||||
}
|
||||
|
||||
if (rayo_call_is_faxing(RAYO_CALL(call))) {
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "fax already in progress");
|
||||
}
|
||||
|
||||
/* get fax document */
|
||||
document = iks_find(sendfax, "document");
|
||||
if (!document) {
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "missing document");
|
||||
}
|
||||
fax_document = iks_find_attrib_soft(document, "url");
|
||||
if (zstr(fax_document)) {
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "missing document url");
|
||||
}
|
||||
|
||||
/* is valid URL type? */
|
||||
if (!strncasecmp(fax_document, "http://", 7) || !strncasecmp(fax_document, "https://", 8)) {
|
||||
switch_stream_handle_t stream = { 0 };
|
||||
SWITCH_STANDARD_STREAM(stream);
|
||||
/* need to fetch document from server... */
|
||||
switch_api_execute("http_get", fax_document, session, &stream);
|
||||
if (!zstr(stream.data) && !strncmp(fax_document, SWITCH_PATH_SEPARATOR, strlen(SWITCH_PATH_SEPARATOR))) {
|
||||
fax_document = switch_core_session_strdup(session, stream.data);
|
||||
} else {
|
||||
switch_safe_free(stream.data);
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to fetch document");
|
||||
}
|
||||
switch_safe_free(stream.data);
|
||||
} else if (!strncasecmp(fax_document, "file://", 7)) {
|
||||
fax_document = fax_document + 7;
|
||||
if (zstr(fax_document)) {
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "invalid file:// url");
|
||||
}
|
||||
} else if (strncasecmp(fax_document, SWITCH_PATH_SEPARATOR, strlen(SWITCH_PATH_SEPARATOR))) {
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "unsupported url type");
|
||||
}
|
||||
|
||||
/* does document exist? */
|
||||
if (switch_file_exists(fax_document, pool) != SWITCH_STATUS_SUCCESS) {
|
||||
return iks_new_error_detailed_printf(iq, STANZA_ERROR_BAD_REQUEST, "file not found: %s", fax_document);
|
||||
}
|
||||
|
||||
/* get fax identity and header */
|
||||
fax_identity = iks_find_attrib_soft(document, "identity");
|
||||
if (!zstr(fax_identity)) {
|
||||
switch_channel_set_variable(channel, "fax_ident", fax_identity);
|
||||
} else {
|
||||
switch_channel_set_variable(channel, "fax_ident", NULL);
|
||||
}
|
||||
fax_header = iks_find_attrib_soft(document, "header");
|
||||
if (!zstr(fax_header)) {
|
||||
switch_channel_set_variable(channel, "fax_header", fax_header);
|
||||
} else {
|
||||
switch_channel_set_variable(channel, "fax_header", NULL);
|
||||
}
|
||||
|
||||
/* get pages to send */
|
||||
pages = iks_find_attrib_soft(document, "pages");
|
||||
if (!zstr(pages)) {
|
||||
if (switch_regex_match(pages, "[1-9][0-9]*(-[1-9][0-9]*)?") == SWITCH_STATUS_FALSE) {
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "invalid pages value");
|
||||
} else {
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
char *pages_dup = switch_core_session_strdup(session, pages);
|
||||
char *sep = strchr(pages_dup, '-');
|
||||
if (sep) {
|
||||
*sep = '\0';
|
||||
sep++;
|
||||
end = atoi(sep);
|
||||
}
|
||||
start = atoi(pages_dup);
|
||||
if (end && end < start) {
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "invalid pages value");
|
||||
}
|
||||
switch_channel_set_variable(channel, "fax_start_page", pages_dup);
|
||||
switch_channel_set_variable(channel, "fax_end_page", sep);
|
||||
}
|
||||
} else {
|
||||
switch_channel_set_variable(channel, "fax_start_page", NULL);
|
||||
switch_channel_set_variable(channel, "fax_end_page", NULL);
|
||||
}
|
||||
|
||||
/* create sendfax component */
|
||||
switch_core_new_memory_pool(&pool);
|
||||
sendfax_component = switch_core_alloc(pool, sizeof(*sendfax_component));
|
||||
rayo_component_init((struct rayo_component *)sendfax_component, pool, RAT_CALL_COMPONENT, "sendfax", NULL, call, iks_find_attrib(iq, "from"));
|
||||
|
||||
/* add channel variable so that fax component can be located from fax events */
|
||||
switch_channel_set_variable(channel, "rayo_fax_jid", RAYO_JID(sendfax_component));
|
||||
|
||||
/* clear fax result variables */
|
||||
switch_channel_set_variable(channel, "fax_success", NULL);
|
||||
switch_channel_set_variable(channel, "fax_result_code", NULL);
|
||||
switch_channel_set_variable(channel, "fax_result_text", NULL);
|
||||
switch_channel_set_variable(channel, "fax_document_transferred_pages", NULL);
|
||||
switch_channel_set_variable(channel, "fax_document_total_pages", NULL);
|
||||
switch_channel_set_variable(channel, "fax_image_resolution", NULL);
|
||||
switch_channel_set_variable(channel, "fax_image_size", NULL);
|
||||
switch_channel_set_variable(channel, "fax_bad_rows", NULL);
|
||||
switch_channel_set_variable(channel, "fax_transfer_rate", NULL);
|
||||
switch_channel_set_variable(channel, "fax_ecm_used", NULL);
|
||||
switch_channel_set_variable(channel, "fax_local_station_id", NULL);
|
||||
switch_channel_set_variable(channel, "fax_remote_station_id", NULL);
|
||||
|
||||
/* clear fax interrupt variable */
|
||||
switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_read_frame_interrupt", NULL);
|
||||
|
||||
rayo_call_set_faxing(RAYO_CALL(call), 1);
|
||||
|
||||
/* execute txfax APP */
|
||||
if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute");
|
||||
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", "txfax");
|
||||
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", fax_document);
|
||||
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true");
|
||||
if (!switch_channel_test_flag(channel, CF_PROXY_MODE)) {
|
||||
switch_channel_set_flag(channel, CF_BLOCK_BROADCAST_UNTIL_MEDIA);
|
||||
}
|
||||
|
||||
if (switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
|
||||
response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to txfax (queue event failed)");
|
||||
if (execute_event) {
|
||||
switch_event_destroy(&execute_event);
|
||||
}
|
||||
rayo_call_set_faxing(RAYO_CALL(call), 0);
|
||||
RAYO_UNLOCK(sendfax_component);
|
||||
} else {
|
||||
/* component starting... */
|
||||
rayo_component_send_start(RAYO_COMPONENT(sendfax_component), iq);
|
||||
}
|
||||
} else {
|
||||
response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to create txfax event");
|
||||
rayo_call_set_faxing(RAYO_CALL(call), 0);
|
||||
RAYO_UNLOCK(sendfax_component);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start execution of call receivefax component
|
||||
* @param call the call to receive fax from
|
||||
* @param msg the original request
|
||||
* @param session_data the call's session
|
||||
*/
|
||||
static iks *start_receivefax_component(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
|
||||
{
|
||||
iks *iq = msg->payload;
|
||||
switch_core_session_t *session = (switch_core_session_t *)session_data;
|
||||
struct receivefax_component *receivefax_component = NULL;
|
||||
iks *receivefax = iks_find(iq, "receivefax");
|
||||
iks *response = NULL;
|
||||
switch_event_t *execute_event = NULL;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_memory_pool_t *pool;
|
||||
int file_no;
|
||||
|
||||
/* validate attributes */
|
||||
if (!VALIDATE_RAYO_RECEIVEFAX(receivefax)) {
|
||||
return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST);
|
||||
}
|
||||
|
||||
/* fax is only allowed if the call is not currently joined */
|
||||
if (rayo_call_is_joined(RAYO_CALL(call))) {
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "can't receive fax on a joined call");
|
||||
}
|
||||
|
||||
if (rayo_call_is_faxing(RAYO_CALL(call))) {
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "fax already in progress");
|
||||
}
|
||||
|
||||
/* create receivefax component */
|
||||
switch_core_new_memory_pool(&pool);
|
||||
receivefax_component = switch_core_alloc(pool, sizeof(*receivefax_component));
|
||||
rayo_component_init((struct rayo_component *)receivefax_component, pool, RAT_CALL_COMPONENT, "receivefax", NULL, call, iks_find_attrib(iq, "from"));
|
||||
file_no = rayo_actor_seq_next(call);
|
||||
receivefax_component->filename = switch_core_sprintf(pool, "%s%s%s-%d.tif",
|
||||
globals.file_prefix, SWITCH_PATH_SEPARATOR, switch_core_session_get_uuid(session), file_no);
|
||||
if (!strncmp(receivefax_component->filename, "http://", 7) || !strncmp(receivefax_component->filename, "https://", 8)) {
|
||||
/* This is an HTTP URL, need to PUT after fax is received */
|
||||
receivefax_component->local_filename = switch_core_sprintf(pool, "%s%s%s-%d",
|
||||
SWITCH_GLOBAL_dirs.temp_dir, SWITCH_PATH_SEPARATOR, switch_core_session_get_uuid(session), file_no);
|
||||
receivefax_component->http_put_after_receive = 1;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s save fax to HTTP URL\n", RAYO_JID(receivefax_component));
|
||||
} else {
|
||||
/* assume file.. */
|
||||
receivefax_component->local_filename = receivefax_component->filename;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s save fax to local file\n", RAYO_JID(receivefax_component));
|
||||
}
|
||||
|
||||
/* add channel variable so that fax component can be located from fax events */
|
||||
switch_channel_set_variable(channel, "rayo_fax_jid", RAYO_JID(receivefax_component));
|
||||
|
||||
/* clear fax result variables */
|
||||
switch_channel_set_variable(channel, "fax_success", NULL);
|
||||
switch_channel_set_variable(channel, "fax_result_code", NULL);
|
||||
switch_channel_set_variable(channel, "fax_result_text", NULL);
|
||||
switch_channel_set_variable(channel, "fax_document_transferred_pages", NULL);
|
||||
switch_channel_set_variable(channel, "fax_document_total_pages", NULL);
|
||||
switch_channel_set_variable(channel, "fax_image_resolution", NULL);
|
||||
switch_channel_set_variable(channel, "fax_image_size", NULL);
|
||||
switch_channel_set_variable(channel, "fax_bad_rows", NULL);
|
||||
switch_channel_set_variable(channel, "fax_transfer_rate", NULL);
|
||||
switch_channel_set_variable(channel, "fax_ecm_used", NULL);
|
||||
switch_channel_set_variable(channel, "fax_local_station_id", NULL);
|
||||
switch_channel_set_variable(channel, "fax_remote_station_id", NULL);
|
||||
|
||||
/* clear fax interrupt variable */
|
||||
switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_read_frame_interrupt", NULL);
|
||||
|
||||
rayo_call_set_faxing(RAYO_CALL(call), 1);
|
||||
|
||||
/* execute rxfax APP */
|
||||
if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute");
|
||||
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", "rxfax");
|
||||
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", receivefax_component->local_filename);
|
||||
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true");
|
||||
if (!switch_channel_test_flag(channel, CF_PROXY_MODE)) {
|
||||
switch_channel_set_flag(channel, CF_BLOCK_BROADCAST_UNTIL_MEDIA);
|
||||
}
|
||||
|
||||
if (switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
|
||||
response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to rxfax (queue event failed)");
|
||||
if (execute_event) {
|
||||
switch_event_destroy(&execute_event);
|
||||
}
|
||||
rayo_call_set_faxing(RAYO_CALL(call), 0);
|
||||
RAYO_UNLOCK(receivefax_component);
|
||||
} else {
|
||||
/* component starting... */
|
||||
rayo_component_send_start(RAYO_COMPONENT(receivefax_component), iq);
|
||||
}
|
||||
} else {
|
||||
response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to create rxfax event");
|
||||
rayo_call_set_faxing(RAYO_CALL(call), 0);
|
||||
RAYO_UNLOCK(receivefax_component);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop execution of fax component
|
||||
*/
|
||||
static iks *stop_fax_component(struct rayo_actor *component, struct rayo_message *msg, void *data)
|
||||
{
|
||||
iks *iq = msg->payload;
|
||||
switch_core_session_t *session = switch_core_session_locate(RAYO_COMPONENT(component)->parent->id);
|
||||
if (session) {
|
||||
/* fail on read frame until component is destroyed */
|
||||
switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_read_frame_interrupt", RAYO_JID(component));
|
||||
switch_core_session_rwunlock(session);
|
||||
}
|
||||
FAX_COMPONENT(component)->stop = 1;
|
||||
return iks_new_iq_result(iq);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add fax metadata to result
|
||||
* @param event source of metadata
|
||||
* @param name of metadata
|
||||
* @param result to add metadata to
|
||||
*/
|
||||
static void insert_fax_metadata(switch_event_t *event, const char *name, iks *result)
|
||||
{
|
||||
char actual_name[256];
|
||||
const char *value;
|
||||
snprintf(actual_name, sizeof(actual_name), "variable_%s", name);
|
||||
actual_name[sizeof(actual_name) - 1] = '\0';
|
||||
value = switch_event_get_header(event, actual_name);
|
||||
if (!zstr(value)) {
|
||||
iks *metadata = iks_insert(result, "metadata");
|
||||
iks_insert_attrib(metadata, "xmlns", RAYO_FAX_COMPLETE_NS);
|
||||
iks_insert_attrib(metadata, "name", name);
|
||||
iks_insert_attrib(metadata, "value", value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle fax completion event from FreeSWITCH core
|
||||
* @param event received from FreeSWITCH core. It will be destroyed by the core after this function returns.
|
||||
*/
|
||||
static void on_execute_complete_event(switch_event_t *event)
|
||||
{
|
||||
const char *application = switch_event_get_header(event, "Application");
|
||||
|
||||
if (!zstr(application) && (!strcmp(application, "rxfax") || !strcmp(application, "txfax"))) {
|
||||
int is_rxfax = !strcmp(application, "rxfax");
|
||||
const char *uuid = switch_event_get_header(event, "Unique-ID");
|
||||
const char *fax_jid = switch_event_get_header(event, "variable_rayo_fax_jid");
|
||||
struct rayo_actor *component;
|
||||
if (!zstr(fax_jid) && (component = RAYO_LOCATE(fax_jid))) {
|
||||
iks *result;
|
||||
iks *complete;
|
||||
iks *fax;
|
||||
int have_fax_document = 1;
|
||||
switch_core_session_t *session;
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Got result for %s\n", fax_jid);
|
||||
|
||||
/* clean up channel */
|
||||
session = switch_core_session_locate(uuid);
|
||||
if (session) {
|
||||
switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_read_frame_interrupt", NULL);
|
||||
switch_core_session_rwunlock(session);
|
||||
}
|
||||
|
||||
/* RX only: transfer HTTP document and delete local copy */
|
||||
if (is_rxfax && RECEIVEFAX_COMPONENT(component)->http_put_after_receive && switch_file_exists(RECEIVEFAX_COMPONENT(component)->local_filename, RAYO_POOL(component)) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_stream_handle_t stream = { 0 };
|
||||
SWITCH_STANDARD_STREAM(stream);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s PUT fax to %s\n", RAYO_JID(component), RECEIVEFAX_COMPONENT(component)->filename);
|
||||
switch_api_execute("http_put", RECEIVEFAX_COMPONENT(component)->filename, NULL, &stream);
|
||||
/* check if successful */
|
||||
if (!zstr(stream.data) && strncmp(stream.data, "+OK", 3)) {
|
||||
/* PUT failed */
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s PUT fax to %s failed: %s\n", RAYO_JID(component), RECEIVEFAX_COMPONENT(component)->filename, (char *)stream.data);
|
||||
have_fax_document = 0;
|
||||
}
|
||||
switch_safe_free(stream.data)
|
||||
switch_file_remove(RECEIVEFAX_COMPONENT(component)->local_filename, RAYO_POOL(component));
|
||||
}
|
||||
|
||||
/* successful fax? */
|
||||
if (have_fax_document && switch_true(switch_event_get_header(event, "variable_fax_success"))) {
|
||||
result = rayo_component_create_complete_event(RAYO_COMPONENT(component), FAX_FINISH);
|
||||
} else if (have_fax_document && FAX_COMPONENT(component)->stop) {
|
||||
result = rayo_component_create_complete_event(RAYO_COMPONENT(component), COMPONENT_COMPLETE_STOP);
|
||||
} else {
|
||||
result = rayo_component_create_complete_event(RAYO_COMPONENT(component), COMPONENT_COMPLETE_ERROR);
|
||||
}
|
||||
complete = iks_find(result, "complete");
|
||||
|
||||
/* RX only: add fax document information */
|
||||
if (is_rxfax && have_fax_document) {
|
||||
const char *pages = switch_event_get_header(event, "variable_fax_document_transferred_pages");
|
||||
if (!zstr(pages) && switch_is_number(pages) && atoi(pages) > 0) {
|
||||
const char *resolution = switch_event_get_header(event, "variable_fax_file_image_resolution");
|
||||
const char *size = switch_event_get_header(event, "variable_fax_image_size");
|
||||
|
||||
fax = iks_insert(complete, "fax");
|
||||
iks_insert_attrib(fax, "xmlns", RAYO_FAX_COMPLETE_NS);
|
||||
|
||||
if (RECEIVEFAX_COMPONENT(component)->http_put_after_receive) {
|
||||
iks_insert_attrib(fax, "url", RECEIVEFAX_COMPONENT(component)->filename);
|
||||
} else {
|
||||
/* convert absolute path to file:// URI */
|
||||
iks_insert_attrib_printf(fax, "url", "file://%s", RECEIVEFAX_COMPONENT(component)->filename);
|
||||
}
|
||||
|
||||
if (!zstr(resolution)) {
|
||||
iks_insert_attrib(fax, "resolution", resolution);
|
||||
}
|
||||
if (!zstr(size)) {
|
||||
iks_insert_attrib(fax, "size", size);
|
||||
}
|
||||
iks_insert_attrib(fax, "pages", pages);
|
||||
}
|
||||
}
|
||||
|
||||
/* add metadata from event */
|
||||
insert_fax_metadata(event, "fax_success", complete);
|
||||
insert_fax_metadata(event, "fax_result_code", complete);
|
||||
insert_fax_metadata(event, "fax_result_text", complete);
|
||||
insert_fax_metadata(event, "fax_document_transferred_pages", complete);
|
||||
insert_fax_metadata(event, "fax_document_total_pages", complete);
|
||||
insert_fax_metadata(event, "fax_image_resolution", complete);
|
||||
insert_fax_metadata(event, "fax_image_size", complete);
|
||||
insert_fax_metadata(event, "fax_bad_rows", complete);
|
||||
insert_fax_metadata(event, "fax_transfer_rate", complete);
|
||||
insert_fax_metadata(event, "fax_ecm_used", complete);
|
||||
insert_fax_metadata(event, "fax_local_station_id", complete);
|
||||
insert_fax_metadata(event, "fax_remote_station_id", complete);
|
||||
|
||||
/* flag faxing as done */
|
||||
rayo_call_set_faxing(RAYO_CALL(RAYO_COMPONENT(component)->parent), 0);
|
||||
|
||||
rayo_component_send_complete_event(RAYO_COMPONENT(component), result);
|
||||
|
||||
RAYO_UNLOCK(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process module XML configuration
|
||||
* @param pool memory pool to allocate from
|
||||
* @param config_file to use
|
||||
* @return SWITCH_STATUS_SUCCESS on successful configuration
|
||||
*/
|
||||
static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_file)
|
||||
{
|
||||
switch_xml_t cfg, xml;
|
||||
|
||||
/* set defaults */
|
||||
globals.file_prefix = switch_core_sprintf(pool, "%s%s", SWITCH_GLOBAL_dirs.recordings_dir, SWITCH_PATH_SEPARATOR);
|
||||
|
||||
if (!(xml = switch_xml_open_cfg(config_file, &cfg, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", config_file);
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
|
||||
/* get params */
|
||||
{
|
||||
switch_xml_t settings = switch_xml_child(cfg, "fax");
|
||||
if (settings) {
|
||||
switch_xml_t param;
|
||||
for (param = switch_xml_child(settings, "param"); param; param = param->next) {
|
||||
const char *var = switch_xml_attr_soft(param, "name");
|
||||
const char *val = switch_xml_attr_soft(param, "value");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "param: %s = %s\n", var, val);
|
||||
if (!strcasecmp(var, "receivefax-file-prefix")) {
|
||||
if (!zstr(val)) {
|
||||
globals.file_prefix = switch_core_strdup(pool, val);
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported param: %s\n", var);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "receivefax-file-prefix = %s\n", globals.file_prefix);
|
||||
|
||||
switch_xml_free(xml);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize fax components
|
||||
* @param module_interface
|
||||
* @param pool memory pool to allocate from
|
||||
* @param config_file to use
|
||||
* @return SWITCH_STATUS_SUCCESS if successful
|
||||
*/
|
||||
switch_status_t rayo_fax_components_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file)
|
||||
{
|
||||
if (do_config(pool, config_file) != SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
|
||||
switch_event_bind("rayo_fax_components", SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE, NULL, on_execute_complete_event, NULL);
|
||||
|
||||
rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_FAX_NS":receivefax", start_receivefax_component);
|
||||
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "receivefax", "set:"RAYO_EXT_NS":stop", stop_fax_component);
|
||||
|
||||
rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_FAX_NS":sendfax", start_sendfax_component);
|
||||
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "sendfax", "set:"RAYO_EXT_NS":stop", stop_fax_component);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown fax components
|
||||
* @return SWITCH_STATUS_SUCCESS if successful
|
||||
*/
|
||||
switch_status_t rayo_fax_components_shutdown(void)
|
||||
{
|
||||
switch_event_unbind_callback(on_execute_complete_event);
|
||||
|
||||
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 noet
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -644,8 +644,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
|
||||
default:
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s decoder error! [%d]\n",
|
||||
session->read_codec->codec_interface->interface_name, status);
|
||||
goto done;
|
||||
|
||||
if (++session->decoder_errors < 10) {
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
session->decoder_errors = 0;
|
||||
}
|
||||
|
||||
if (session->bugs) {
|
||||
|
||||
+952
-744
File diff suppressed because it is too large
Load Diff
+88
-20
@@ -325,7 +325,6 @@ struct switch_rtp {
|
||||
int8_t sending_dtmf;
|
||||
uint8_t need_mark;
|
||||
switch_payload_t payload;
|
||||
switch_payload_t rpayload;
|
||||
switch_rtp_invalid_handler_t invalid_handler;
|
||||
void *private_data;
|
||||
uint32_t ts;
|
||||
@@ -398,6 +397,10 @@ struct switch_rtp {
|
||||
switch_size_t last_flush_packet_count;
|
||||
uint32_t interdigit_delay;
|
||||
switch_core_session_t *session;
|
||||
payload_map_t **pmaps;
|
||||
payload_map_t *pmap_tail;
|
||||
int pmap_ttl;
|
||||
|
||||
#ifdef ENABLE_ZRTP
|
||||
zrtp_session_t *zrtp_session;
|
||||
zrtp_profile_t *zrtp_profile;
|
||||
@@ -1859,6 +1862,19 @@ SWITCH_DECLARE(switch_port_t) switch_rtp_request_port(const char *ip)
|
||||
return port;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_rtp_set_payload_map(switch_rtp_t *rtp_session, payload_map_t **pmap)
|
||||
{
|
||||
|
||||
if (rtp_session) {
|
||||
switch_mutex_lock(rtp_session->flag_mutex);
|
||||
rtp_session->pmaps = pmap;
|
||||
switch_mutex_unlock(rtp_session->flag_mutex);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_rtp_intentional_bugs(switch_rtp_t *rtp_session, switch_rtp_bug_flag_t bugs)
|
||||
{
|
||||
rtp_session->rtp_bugs = bugs;
|
||||
@@ -2973,7 +2989,6 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
|
||||
rtp_session->recv_msg.header.cc = 0;
|
||||
|
||||
rtp_session->payload = payload;
|
||||
rtp_session->rpayload = payload;
|
||||
|
||||
switch_rtp_set_interval(rtp_session, ms_per_packet, samples_per_interval);
|
||||
rtp_session->conf_samples_per_interval = samples_per_interval;
|
||||
@@ -3164,11 +3179,6 @@ SWITCH_DECLARE(void) switch_rtp_set_telephony_recv_event(switch_rtp_t *rtp_sessi
|
||||
}
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_rtp_set_recv_pt(switch_rtp_t *rtp_session, switch_payload_t pt)
|
||||
{
|
||||
rtp_session->rpayload = pt;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(void) switch_rtp_set_cng_pt(switch_rtp_t *rtp_session, switch_payload_t pt)
|
||||
{
|
||||
@@ -4063,6 +4073,27 @@ static int jb_valid(switch_rtp_t *rtp_session)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_recv_payload(switch_rtp_t *rtp_session)
|
||||
{
|
||||
int ok = 0;
|
||||
|
||||
if (rtp_session->pmaps && *rtp_session->pmaps) {
|
||||
payload_map_t *pmap;
|
||||
switch_mutex_lock(rtp_session->flag_mutex);
|
||||
for (pmap = *rtp_session->pmaps; pmap && pmap->allocated; pmap = pmap->next) {
|
||||
if (!pmap->negotiated) {
|
||||
continue;
|
||||
}
|
||||
if (rtp_session->recv_msg.header.pt == pmap->pt) {
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(rtp_session->flag_mutex);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
#define return_cng_frame() do_cng = 1; goto timer_check
|
||||
|
||||
static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t *bytes, switch_frame_flag_t *flags, switch_bool_t return_jb_packet)
|
||||
@@ -4149,7 +4180,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
|
||||
if (status == SWITCH_STATUS_SUCCESS && *bytes) {
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) {
|
||||
*flags &= ~SFF_RTCP;
|
||||
if (rtp_session->recv_msg.header.pt != rtp_session->rpayload &&
|
||||
if (!check_recv_payload(rtp_session) &&
|
||||
(!rtp_session->recv_te || rtp_session->recv_msg.header.pt != rtp_session->recv_te) &&
|
||||
(!rtp_session->cng_pt || rtp_session->recv_msg.header.pt != rtp_session->cng_pt) &&
|
||||
rtp_session->rtcp_recv_msg_p->header.version == 2 &&
|
||||
@@ -4319,7 +4350,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
|
||||
|
||||
#ifdef ENABLE_SRTP
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV] && rtp_session->recv_msg.header.version == 2 &&
|
||||
((rtp_session->recv_msg.header.pt == rtp_session->rpayload) ||
|
||||
(check_recv_payload(rtp_session) ||
|
||||
(rtp_session->recv_te && rtp_session->recv_msg.header.pt == rtp_session->recv_te) ||
|
||||
(rtp_session->cng_pt && rtp_session->recv_msg.header.pt == rtp_session->cng_pt))) {
|
||||
//if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV] && (!rtp_session->ice.ice_user || rtp_session->recv_msg.header.version == 2)) {
|
||||
@@ -4376,7 +4407,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
|
||||
rtp_session->last_read_ts = ts;
|
||||
}
|
||||
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_BYTESWAP] && rtp_session->recv_msg.header.pt == rtp_session->rpayload) {
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_BYTESWAP] && check_recv_payload(rtp_session)) {
|
||||
switch_swap_linear((int16_t *)RTP_BODY(rtp_session), (int) *bytes - rtp_header_len);
|
||||
}
|
||||
|
||||
@@ -4602,7 +4633,8 @@ static int using_ice(switch_rtp_t *rtp_session)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_type, switch_frame_flag_t *flags, switch_io_flag_t io_flags)
|
||||
static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_type,
|
||||
payload_map_t **pmapP, switch_frame_flag_t *flags, switch_io_flag_t io_flags)
|
||||
{
|
||||
|
||||
switch_channel_t *channel = NULL;
|
||||
@@ -4969,11 +5001,33 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
||||
!rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA] && !rtp_session->flags[SWITCH_RTP_FLAG_UDPTL] &&
|
||||
rtp_session->recv_msg.header.pt != 13 &&
|
||||
rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
|
||||
(!rtp_session->cng_pt || rtp_session->recv_msg.header.pt != rtp_session->cng_pt) &&
|
||||
rtp_session->recv_msg.header.pt != rtp_session->rpayload &&
|
||||
!(rtp_session->rtp_bugs & RTP_BUG_ACCEPT_ANY_PAYLOAD) && !(rtp_session->rtp_bugs & RTP_BUG_ACCEPT_ANY_PACKETS)) {
|
||||
/* drop frames of incorrect payload number and return CNG frame instead */
|
||||
return_cng_frame();
|
||||
(!rtp_session->cng_pt || rtp_session->recv_msg.header.pt != rtp_session->cng_pt)) {
|
||||
int accept_packet = 0;
|
||||
|
||||
|
||||
if (rtp_session->pmaps && *rtp_session->pmaps) {
|
||||
payload_map_t *pmap;
|
||||
switch_mutex_lock(rtp_session->flag_mutex);
|
||||
for (pmap = *rtp_session->pmaps; pmap && pmap->allocated; pmap = pmap->next) {
|
||||
if (!pmap->negotiated) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rtp_session->recv_msg.header.pt == pmap->pt) {
|
||||
accept_packet = 1;
|
||||
if (pmapP) {
|
||||
*pmapP = pmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(rtp_session->flag_mutex);
|
||||
}
|
||||
|
||||
if (!accept_packet &&
|
||||
!(rtp_session->rtp_bugs & RTP_BUG_ACCEPT_ANY_PAYLOAD) && !(rtp_session->rtp_bugs & RTP_BUG_ACCEPT_ANY_PACKETS)) {
|
||||
/* drop frames of incorrect payload number and return CNG frame instead */
|
||||
return_cng_frame();
|
||||
}
|
||||
}
|
||||
|
||||
if (!bytes && (io_flags & SWITCH_IO_FLAG_NOBLOCK)) {
|
||||
@@ -5085,7 +5139,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
||||
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_UDPTL]) {
|
||||
#if 0
|
||||
if (rtp_session->recv_msg.header.version == 2 && rtp_session->recv_msg.header.pt == rtp_session->rpayload) {
|
||||
if (rtp_session->recv_msg.header.version == 2 && check_recv_payload(rtp_session)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_WARNING,
|
||||
"Ignoring udptl packet of size of %ld bytes that looks strikingly like a RTP packet.\n", (long)bytes);
|
||||
bytes = 0;
|
||||
@@ -5335,7 +5389,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_read(switch_rtp_t *rtp_session, void
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
bytes = rtp_common_read(rtp_session, payload_type, flags, io_flags);
|
||||
bytes = rtp_common_read(rtp_session, payload_type, NULL, flags, io_flags);
|
||||
|
||||
if (bytes < 0) {
|
||||
*datalen = 0;
|
||||
@@ -5415,7 +5469,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
bytes = rtp_common_read(rtp_session, &frame->payload, &frame->flags, io_flags);
|
||||
bytes = rtp_common_read(rtp_session, &frame->payload, &frame->pmap, &frame->flags, io_flags);
|
||||
|
||||
frame->data = RTP_BODY(rtp_session);
|
||||
frame->packet = &rtp_session->recv_msg;
|
||||
@@ -5504,7 +5558,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_sessi
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
bytes = rtp_common_read(rtp_session, payload_type, flags, io_flags);
|
||||
bytes = rtp_common_read(rtp_session, payload_type, NULL, flags, io_flags);
|
||||
*data = RTP_BODY(rtp_session);
|
||||
|
||||
if (bytes < 0) {
|
||||
@@ -6146,12 +6200,26 @@ SWITCH_DECLARE(int) switch_rtp_write_frame(switch_rtp_t *rtp_session, switch_fra
|
||||
rtp_session->stats.outbound.packet_count++;
|
||||
}
|
||||
|
||||
if (frame->pmap && rtp_session->pmaps && *rtp_session->pmaps && rtp_session->pmap_ttl > 1) {
|
||||
payload_map_t *pmap;
|
||||
switch_mutex_lock(rtp_session->flag_mutex);
|
||||
|
||||
for (pmap = *rtp_session->pmaps; pmap; pmap = pmap->next) {
|
||||
if (pmap->hash == frame->pmap->hash && !strcmp(pmap->iananame, frame->pmap->iananame)) {
|
||||
payload = pmap->recv_pt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(rtp_session->flag_mutex);
|
||||
}
|
||||
|
||||
if (fwd) {
|
||||
send_msg = frame->packet;
|
||||
len = frame->packetlen;
|
||||
ts = 0;
|
||||
// Trying this based on http://jira.freeswitch.org/browse/MODSOFIA-90
|
||||
//if (frame->codec && frame->codec->agreed_pt == frame->payload) {
|
||||
|
||||
send_msg->header.pt = payload;
|
||||
//}
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -114,7 +114,7 @@ SWITCH_DECLARE(switch_status_t) switch_frame_dup(switch_frame_t *orig, switch_fr
|
||||
|
||||
memcpy(new_frame->data, orig->data, orig->datalen);
|
||||
new_frame->codec = NULL;
|
||||
|
||||
new_frame->pmap = NULL;
|
||||
*clone = new_frame;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
Reference in New Issue
Block a user