Compare commits
13 Commits
cef3b4f181
...
91e66323a5
Author | SHA1 | Date |
---|---|---|
Aron Podrigal | 91e66323a5 | |
Aron Podrigal | 334b4ce204 | |
Aron Podrigal | 96de8fd377 | |
Andrey Volk | 55d8f3ff97 | |
Andrey Volk | 6bad50d875 | |
Andrey Volk | 2970101bd8 | |
Andrey Volk | b3cdc8a783 | |
Andrey Volk | f1524d397c | |
Andrey Volk | 74c6433955 | |
Andrey Volk | 4f17bc760c | |
Andrey Volk | e600ab66a7 | |
Andrey Volk | ca5b32701c | |
Aron Podrigal | 083e6ae80f |
|
@ -588,10 +588,6 @@ libs/srtp/libsrtp.la: libs/srtp libs/srtp/.update $(SRTP_SRC)
|
|||
##
|
||||
## helper targets
|
||||
##
|
||||
yaml-files:
|
||||
@echo `mkdir $(DESTDIR)$(confdir)/yaml 2>/dev/null`
|
||||
$(INSTALL) -m 644 $(switch_srcdir)/conf/default/yaml/*.yaml $(DESTDIR)$(confdir)/yaml
|
||||
|
||||
vm-sync:
|
||||
test -d $(DESTDIR)$(confdir) || $(mkinstalldirs) $(DESTDIR)$(confdir)
|
||||
test -d $(DESTDIR)$(confdir)/lang || $(mkinstalldirs) $(DESTDIR)$(confdir)/lang
|
||||
|
|
|
@ -29,7 +29,6 @@ applications/mod_httapi
|
|||
#applications/mod_memcache
|
||||
#applications/mod_mongo
|
||||
#applications/mod_nibblebill
|
||||
#applications/mod_oreka
|
||||
#applications/mod_osp
|
||||
#applications/mod_prefix
|
||||
#applications/mod_redis
|
||||
|
@ -52,7 +51,6 @@ codecs/mod_amr
|
|||
#codecs/mod_amrwb
|
||||
codecs/mod_b64
|
||||
#codecs/mod_bv
|
||||
#codecs/mod_clearmode
|
||||
#codecs/mod_codec2
|
||||
#codecs/mod_com_g729
|
||||
codecs/mod_g723_1
|
||||
|
@ -61,7 +59,6 @@ codecs/mod_g729
|
|||
codecs/mod_opus
|
||||
#codecs/mod_silk
|
||||
#codecs/mod_siren
|
||||
#codecs/mod_theora
|
||||
#databases/mod_mariadb
|
||||
databases/mod_pgsql
|
||||
dialplans/mod_dialplan_asterisk
|
||||
|
@ -109,7 +106,6 @@ languages/mod_lua
|
|||
#languages/mod_python
|
||||
#languages/mod_python3
|
||||
#languages/mod_v8
|
||||
#languages/mod_yaml
|
||||
loggers/mod_console
|
||||
#loggers/mod_graylog2
|
||||
loggers/mod_logfile
|
||||
|
|
|
@ -29,7 +29,6 @@ applications/mod_lcr
|
|||
applications/mod_memcache
|
||||
applications/mod_mongo
|
||||
applications/mod_nibblebill
|
||||
applications/mod_oreka
|
||||
#applications/mod_osp
|
||||
applications/mod_prefix
|
||||
applications/mod_redis
|
||||
|
@ -60,7 +59,6 @@ codecs/mod_ilbc
|
|||
codecs/mod_opus
|
||||
codecs/mod_silk
|
||||
codecs/mod_siren
|
||||
codecs/mod_theora
|
||||
#databases/mod_mariadb
|
||||
databases/mod_pgsql
|
||||
dialplans/mod_dialplan_asterisk
|
||||
|
@ -104,7 +102,6 @@ languages/mod_managed
|
|||
languages/mod_perl
|
||||
languages/mod_python3
|
||||
#languages/mod_v8
|
||||
languages/mod_yaml
|
||||
loggers/mod_console
|
||||
loggers/mod_graylog2
|
||||
loggers/mod_logfile
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
<load module="mod_logfile"/>
|
||||
<!-- <load module="mod_syslog"/> -->
|
||||
|
||||
<!--<load module="mod_yaml"/>-->
|
||||
|
||||
<!-- Multi-Faceted -->
|
||||
<!-- mod_enum is a dialplan interface, an application interface and an api command interface -->
|
||||
<load module="mod_enum"/>
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
<load module="mod_logfile"/>
|
||||
<!-- <load module="mod_syslog"/> -->
|
||||
|
||||
<!--<load module="mod_yaml"/>-->
|
||||
|
||||
<!-- Multi-Faceted -->
|
||||
<!-- mod_enum is a dialplan interface, an application interface and an api command interface -->
|
||||
<load module="mod_enum"/>
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
<!--
|
||||
To use this application simply install the open source Oreka recorder server (Orkaudio) and point
|
||||
the sip-server-addr and sip-server-port to the oreka server
|
||||
-->
|
||||
<configuration name="oreka.conf" description="Oreka Recorder configuration">
|
||||
<settings>
|
||||
<!-- Oreka/Orkaudio recording server address -->
|
||||
<!-- <param name="sip-server-addr" value="192.168.1.200"/> -->
|
||||
|
||||
<!-- Which port to send signaling to in the recording server -->
|
||||
<!-- <param name="sip-server-port" value="6000"/> -->
|
||||
</settings>
|
||||
</configuration>
|
|
@ -1,4 +0,0 @@
|
|||
default:
|
||||
${destination_number} =~ (9664):
|
||||
set: foo=bar
|
||||
playback: ${hold_music}
|
|
@ -1,6 +0,0 @@
|
|||
settings:
|
||||
#look for foo.conf.yaml when foo.conf is looked for in the xml
|
||||
bind_config: true
|
||||
|
||||
|
||||
|
|
@ -1330,9 +1330,6 @@ PKG_CHECK_MODULES([SQLITE], [sqlite3 >= 3.6.20])
|
|||
PKG_CHECK_MODULES([CURL], [libcurl >= 7.19])
|
||||
PKG_CHECK_MODULES([PCRE], [libpcre >= 7.8])
|
||||
PKG_CHECK_MODULES([SPEEX], [speex >= 1.2rc1 speexdsp >= 1.2rc1])
|
||||
PKG_CHECK_MODULES([YAML], [yaml-0.1 >= 0.1.4],[
|
||||
AM_CONDITIONAL([HAVE_YAML],[true])],[
|
||||
AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_YAML],[false])])
|
||||
PKG_CHECK_MODULES([LDNS], [libldns-fs >= 1.6.6],[
|
||||
AM_CONDITIONAL([HAVE_LDNS],[true])],[
|
||||
PKG_CHECK_MODULES([LDNS], [libldns >= 1.6.6],[
|
||||
|
@ -2121,7 +2118,6 @@ AC_CONFIG_FILES([Makefile
|
|||
src/mod/applications/mod_memcache/Makefile
|
||||
src/mod/applications/mod_mongo/Makefile
|
||||
src/mod/applications/mod_nibblebill/Makefile
|
||||
src/mod/applications/mod_oreka/Makefile
|
||||
src/mod/applications/mod_osp/Makefile
|
||||
src/mod/applications/mod_prefix/Makefile
|
||||
src/mod/applications/mod_random/Makefile
|
||||
|
@ -2145,7 +2141,6 @@ AC_CONFIG_FILES([Makefile
|
|||
src/mod/codecs/mod_amrwb/Makefile
|
||||
src/mod/codecs/mod_b64/Makefile
|
||||
src/mod/codecs/mod_bv/Makefile
|
||||
src/mod/codecs/mod_clearmode/Makefile
|
||||
src/mod/codecs/mod_codec2/Makefile
|
||||
src/mod/codecs/mod_com_g729/Makefile
|
||||
src/mod/codecs/mod_g723_1/Makefile
|
||||
|
@ -2156,7 +2151,6 @@ AC_CONFIG_FILES([Makefile
|
|||
src/mod/codecs/mod_silk/Makefile
|
||||
src/mod/codecs/mod_siren/Makefile
|
||||
src/mod/codecs/mod_skel_codec/Makefile
|
||||
src/mod/codecs/mod_theora/Makefile
|
||||
src/mod/databases/mod_mariadb/Makefile
|
||||
src/mod/databases/mod_pgsql/Makefile
|
||||
src/mod/dialplans/mod_dialplan_asterisk/Makefile
|
||||
|
@ -2205,7 +2199,6 @@ AC_CONFIG_FILES([Makefile
|
|||
src/mod/languages/mod_python/Makefile
|
||||
src/mod/languages/mod_python3/Makefile
|
||||
src/mod/languages/mod_v8/Makefile
|
||||
src/mod/languages/mod_yaml/Makefile
|
||||
src/mod/languages/mod_basic/Makefile
|
||||
src/mod/loggers/mod_console/Makefile
|
||||
src/mod/loggers/mod_graylog2/Makefile
|
||||
|
|
|
@ -529,7 +529,6 @@ Recommends:
|
|||
freeswitch-mod-http-cache (= \${binary:Version}),
|
||||
freeswitch-mod-lcr (= \${binary:Version}),
|
||||
freeswitch-mod-nibblebill (= \${binary:Version}),
|
||||
freeswitch-mod-oreka (= \${binary:Version}),
|
||||
freeswitch-mod-pgsql (= \${binary:Version}),
|
||||
freeswitch-mod-redis (= \${binary:Version}),
|
||||
freeswitch-mod-sms (= \${binary:Version}),
|
||||
|
@ -610,7 +609,6 @@ Depends: \${misc:Depends}, freeswitch (= \${binary:Version}),
|
|||
freeswitch-mod-lcr (= \${binary:Version}),
|
||||
freeswitch-mod-memcache (= \${binary:Version}),
|
||||
freeswitch-mod-nibblebill (= \${binary:Version}),
|
||||
freeswitch-mod-oreka (= \${binary:Version}),
|
||||
freeswitch-mod-mariadb (= \${binary:Version}),
|
||||
freeswitch-mod-pgsql (= \${binary:Version}),
|
||||
freeswitch-mod-png (= \${binary:Version}),
|
||||
|
@ -655,7 +653,6 @@ Depends: \${misc:Depends}, freeswitch (= \${binary:Version}),
|
|||
freeswitch-mod-lua (= \${binary:Version}),
|
||||
freeswitch-mod-perl (= \${binary:Version}),
|
||||
freeswitch-mod-python3 (= \${binary:Version}),
|
||||
freeswitch-mod-yaml (= \${binary:Version}),
|
||||
freeswitch-mod-console (= \${binary:Version}),
|
||||
freeswitch-mod-logfile (= \${binary:Version}),
|
||||
freeswitch-mod-syslog (= \${binary:Version}),
|
||||
|
@ -688,7 +685,6 @@ Depends: \${misc:Depends}, freeswitch (= \${binary:Version}),
|
|||
freeswitch-mod-opus (= \${binary:Version}),
|
||||
freeswitch-mod-silk (= \${binary:Version}),
|
||||
freeswitch-mod-spandsp (= \${binary:Version}),
|
||||
freeswitch-mod-theora (= \${binary:Version}),
|
||||
Suggests:
|
||||
freeswitch-mod-ilbc (= \${binary:Version}),
|
||||
freeswitch-mod-siren (= \${binary:Version})
|
||||
|
@ -711,7 +707,6 @@ Depends: \${misc:Depends}, freeswitch (= \${binary:Version}),
|
|||
freeswitch-mod-opus-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-silk-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-spandsp-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-theora-dbg (= \${binary:Version}),
|
||||
Suggests:
|
||||
freeswitch-mod-ilbc-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-siren-dbg (= \${binary:Version})
|
||||
|
@ -832,7 +827,6 @@ Depends: \${misc:Depends}, freeswitch (= \${binary:Version}),
|
|||
freeswitch-mod-lcr-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-memcache-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-nibblebill-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-oreka-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-mariadb-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-pgsql-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-png-dbg (= \${binary:Version}),
|
||||
|
@ -875,7 +869,6 @@ Depends: \${misc:Depends}, freeswitch (= \${binary:Version}),
|
|||
freeswitch-mod-lua-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-perl-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-python3-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-yaml-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-console-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-logfile-dbg (= \${binary:Version}),
|
||||
freeswitch-mod-syslog-dbg (= \${binary:Version}),
|
||||
|
|
|
@ -149,11 +149,6 @@ Description: Nibblebill
|
|||
This module allows for real-time accounting of a cash balance and
|
||||
using that information for call routing.
|
||||
|
||||
Module: applications/mod_oreka
|
||||
Description: Media recording with Oreka
|
||||
This module provides media recording with the Oreka cross-platfor
|
||||
audio stream recording and retrieval system.
|
||||
|
||||
Module: applications/mod_osp
|
||||
Description: Open Settlement Protocol
|
||||
This module adds support for the Open Settlement Protocol (OSP).
|
||||
|
@ -308,10 +303,6 @@ Module: codecs/mod_skel_codec
|
|||
Description: Adds mod_skel_codec
|
||||
Adds mod_skel_codec.
|
||||
|
||||
Module: codecs/mod_theora
|
||||
Description: mod_theora
|
||||
Adds mod_theora.
|
||||
|
||||
Module: codecs/mod_yuv
|
||||
Description: Adds mod_yuv
|
||||
Adds mod_yuv.
|
||||
|
@ -562,11 +553,6 @@ Description: mod_v8
|
|||
Adds mod_v8.
|
||||
Build-Depends: git, libv8-6.1-dev
|
||||
|
||||
Module: languages/mod_yaml
|
||||
Description: mod_yaml
|
||||
Adds mod_yaml.
|
||||
Build-Depends: libyaml-dev, libglib2.0-dev
|
||||
|
||||
## mod/loggers
|
||||
|
||||
Module: loggers/mod_console
|
||||
|
|
|
@ -683,14 +683,6 @@ see http://www.polycom.com/usa/en/company/about_us/technology/siren_g7221/siren_
|
|||
and http://www.polycom.com/usa/en/company/about_us/technology/siren14_g7221c/siren14_g7221c.html
|
||||
At the time of this packaging, Polycom does not charge for licensing.
|
||||
|
||||
%package codec-theora
|
||||
Summary: Theora Video Codec support for FreeSWITCH open source telephony platform
|
||||
Group: System/Libraries
|
||||
Requires: %{name} = %{version}-%{release}
|
||||
|
||||
%description codec-theora
|
||||
Theora Video Codec support for FreeSWITCH open source telephony platform.
|
||||
|
||||
######################################################################################################################
|
||||
# FreeSWITCH Database Modules
|
||||
######################################################################################################################
|
||||
|
@ -1242,7 +1234,7 @@ ASR_TTS_MODULES="asr_tts/mod_flite asr_tts/mod_pocketsphinx asr_tts/mod_tts_comm
|
|||
######################################################################################################################
|
||||
CODECS_MODULES="codecs/mod_amr codecs/mod_amrwb codecs/mod_bv codecs/mod_codec2 codecs/mod_g723_1 \
|
||||
codecs/mod_g729 codecs/mod_ilbc codecs/mod_opus codecs/mod_silk \
|
||||
codecs/mod_siren codecs/mod_theora"
|
||||
codecs/mod_siren"
|
||||
#
|
||||
|
||||
######################################################################################################################
|
||||
|
@ -1709,7 +1701,6 @@ fi
|
|||
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/msrp.conf.xml
|
||||
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/nibblebill.conf.xml
|
||||
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/opal.conf.xml
|
||||
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/oreka.conf.xml
|
||||
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/osp.conf.xml
|
||||
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/pocketsphinx.conf.xml
|
||||
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/post_load_modules.conf.xml
|
||||
|
@ -1947,9 +1938,6 @@ fi
|
|||
%files codec-siren
|
||||
%{MODINSTDIR}/mod_siren.so*
|
||||
|
||||
%files codec-theora
|
||||
%{MODINSTDIR}/mod_theora.so*
|
||||
|
||||
######################################################################################################################
|
||||
#
|
||||
# FreeSWITCH Database Modules
|
||||
|
|
|
@ -898,7 +898,7 @@ SWITCH_STANDARD_APP(curl_app_function)
|
|||
if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
|
||||
if (argc == 0) {
|
||||
switch_goto_status(SWITCH_STATUS_SUCCESS, usage);
|
||||
} else if (argc >= MOD_CURL_MAX_ARGS) {
|
||||
} else if (argc > MOD_CURL_MAX_ARGS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Max args exceeded: %d\n", MOD_CURL_MAX_ARGS);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
}
|
||||
|
@ -1021,7 +1021,7 @@ SWITCH_STANDARD_API(curl_function)
|
|||
if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
|
||||
if (argc < 1) {
|
||||
switch_goto_status(SWITCH_STATUS_SUCCESS, usage);
|
||||
} else if (argc >= MOD_CURL_MAX_ARGS) {
|
||||
} else if (argc > MOD_CURL_MAX_ARGS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Max args exceeded: %d\n", MOD_CURL_MAX_ARGS);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, done);
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
include $(top_srcdir)/build/modmake.rulesam
|
||||
MODNAME=mod_oreka
|
||||
|
||||
mod_LTLIBRARIES = mod_oreka.la
|
||||
mod_oreka_la_SOURCES = mod_oreka.c
|
||||
mod_oreka_la_CFLAGS = $(AM_CFLAGS)
|
||||
mod_oreka_la_LIBADD = $(switch_builddir)/libfreeswitch.la
|
||||
mod_oreka_la_LDFLAGS = -avoid-version -module -no-undefined -shared
|
|
@ -1,786 +0,0 @@
|
|||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Oreka Recording Module
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Moises Silva <moises.silva@gmail.com>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Moises Silva <moises.silva@gmail.com>
|
||||
*
|
||||
* mod_oreka -- Module for Media Recording with Oreka
|
||||
*
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <g711.h>
|
||||
|
||||
static const char SIP_OREKA_HEADER_PREFIX[] = "oreka_sip_h_";
|
||||
#define OREKA_PRIVATE "_oreka_"
|
||||
#define OREKA_BUG_NAME_READ "oreka_read"
|
||||
#define OREKA_BUG_NAME_WRITE "oreka_write"
|
||||
#define SIP_OREKA_HEADER_PREFIX_LEN (sizeof(SIP_OREKA_HEADER_PREFIX)-1)
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_oreka_load);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_oreka_shutdown);
|
||||
SWITCH_MODULE_DEFINITION(mod_oreka, mod_oreka_load, mod_oreka_shutdown, NULL);
|
||||
|
||||
typedef struct oreka_session_s {
|
||||
switch_core_session_t *session;
|
||||
switch_port_t read_rtp_port;
|
||||
switch_port_t write_rtp_port;
|
||||
switch_rtp_t *read_rtp_stream;
|
||||
switch_rtp_t *write_rtp_stream;
|
||||
switch_codec_implementation_t read_impl;
|
||||
switch_codec_implementation_t write_impl;
|
||||
uint32_t read_cnt;
|
||||
uint32_t write_cnt;
|
||||
switch_media_bug_t *read_bug;
|
||||
switch_event_t *invite_extra_headers;
|
||||
switch_event_t *bye_extra_headers;
|
||||
int usecnt;
|
||||
switch_audio_resampler_t *read_resampler;
|
||||
switch_audio_resampler_t *write_resampler;
|
||||
int mux_streams;
|
||||
} oreka_session_t;
|
||||
|
||||
static struct {
|
||||
char local_ipv4_str[256];
|
||||
char sip_server_addr_str[256];
|
||||
char sip_server_ipv4_str[256];
|
||||
int sip_server_port;
|
||||
switch_sockaddr_t *sip_server_addr;
|
||||
switch_socket_t *sip_socket;
|
||||
pid_t our_pid;
|
||||
int mux_streams;
|
||||
} globals;
|
||||
|
||||
typedef enum {
|
||||
FS_OREKA_START,
|
||||
FS_OREKA_STOP
|
||||
} oreka_recording_status_t;
|
||||
|
||||
typedef enum {
|
||||
FS_OREKA_READ,
|
||||
FS_OREKA_WRITE
|
||||
} oreka_stream_type_t;
|
||||
|
||||
static int oreka_write_udp(oreka_session_t *oreka, switch_stream_handle_t *udp)
|
||||
{
|
||||
switch_size_t udplen = udp->data_len;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(oreka->session), SWITCH_LOG_DEBUG, "Oreka SIP Packet:\n%s", (const char *)udp->data);
|
||||
switch_socket_sendto(globals.sip_socket, globals.sip_server_addr, 0, (void *)udp->data, &udplen);
|
||||
if (udplen != udp->data_len) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(oreka->session), SWITCH_LOG_ERROR, "Failed to write SIP Packet of len %zd (wrote=%zd)",
|
||||
udp->data_len, udplen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oreka_tear_down_rtp(oreka_session_t *oreka, oreka_stream_type_t type)
|
||||
{
|
||||
if (type == FS_OREKA_READ && oreka->read_rtp_stream) {
|
||||
switch_rtp_release_port(globals.local_ipv4_str, oreka->read_rtp_port);
|
||||
switch_rtp_destroy(&oreka->read_rtp_stream);
|
||||
oreka->read_rtp_port = 0;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(oreka->session), SWITCH_LOG_DEBUG, "Destroyed read rtp\n");
|
||||
} else if (oreka->write_rtp_stream) {
|
||||
switch_rtp_release_port(globals.local_ipv4_str, oreka->write_rtp_port);
|
||||
switch_rtp_destroy(&oreka->write_rtp_stream);
|
||||
oreka->write_rtp_port = 0;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(oreka->session), SWITCH_LOG_DEBUG, "Destroyed write rtp\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oreka_setup_rtp(oreka_session_t *oreka, oreka_stream_type_t type)
|
||||
{
|
||||
switch_port_t rtp_port = 0;
|
||||
switch_rtp_flag_t flags[SWITCH_RTP_FLAG_INVALID] = {0};
|
||||
switch_rtp_t *rtp_stream = NULL;
|
||||
switch_codec_implementation_t *codec_impl = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
int res = 0;
|
||||
const char *err = "unknown error";
|
||||
const char *type_str = type == FS_OREKA_READ ? "read" : "write";
|
||||
|
||||
|
||||
if (type == FS_OREKA_READ) {
|
||||
status = switch_core_session_get_read_impl(oreka->session, &oreka->read_impl);
|
||||
codec_impl = &oreka->read_impl;
|
||||
} else {
|
||||
status = switch_core_session_get_write_impl(oreka->session, &oreka->write_impl);
|
||||
codec_impl = &oreka->write_impl;
|
||||
}
|
||||
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No %s codec implementation available!\n", type_str);
|
||||
res = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(rtp_port = switch_rtp_request_port(globals.local_ipv4_str))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to allocate %s RTP port for IP %s\n", type_str, globals.local_ipv4_str);
|
||||
res = -1;
|
||||
goto done;
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Allocated %s port %d for local IP %s, destination IP %s\n", type_str,
|
||||
rtp_port, globals.local_ipv4_str, globals.sip_server_ipv4_str);
|
||||
rtp_stream = switch_rtp_new(globals.local_ipv4_str, rtp_port,
|
||||
globals.sip_server_ipv4_str, rtp_port,
|
||||
0, /* PCMU IANA*/
|
||||
codec_impl->samples_per_packet,
|
||||
codec_impl->microseconds_per_packet,
|
||||
flags, NULL, &err, switch_core_session_get_pool(oreka->session), 0, 0);
|
||||
if (!rtp_stream) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create %s RTP stream at %s:%d: %s\n",
|
||||
type_str, globals.local_ipv4_str, rtp_port, err);
|
||||
res = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_rtp_intentional_bugs(rtp_stream, RTP_BUG_SEND_LINEAR_TIMESTAMPS);
|
||||
|
||||
|
||||
done:
|
||||
if (res == -1) {
|
||||
if (rtp_port) {
|
||||
switch_rtp_release_port(globals.local_ipv4_str, rtp_port);
|
||||
}
|
||||
if (rtp_stream) {
|
||||
switch_rtp_destroy(&rtp_stream);
|
||||
}
|
||||
} else {
|
||||
if (type == FS_OREKA_READ) {
|
||||
oreka->read_rtp_stream = rtp_stream;
|
||||
oreka->read_rtp_port = rtp_port;
|
||||
} else {
|
||||
oreka->write_rtp_stream = rtp_stream;
|
||||
oreka->write_rtp_port = rtp_port;
|
||||
}
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Successfully created %s RTP stream at %s:%d at %dms@%dHz\n",
|
||||
type_str, globals.local_ipv4_str, rtp_port, codec_impl->microseconds_per_packet/1000, codec_impl->samples_per_second);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void save_extra_headers(switch_event_t *extra_headers, switch_channel_t *channel)
|
||||
{
|
||||
switch_event_header_t *ei = NULL;
|
||||
for (ei = switch_channel_variable_first(channel);
|
||||
ei;
|
||||
ei = ei->next) {
|
||||
const char *name = ei->name;
|
||||
char *value = ei->value;
|
||||
if (!strncasecmp(name, SIP_OREKA_HEADER_PREFIX, SIP_OREKA_HEADER_PREFIX_LEN)) {
|
||||
switch_event_add_header_string(extra_headers, SWITCH_STACK_BOTTOM, name, value);
|
||||
}
|
||||
}
|
||||
switch_channel_variable_last(channel);
|
||||
|
||||
/* Remove the custom header variables that were saved */
|
||||
for (ei = extra_headers->headers;
|
||||
ei;
|
||||
ei = ei->next) {
|
||||
char *varname = ei->name;
|
||||
switch_channel_set_variable(channel, varname, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static switch_event_t *get_extra_headers(oreka_session_t *oreka, oreka_recording_status_t status)
|
||||
{
|
||||
switch_event_t *extra_headers = NULL;
|
||||
switch_channel_t *channel = NULL;
|
||||
switch_core_session_t *session = oreka->session;
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
if (status == FS_OREKA_START) {
|
||||
if (!oreka->invite_extra_headers) {
|
||||
switch_event_create_subclass(&oreka->invite_extra_headers, SWITCH_EVENT_CLONE, NULL);
|
||||
switch_assert(oreka->invite_extra_headers);
|
||||
save_extra_headers(oreka->invite_extra_headers, channel);
|
||||
}
|
||||
extra_headers = oreka->invite_extra_headers;
|
||||
} else if (status == FS_OREKA_STOP) {
|
||||
if (!oreka->bye_extra_headers) {
|
||||
switch_event_create_subclass(&oreka->bye_extra_headers, SWITCH_EVENT_CLONE, NULL);
|
||||
switch_assert(oreka->bye_extra_headers);
|
||||
save_extra_headers(oreka->bye_extra_headers, channel);
|
||||
}
|
||||
extra_headers = oreka->bye_extra_headers;
|
||||
}
|
||||
return extra_headers;
|
||||
}
|
||||
|
||||
static void oreka_destroy(oreka_session_t *oreka)
|
||||
{
|
||||
oreka->usecnt--;
|
||||
if (!oreka->usecnt) {
|
||||
if (oreka->invite_extra_headers) {
|
||||
switch_event_destroy(&oreka->invite_extra_headers);
|
||||
}
|
||||
if (oreka->bye_extra_headers) {
|
||||
switch_event_destroy(&oreka->bye_extra_headers);
|
||||
}
|
||||
/* Actual memory for the oreka session was taken from the switch core session pool, the core will take care of it */
|
||||
}
|
||||
}
|
||||
|
||||
static int oreka_send_sip_message(oreka_session_t *oreka, oreka_recording_status_t status, oreka_stream_type_t type)
|
||||
{
|
||||
switch_stream_handle_t sip_header = { 0 };
|
||||
switch_stream_handle_t sdp = { 0 };
|
||||
switch_stream_handle_t udp_packet = { 0 };
|
||||
switch_caller_profile_t *caller_profile = NULL;
|
||||
switch_channel_t *channel = NULL;
|
||||
switch_event_t *extra_headers = NULL;
|
||||
switch_event_header_t *ei = NULL;
|
||||
switch_core_session_t *session = oreka->session;
|
||||
const char *method = status == FS_OREKA_START ? "INVITE" : "BYE";
|
||||
const char *session_uuid = switch_core_session_get_uuid(oreka->session);
|
||||
const char *caller_id_number = NULL;
|
||||
const char *caller_id_name = NULL;
|
||||
const char *callee_id_number = NULL;
|
||||
const char *callee_id_name = NULL;
|
||||
int rc = 0;
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
|
||||
SWITCH_STANDARD_STREAM(sip_header);
|
||||
SWITCH_STANDARD_STREAM(sdp);
|
||||
SWITCH_STANDARD_STREAM(udp_packet);
|
||||
|
||||
extra_headers = get_extra_headers(oreka, status);
|
||||
|
||||
caller_profile = switch_channel_get_caller_profile(channel);
|
||||
|
||||
/* Get caller meta data */
|
||||
caller_id_number = switch_caller_get_field_by_name(caller_profile, "caller_id_number");
|
||||
|
||||
caller_id_name = switch_caller_get_field_by_name(caller_profile, "caller_id_name");
|
||||
if (zstr(caller_id_name)) {
|
||||
caller_id_name = caller_id_number;
|
||||
}
|
||||
|
||||
callee_id_number = switch_caller_get_field_by_name(caller_profile, "callee_id_number");
|
||||
if (zstr(callee_id_number)) {
|
||||
callee_id_number = switch_caller_get_field_by_name(caller_profile, "destination_number");
|
||||
}
|
||||
|
||||
callee_id_name = switch_caller_get_field_by_name(caller_profile, "callee_id_name");
|
||||
if (zstr(callee_id_name)) {
|
||||
callee_id_name = callee_id_number;
|
||||
}
|
||||
|
||||
/* Setup the RTP */
|
||||
if (status == FS_OREKA_START) {
|
||||
if (oreka_setup_rtp(oreka, type)) {
|
||||
rc = -1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == FS_OREKA_STOP) {
|
||||
oreka_tear_down_rtp(oreka, type);
|
||||
}
|
||||
|
||||
/* Fill in the SDP first if this is the beginning */
|
||||
if (status == FS_OREKA_START) {
|
||||
sdp.write_function(&sdp, "v=0\r\n");
|
||||
sdp.write_function(&sdp, "o=freeswitch %s 1 IN IP4 %s\r\n", session_uuid, globals.local_ipv4_str);
|
||||
sdp.write_function(&sdp, "c=IN IP4 %s\r\n", globals.sip_server_ipv4_str);
|
||||
sdp.write_function(&sdp, "s=Phone Recording (%s)\r\n", type == FS_OREKA_READ ? "RX" : "TX");
|
||||
sdp.write_function(&sdp, "i=FreeSWITCH Oreka Recorder (pid=%d)\r\n", globals.our_pid);
|
||||
sdp.write_function(&sdp, "m=audio %d RTP/AVP 0\r\n", type == FS_OREKA_READ ? oreka->read_rtp_port : oreka->write_rtp_port);
|
||||
sdp.write_function(&sdp, "a=rtpmap:0 PCMU/%d\r\n", type == FS_OREKA_READ
|
||||
? oreka->read_impl.samples_per_second : oreka->write_impl.samples_per_second);
|
||||
}
|
||||
|
||||
/* Request line */
|
||||
sip_header.write_function(&sip_header, "%s sip:%s@%s:5060 SIP/2.0\r\n", method, callee_id_name, globals.local_ipv4_str);
|
||||
|
||||
/* Via */
|
||||
sip_header.write_function(&sip_header, "Via: SIP/2.0/UDP %s:5061;branch=z9hG4bK-%s\r\n", globals.local_ipv4_str, session_uuid);
|
||||
|
||||
/* From */
|
||||
sip_header.write_function(&sip_header, "From: <sip:%s@%s:5061;tag=1>\r\n", caller_id_number, globals.local_ipv4_str);
|
||||
|
||||
/* To */
|
||||
sip_header.write_function(&sip_header, "To: <sip:%s@%s:5060>\r\n", callee_id_number, globals.local_ipv4_str);
|
||||
|
||||
/* Call-ID */
|
||||
sip_header.write_function(&sip_header, "Call-ID: %s\r\n", session_uuid);
|
||||
|
||||
/* CSeq */
|
||||
sip_header.write_function(&sip_header, "CSeq: 1 %s\r\n", method);
|
||||
|
||||
/* Contact */
|
||||
sip_header.write_function(&sip_header, "Contact: sip:freeswitch@%s:5061\r\n", globals.local_ipv4_str);
|
||||
|
||||
/* Max-Forwards */
|
||||
sip_header.write_function(&sip_header, "Max-Forwards: 70\r\n", method);
|
||||
|
||||
/* Subject */
|
||||
sip_header.write_function(&sip_header, "Subject: %s %s recording of %s\r\n",
|
||||
status == FS_OREKA_START ? "BEGIN": "END",
|
||||
type == FS_OREKA_READ ? "RX" : "TX", caller_id_name);
|
||||
|
||||
/* Add any custom extra headers */
|
||||
for (ei = extra_headers->headers;
|
||||
ei;
|
||||
ei = ei->next) {
|
||||
const char *name = ei->name;
|
||||
char *value = ei->value;
|
||||
if (!strncasecmp(name, SIP_OREKA_HEADER_PREFIX, SIP_OREKA_HEADER_PREFIX_LEN)) {
|
||||
const char *hname = name + SIP_OREKA_HEADER_PREFIX_LEN;
|
||||
sip_header.write_function(&sip_header, "%s: %s\r\n", hname, value);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Adding custom oreka SIP header %s: %s\n", hname, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (status == FS_OREKA_START) {
|
||||
/* Content-Type */
|
||||
sip_header.write_function(&sip_header, "Content-Type: application/sdp\r\n");
|
||||
|
||||
}
|
||||
|
||||
/* Content-Length */
|
||||
sip_header.write_function(&sip_header, "Content-Length: %d\r\n", sdp.data_len);
|
||||
|
||||
udp_packet.write_function(&udp_packet, "%s\r\n%s\n", sip_header.data, sdp.data);
|
||||
|
||||
oreka_write_udp(oreka, &udp_packet);
|
||||
|
||||
done:
|
||||
if (sip_header.data) {
|
||||
free(sip_header.data);
|
||||
}
|
||||
|
||||
if (sdp.data) {
|
||||
free(sdp.data);
|
||||
}
|
||||
|
||||
if (udp_packet.data) {
|
||||
free(udp_packet.data);
|
||||
}
|
||||
|
||||
if (status == FS_OREKA_STOP) {
|
||||
oreka_destroy(oreka);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static switch_bool_t oreka_audio_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
|
||||
{
|
||||
oreka_session_t *oreka = user_data;
|
||||
switch_core_session_t *session = oreka->session;
|
||||
switch_frame_t pcmu_frame = { 0 };
|
||||
switch_frame_t *linear_frame, raw_frame = { 0 };
|
||||
uint8_t pcmu_data[SWITCH_RECOMMENDED_BUFFER_SIZE];
|
||||
uint8_t raw_data[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
|
||||
uint8_t resample_data[SWITCH_RECOMMENDED_BUFFER_SIZE];
|
||||
uint32_t linear_len = 0;
|
||||
uint32_t i = 0;
|
||||
int16_t *linear_samples = NULL;
|
||||
|
||||
|
||||
|
||||
if (type == SWITCH_ABC_TYPE_READ_REPLACE || type == SWITCH_ABC_TYPE_WRITE_REPLACE || type == SWITCH_ABC_TYPE_READ_PING) {
|
||||
int16_t *data;
|
||||
|
||||
if (type == SWITCH_ABC_TYPE_READ_REPLACE || type == SWITCH_ABC_TYPE_READ_PING) {
|
||||
|
||||
if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
|
||||
linear_frame = switch_core_media_bug_get_read_replace_frame(bug);
|
||||
} else {
|
||||
switch_status_t status;
|
||||
|
||||
raw_frame.data = raw_data;
|
||||
raw_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;
|
||||
linear_frame = &raw_frame;
|
||||
|
||||
status = switch_core_media_bug_read(bug, &raw_frame, SWITCH_FALSE);
|
||||
if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
|
||||
return SWITCH_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (oreka->read_resampler) {
|
||||
data = (int16_t *) linear_frame->data;
|
||||
switch_resample_process(oreka->read_resampler, data, (int) linear_frame->datalen / 2);
|
||||
linear_len = oreka->read_resampler->to_len * 2;
|
||||
memcpy(resample_data, oreka->read_resampler->to, linear_len);
|
||||
linear_samples = (int16_t *)resample_data;
|
||||
} else {
|
||||
linear_samples = linear_frame->data;
|
||||
linear_len = linear_frame->datalen;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == SWITCH_ABC_TYPE_WRITE_REPLACE) {
|
||||
linear_frame = switch_core_media_bug_get_write_replace_frame(bug);
|
||||
|
||||
if (oreka->write_resampler) {
|
||||
data = (int16_t *) linear_frame->data;
|
||||
switch_resample_process(oreka->write_resampler, data, (int) linear_frame->datalen / 2);
|
||||
linear_len = oreka->write_resampler->to_len * 2;
|
||||
memcpy(resample_data, oreka->write_resampler->to, linear_len);
|
||||
linear_samples = (int16_t *)resample_data;
|
||||
} else {
|
||||
linear_samples = linear_frame->data;
|
||||
linear_len = linear_frame->datalen;
|
||||
}
|
||||
}
|
||||
|
||||
/* convert the L16 frame into PCMU */
|
||||
memset(&pcmu_frame, 0, sizeof(pcmu_frame));
|
||||
for (i = 0; i < linear_len / sizeof(int16_t); i++) {
|
||||
pcmu_data[i] = linear_to_ulaw(linear_samples[i]);
|
||||
}
|
||||
pcmu_frame.source = __SWITCH_FUNC__;
|
||||
pcmu_frame.data = pcmu_data;
|
||||
pcmu_frame.datalen = i;
|
||||
pcmu_frame.payload = 0;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SWITCH_ABC_TYPE_INIT:
|
||||
{
|
||||
switch_codec_implementation_t read_impl;
|
||||
|
||||
switch_core_session_get_read_impl(session, &read_impl);
|
||||
|
||||
if (read_impl.actual_samples_per_second != 8000) {
|
||||
switch_resample_create(&oreka->read_resampler,
|
||||
read_impl.actual_samples_per_second,
|
||||
8000,
|
||||
320, SWITCH_RESAMPLE_QUALITY, 1);
|
||||
|
||||
switch_resample_create(&oreka->write_resampler,
|
||||
read_impl.actual_samples_per_second,
|
||||
8000,
|
||||
320, SWITCH_RESAMPLE_QUALITY, 1);
|
||||
}
|
||||
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Starting Oreka recording for audio stream\n");
|
||||
oreka_send_sip_message(oreka, FS_OREKA_START, FS_OREKA_READ);
|
||||
if (!oreka->mux_streams) {
|
||||
oreka_send_sip_message(oreka, FS_OREKA_START, FS_OREKA_WRITE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_CLOSE:
|
||||
{
|
||||
if (oreka->mux_streams) {
|
||||
int16_t *data;
|
||||
|
||||
raw_frame.data = raw_data;
|
||||
raw_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;
|
||||
|
||||
while (switch_core_media_bug_read(bug, &raw_frame, SWITCH_TRUE) == SWITCH_STATUS_SUCCESS) {
|
||||
linear_frame = &raw_frame;
|
||||
|
||||
|
||||
if (oreka->read_resampler) {
|
||||
data = (int16_t *) linear_frame->data;
|
||||
switch_resample_process(oreka->read_resampler, data, (int) linear_frame->datalen / 2);
|
||||
linear_len = oreka->read_resampler->to_len * 2;
|
||||
memcpy(resample_data, oreka->read_resampler->to, linear_len);
|
||||
linear_samples = (int16_t *)resample_data;
|
||||
} else {
|
||||
linear_samples = linear_frame->data;
|
||||
linear_len = linear_frame->datalen;
|
||||
}
|
||||
|
||||
memset(&pcmu_frame, 0, sizeof(pcmu_frame));
|
||||
for (i = 0; i < linear_len / sizeof(int16_t); i++) {
|
||||
pcmu_data[i] = linear_to_ulaw(linear_samples[i]);
|
||||
}
|
||||
pcmu_frame.source = __SWITCH_FUNC__;
|
||||
pcmu_frame.data = pcmu_data;
|
||||
pcmu_frame.datalen = i;
|
||||
pcmu_frame.payload = 0;
|
||||
|
||||
switch_rtp_write_frame(oreka->read_rtp_stream, &pcmu_frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (oreka->read_resampler) {
|
||||
switch_resample_destroy(&oreka->read_resampler);
|
||||
}
|
||||
|
||||
if (oreka->write_resampler) {
|
||||
switch_resample_destroy(&oreka->write_resampler);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Stopping Oreka recording for audio stream\n");
|
||||
oreka_send_sip_message(oreka, FS_OREKA_STOP, FS_OREKA_READ);
|
||||
if (!oreka->mux_streams) {
|
||||
oreka_send_sip_message(oreka, FS_OREKA_STOP, FS_OREKA_WRITE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_READ_REPLACE:
|
||||
case SWITCH_ABC_TYPE_READ_PING:
|
||||
{
|
||||
if (pcmu_frame.datalen) {
|
||||
if (switch_rtp_write_frame(oreka->read_rtp_stream, &pcmu_frame) > 0) {
|
||||
oreka->read_cnt++;
|
||||
if (oreka->read_cnt < 10) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Oreka wrote %u bytes! (read)\n", pcmu_frame.datalen);
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to write %u bytes! (read)\n", pcmu_frame.datalen);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_WRITE_REPLACE:
|
||||
{
|
||||
if (pcmu_frame.datalen) {
|
||||
if (switch_rtp_write_frame(oreka->write_rtp_stream, &pcmu_frame) > 0) {
|
||||
oreka->write_cnt++;
|
||||
if (oreka->write_cnt < 10) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Oreka wrote %u bytes! (write)\n", pcmu_frame.datalen);
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to write %u bytes! (write)\n", pcmu_frame.datalen);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SWITCH_TRUE;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_STANDARD_APP(oreka_start_function)
|
||||
{
|
||||
switch_status_t status;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
oreka_session_t *oreka = NULL;
|
||||
switch_media_bug_t *bug = NULL;
|
||||
char *argv[6];
|
||||
int flags = 0;
|
||||
char *lbuf = NULL;
|
||||
const char *var;
|
||||
|
||||
if ((oreka = (oreka_session_t *) switch_channel_get_private(channel, OREKA_PRIVATE))) {
|
||||
if (!zstr(data) && !strcasecmp(data, "stop")) {
|
||||
switch_channel_set_private(channel, OREKA_PRIVATE, NULL);
|
||||
if (oreka->read_bug) {
|
||||
switch_core_media_bug_remove(session, &oreka->read_bug);
|
||||
oreka->read_bug = NULL;
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Stopped oreka recorder\n");
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot run oreka recording 2 times on the same session!\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
oreka = switch_core_session_alloc(session, sizeof(*oreka));
|
||||
switch_assert(oreka);
|
||||
memset(oreka, 0, sizeof(*oreka));
|
||||
|
||||
oreka->mux_streams = globals.mux_streams;
|
||||
|
||||
if ((var = switch_channel_get_variable(channel, "oreka_mux_streams"))) {
|
||||
oreka->mux_streams = switch_true(var);
|
||||
}
|
||||
|
||||
if (data && (lbuf = switch_core_session_strdup(session, data))
|
||||
&& switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) {
|
||||
#if 0
|
||||
if (!strncasecmp(argv[x], "server", sizeof("server"))) {
|
||||
/* parse server=192.168.1.144 string */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
oreka->session = session;
|
||||
|
||||
if (oreka->mux_streams) {
|
||||
flags = SMBF_READ_STREAM | SMBF_WRITE_STREAM | SMBF_READ_PING | SMBF_ANSWER_REQ;
|
||||
} else {
|
||||
flags = SMBF_READ_REPLACE | SMBF_WRITE_REPLACE | SMBF_ANSWER_REQ;
|
||||
}
|
||||
|
||||
status = switch_core_media_bug_add(session, OREKA_BUG_NAME_READ, NULL, oreka_audio_callback, oreka, 0, flags, &bug);
|
||||
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to attach oreka to media stream!\n");
|
||||
return;
|
||||
}
|
||||
oreka->read_bug = bug;
|
||||
oreka->usecnt++;
|
||||
bug = NULL;
|
||||
oreka->usecnt++;
|
||||
switch_channel_set_private(channel, OREKA_PRIVATE, oreka);
|
||||
|
||||
}
|
||||
|
||||
#define OREKA_XML_CONFIG "oreka.conf"
|
||||
static int load_config(void)
|
||||
{
|
||||
switch_xml_t cfg, xml, settings, param;
|
||||
if (!(xml = switch_xml_open_cfg(OREKA_XML_CONFIG, &cfg, NULL))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open XML configuration '%s'\n", OREKA_XML_CONFIG);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((settings = switch_xml_child(cfg, "settings"))) {
|
||||
for (param = switch_xml_child(settings, "param"); param; param = param->next) {
|
||||
char *var = (char *) switch_xml_attr_soft(param, "name");
|
||||
char *val = (char *) switch_xml_attr_soft(param, "value");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Found parameter %s=%s\n", var, val);
|
||||
if (!strcasecmp(var, "sip-server-addr")) {
|
||||
snprintf(globals.sip_server_addr_str, sizeof(globals.sip_server_addr_str), "%s", val);
|
||||
} else if (!strcasecmp(var, "sip-server-port")) {
|
||||
globals.sip_server_port = atoi(val);
|
||||
} else if (!strcasecmp(var, "mux-all-streams")) {
|
||||
globals.mux_streams = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch_xml_free(xml);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_oreka_load)
|
||||
{
|
||||
switch_application_interface_t *app_interface = NULL;
|
||||
int mask = 0;
|
||||
#if 0
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
int x = 0;
|
||||
switch_size_t len = 0;
|
||||
switch_size_t ilen = 0;
|
||||
char dummy_output[] = "Parangaricutirimicuaro";
|
||||
char dummy_input[sizeof(dummy_output)] = "";
|
||||
switch_sockaddr_t *from_addr = NULL;
|
||||
#endif
|
||||
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
|
||||
if (load_config()) {
|
||||
return SWITCH_STATUS_UNLOAD;
|
||||
}
|
||||
|
||||
if (zstr(globals.sip_server_addr_str)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No sip server address specified!\n");
|
||||
return SWITCH_STATUS_UNLOAD;
|
||||
}
|
||||
|
||||
if (!globals.sip_server_port) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No sip server port specified!\n");
|
||||
return SWITCH_STATUS_UNLOAD;
|
||||
}
|
||||
|
||||
//switch_sockaddr_info_get(&globals.sip_server_addr, "sigchld.sangoma.local", SWITCH_UNSPEC, 5080, 0, pool);
|
||||
switch_sockaddr_info_get(&globals.sip_server_addr, globals.sip_server_addr_str, SWITCH_UNSPEC, globals.sip_server_port, 0, pool);
|
||||
|
||||
if (!globals.sip_server_addr) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid sip server address specified: %s!\n", globals.sip_server_addr_str);
|
||||
return SWITCH_STATUS_UNLOAD;
|
||||
}
|
||||
|
||||
if (switch_socket_create(&globals.sip_socket, switch_sockaddr_get_family(globals.sip_server_addr), SOCK_DGRAM, 0, pool) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create socket!\n");
|
||||
return SWITCH_STATUS_UNLOAD;
|
||||
}
|
||||
|
||||
switch_find_local_ip(globals.local_ipv4_str, sizeof(globals.local_ipv4_str), &mask, AF_INET);
|
||||
switch_get_addr(globals.sip_server_ipv4_str, sizeof(globals.sip_server_ipv4_str), globals.sip_server_addr);
|
||||
globals.our_pid = getpid();
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
|
||||
"Loading mod_oreka, sip_server_addr=%s, sip_server_ipv4_str=%s, sip_server_port=%d, local_ipv4_str=%s\n",
|
||||
globals.sip_server_addr_str, globals.sip_server_ipv4_str, globals.sip_server_port, globals.local_ipv4_str);
|
||||
|
||||
#if 0
|
||||
if (switch_socket_bind(globals.sip_socket, globals.sip_addr) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to bind to SIP address: %s!\n", strerror(errno));
|
||||
return SWITCH_STATUS_UNLOAD;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
len = sizeof(dummy_output);
|
||||
#ifndef WIN32
|
||||
switch_socket_opt_set(globals.sip_socket, SWITCH_SO_NONBLOCK, TRUE);
|
||||
|
||||
status = switch_socket_sendto(globals.sip_socket, globals.sip_addr, 0, (void *)dummy_output, &len);
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to send UDP message! (status=%d)\n", status);
|
||||
}
|
||||
|
||||
status = switch_sockaddr_create(&from_addr, pool);
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to creat socket address\n");
|
||||
}
|
||||
|
||||
while (!ilen) {
|
||||
ilen = sizeof(dummy_input);
|
||||
status = switch_socket_recvfrom(from_addr, globals.sip_socket, 0, (void *)dummy_input, &ilen);
|
||||
if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (++x > 1000) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch_cond_next();
|
||||
}
|
||||
|
||||
switch_socket_opt_set(globals.sip_socket, SWITCH_SO_NONBLOCK, FALSE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "oreka_record", "Send media to Oreka recording server", "Send media to Oreka recording server",
|
||||
oreka_start_function, "[stop]", SAF_NONE);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_oreka_shutdown)
|
||||
{
|
||||
switch_socket_close(globals.sip_socket);
|
||||
return SWITCH_STATUS_UNLOAD;
|
||||
}
|
||||
|
||||
/* 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:
|
||||
*/
|
|
@ -1,8 +0,0 @@
|
|||
include $(top_srcdir)/build/modmake.rulesam
|
||||
MODNAME=mod_clearmode
|
||||
|
||||
mod_LTLIBRARIES = mod_clearmode.la
|
||||
mod_clearmode_la_SOURCES = mod_clearmode.c
|
||||
mod_clearmode_la_CFLAGS = $(AM_CFLAGS)
|
||||
mod_clearmode_la_LIBADD = $(switch_builddir)/libfreeswitch.la
|
||||
mod_clearmode_la_LDFLAGS = -avoid-version -module -no-undefined -shared
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Brian West <brian@freeswitch.org>
|
||||
*
|
||||
* mod_clear.c -- CLEARMODE Passthru Codec
|
||||
*
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_clearmode_load);
|
||||
SWITCH_MODULE_DEFINITION(mod_clearmode, mod_clearmode_load, NULL, NULL);
|
||||
|
||||
static switch_status_t switch_clearmode_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
|
||||
{
|
||||
int encoding, decoding;
|
||||
|
||||
encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
|
||||
decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
|
||||
|
||||
if (!(encoding || decoding)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
} else {
|
||||
if (codec->fmtp_in) {
|
||||
codec->fmtp_out = switch_core_strdup(codec->memory_pool, codec->fmtp_in);
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static switch_status_t switch_clearmode_encode(switch_codec_t *codec,
|
||||
switch_codec_t *other_codec,
|
||||
void *decoded_data,
|
||||
uint32_t decoded_data_len,
|
||||
uint32_t decoded_rate, void *encoded_data, uint32_t *encoded_data_len, uint32_t *encoded_rate,
|
||||
unsigned int *flag)
|
||||
{
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
static switch_status_t switch_clearmode_decode(switch_codec_t *codec,
|
||||
switch_codec_t *other_codec,
|
||||
void *encoded_data,
|
||||
uint32_t encoded_data_len,
|
||||
uint32_t encoded_rate, void *decoded_data, uint32_t *decoded_data_len, uint32_t *decoded_rate,
|
||||
unsigned int *flag)
|
||||
{
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
static switch_status_t switch_clearmode_destroy(switch_codec_t *codec)
|
||||
{
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_clearmode_load)
|
||||
{
|
||||
switch_codec_interface_t *codec_interface;
|
||||
/* 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, "Clearmode (passthru)");
|
||||
switch_core_codec_add_implementation(pool, codec_interface,
|
||||
SWITCH_CODEC_TYPE_AUDIO, 106, "CLEARMODE", NULL, 8000, 8000, 64000,
|
||||
20000, 160, 320, 320, 1, 1,
|
||||
switch_clearmode_init, switch_clearmode_encode, switch_clearmode_decode, switch_clearmode_destroy);
|
||||
switch_core_codec_add_implementation(pool, codec_interface,
|
||||
SWITCH_CODEC_TYPE_AUDIO, 106, "CLEARMODE", NULL, 8000, 8000, 64000,
|
||||
30000, 240, 480, 480, 1, 1,
|
||||
switch_clearmode_init, switch_clearmode_encode, switch_clearmode_decode, switch_clearmode_destroy);
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -1,8 +0,0 @@
|
|||
include $(top_srcdir)/build/modmake.rulesam
|
||||
MODNAME=mod_theora
|
||||
|
||||
mod_LTLIBRARIES = mod_theora.la
|
||||
mod_theora_la_SOURCES = mod_theora.c
|
||||
mod_theora_la_CFLAGS = $(AM_CFLAGS)
|
||||
mod_theora_la_LIBADD = $(switch_builddir)/libfreeswitch.la
|
||||
mod_theora_la_LDFLAGS = -avoid-version -module -no-undefined -shared
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
*
|
||||
* mod_theora.c -- THEORA Video Codec
|
||||
*
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_theora_load);
|
||||
SWITCH_MODULE_DEFINITION(mod_theora, mod_theora_load, NULL, NULL);
|
||||
|
||||
static switch_status_t switch_theora_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
|
||||
{
|
||||
int encoding, decoding;
|
||||
|
||||
encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
|
||||
decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
|
||||
|
||||
if (!(encoding || decoding)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
} else {
|
||||
if (codec->fmtp_in) {
|
||||
codec->fmtp_out = switch_core_strdup(codec->memory_pool, codec->fmtp_in);
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static switch_status_t switch_theora_encode(switch_codec_t *codec,
|
||||
switch_codec_t *other_codec,
|
||||
void *decoded_data,
|
||||
uint32_t decoded_data_len,
|
||||
uint32_t decoded_rate, void *encoded_data, uint32_t *encoded_data_len, uint32_t *encoded_rate,
|
||||
unsigned int *flag)
|
||||
{
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
static switch_status_t switch_theora_decode(switch_codec_t *codec,
|
||||
switch_codec_t *other_codec,
|
||||
void *encoded_data,
|
||||
uint32_t encoded_data_len,
|
||||
uint32_t encoded_rate, void *decoded_data, uint32_t *decoded_data_len, uint32_t *decoded_rate,
|
||||
unsigned int *flag)
|
||||
{
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
static switch_status_t switch_theora_destroy(switch_codec_t *codec)
|
||||
{
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_theora_load)
|
||||
{
|
||||
switch_codec_interface_t *codec_interface;
|
||||
/* 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, "THEORA Video (passthru)");
|
||||
switch_core_codec_add_implementation(pool, codec_interface,
|
||||
SWITCH_CODEC_TYPE_VIDEO, 99, "THEORA", NULL, 90000, 90000, 0,
|
||||
0, 0, 0, 0, 1, 1, switch_theora_init, switch_theora_encode, switch_theora_decode, switch_theora_destroy);
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -1,18 +0,0 @@
|
|||
include $(top_srcdir)/build/modmake.rulesam
|
||||
MODNAME=mod_yaml
|
||||
|
||||
if HAVE_YAML
|
||||
|
||||
mod_LTLIBRARIES = mod_yaml.la
|
||||
mod_yaml_la_SOURCES = mod_yaml.c
|
||||
mod_yaml_la_CFLAGS = $(AM_CFLAGS)
|
||||
mod_yaml_la_CPPFLAGS = $(AM_CPPFLAGS) $(YAML_CFLAGS)
|
||||
mod_yaml_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(YAML_LIBS)
|
||||
mod_yaml_la_LDFLAGS = -avoid-version -module -no-undefined -shared
|
||||
|
||||
else
|
||||
install: error
|
||||
all: error
|
||||
error:
|
||||
$(error You must install libyaml-dev to build mod_yaml)
|
||||
endif
|
|
@ -1,529 +0,0 @@
|
|||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
|
||||
*
|
||||
* mod_yaml.c -- YAML Module
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
#include <yaml.h>
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_yaml_load);
|
||||
SWITCH_MODULE_DEFINITION(mod_yaml, mod_yaml_load, NULL, NULL);
|
||||
|
||||
static void print_error(yaml_parser_t *parser)
|
||||
{
|
||||
switch (parser->error) {
|
||||
case YAML_MEMORY_ERROR:
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory error: Not enough memory for parsing\n");
|
||||
break;
|
||||
|
||||
case YAML_READER_ERROR:
|
||||
if (parser->problem_value != -1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Reader error: %s: #%X at %d\n", parser->problem,
|
||||
parser->problem_value, (int) parser->problem_offset);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Reader error: %s at %d\n", parser->problem, (int) parser->problem_offset);
|
||||
}
|
||||
break;
|
||||
|
||||
case YAML_SCANNER_ERROR:
|
||||
if (parser->context) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Scanner error: %s at line %d, column %d\n"
|
||||
"%s at line %d, column %d\n", parser->context,
|
||||
(int) parser->context_mark.line + 1, (int) parser->context_mark.column + 1,
|
||||
parser->problem, (int) parser->problem_mark.line + 1, (int) parser->problem_mark.column + 1);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Scanner error: %s at line %d, column %d\n",
|
||||
parser->problem, (int) parser->problem_mark.line + 1, (int) parser->problem_mark.column + 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case YAML_PARSER_ERROR:
|
||||
if (parser->context) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parser error: %s at line %d, column %d\n"
|
||||
"%s at line %d, column %d\n", parser->context,
|
||||
(int) parser->context_mark.line + 1, (int) parser->context_mark.column + 1,
|
||||
parser->problem, (int) parser->problem_mark.line + 1, (int) parser->problem_mark.column + 1);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parser error: %s at line %d, column %d\n",
|
||||
parser->problem, (int) parser->problem_mark.line + 1, (int) parser->problem_mark.column + 1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Couldn't happen. */
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Internal error\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static switch_xml_t parse_file(FILE * input, const char *file_name)
|
||||
{
|
||||
yaml_parser_t parser;
|
||||
yaml_event_t event = { 0 };
|
||||
char *scalar_data;
|
||||
int done = 0;
|
||||
int depth = 0;
|
||||
char name[128] = "";
|
||||
char value[128] = "";
|
||||
char category[128] = "";
|
||||
int nv = 0, p_off = 0;
|
||||
switch_xml_t xml, param, top, current = NULL;
|
||||
|
||||
yaml_parser_initialize(&parser);
|
||||
yaml_parser_set_input_file(&parser, input);
|
||||
|
||||
|
||||
if (!(xml = switch_xml_new("document"))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch_xml_set_attr_d(xml, "type", "freeswitch/xml");
|
||||
current = switch_xml_add_child_d(xml, "section", 0);
|
||||
switch_xml_set_attr_d(current, "name", "configuration");
|
||||
|
||||
top = switch_xml_add_child_d(current, "configuration", 0);
|
||||
switch_xml_set_attr_d(top, "name", file_name);
|
||||
|
||||
while (!done) {
|
||||
if (!yaml_parser_parse(&parser, &event)) {
|
||||
print_error(&parser);
|
||||
break;
|
||||
} else {
|
||||
switch (event.type) {
|
||||
case YAML_MAPPING_START_EVENT:
|
||||
depth++;
|
||||
break;
|
||||
case YAML_MAPPING_END_EVENT:
|
||||
depth--;
|
||||
break;
|
||||
case YAML_STREAM_END_EVENT:
|
||||
done = 1;
|
||||
break;
|
||||
case YAML_SCALAR_EVENT:
|
||||
scalar_data = (char *) event.data.scalar.value;
|
||||
switch (depth) {
|
||||
case 1:
|
||||
if (!(current = switch_xml_add_child_d(top, scalar_data, depth - 1))) {
|
||||
done = 1;
|
||||
}
|
||||
switch_set_string(category, scalar_data);
|
||||
nv = 0;
|
||||
p_off = 0;
|
||||
break;
|
||||
case 2:
|
||||
if (current) {
|
||||
if (nv == 0) {
|
||||
switch_set_string(name, scalar_data);
|
||||
nv++;
|
||||
} else {
|
||||
switch_set_string(value, scalar_data);
|
||||
param = switch_xml_add_child_d(current, "param", p_off++);
|
||||
switch_xml_set_attr_d_buf(param, "name", name);
|
||||
switch_xml_set_attr_d(param, "value", scalar_data);
|
||||
nv = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
yaml_event_delete(&event);
|
||||
}
|
||||
|
||||
yaml_parser_delete(&parser);
|
||||
|
||||
if (input) {
|
||||
fclose(input);
|
||||
}
|
||||
#ifdef DEBUG_XML
|
||||
if (xml) {
|
||||
char *foo = switch_xml_toxml(xml, SWITCH_FALSE);
|
||||
printf("%s\n", foo);
|
||||
free(foo);
|
||||
}
|
||||
#endif
|
||||
|
||||
return xml;
|
||||
|
||||
}
|
||||
|
||||
static switch_xml_t yaml_fetch(const char *section,
|
||||
const char *tag_name, const char *key_name, const char *key_value, switch_event_t *params, void *user_data)
|
||||
{
|
||||
char *path;
|
||||
FILE *input;
|
||||
switch_xml_t xml = NULL;
|
||||
|
||||
path = switch_mprintf("%s/yaml/%s.yaml", SWITCH_GLOBAL_dirs.conf_dir, key_value);
|
||||
if ((input = fopen(path, "r"))) {
|
||||
xml = parse_file(input, key_value);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "cannot open %s\n", path);
|
||||
}
|
||||
|
||||
switch_safe_free(path);
|
||||
return xml;
|
||||
}
|
||||
|
||||
|
||||
static switch_caller_extension_t *parse_dp(FILE * input, switch_core_session_t *session, switch_caller_profile_t *caller_profile)
|
||||
{
|
||||
yaml_parser_t parser;
|
||||
yaml_event_t event = { 0 };
|
||||
char *scalar_data;
|
||||
int done = 0;
|
||||
int depth = 0;
|
||||
char name[128] = "";
|
||||
char value[128] = "";
|
||||
char category[128] = "";
|
||||
char *last_field = NULL;
|
||||
int nv = 0;
|
||||
switch_caller_extension_t *extension = NULL;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
int context_hit = 0;
|
||||
int proceed = 0;
|
||||
switch_regex_t *re = NULL;
|
||||
int ovector[30];
|
||||
int parens = 0;
|
||||
|
||||
if (!caller_profile) {
|
||||
if (!(caller_profile = switch_channel_get_caller_profile(channel))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Obtaining Profile!\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!caller_profile->context) {
|
||||
caller_profile->context = "default";
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Processing %s->%s@%s\n",
|
||||
caller_profile->caller_id_name, caller_profile->destination_number, caller_profile->context);
|
||||
|
||||
yaml_parser_initialize(&parser);
|
||||
yaml_parser_set_input_file(&parser, input);
|
||||
|
||||
while (!done) {
|
||||
if (!yaml_parser_parse(&parser, &event)) {
|
||||
print_error(&parser);
|
||||
break;
|
||||
} else {
|
||||
switch (event.type) {
|
||||
case YAML_MAPPING_START_EVENT:
|
||||
depth++;
|
||||
break;
|
||||
case YAML_MAPPING_END_EVENT:
|
||||
depth--;
|
||||
break;
|
||||
case YAML_STREAM_END_EVENT:
|
||||
done = 1;
|
||||
break;
|
||||
case YAML_SCALAR_EVENT:
|
||||
scalar_data = (char *) event.data.scalar.value;
|
||||
switch (depth) {
|
||||
case 1:
|
||||
switch_set_string(category, scalar_data);
|
||||
context_hit = (!strcasecmp(category, caller_profile->context));
|
||||
nv = 0;
|
||||
break;
|
||||
case 2:
|
||||
if (context_hit) {
|
||||
char *field = switch_core_session_strdup(session, scalar_data);
|
||||
char *p, *e, *expression = NULL, *field_expanded = NULL, *expression_expanded = NULL;
|
||||
const char *field_data = NULL;
|
||||
|
||||
parens = 0;
|
||||
proceed = 0;
|
||||
switch_regex_safe_free(re);
|
||||
|
||||
if ((p = strstr(field, "=~"))) {
|
||||
*p = '\0';
|
||||
e = p - 1;
|
||||
while (*e == ' ') {
|
||||
*e-- = '\0';
|
||||
}
|
||||
e = p + 2;
|
||||
while (*e == ' ') {
|
||||
*e++ = '\0';
|
||||
}
|
||||
expression = e;
|
||||
}
|
||||
|
||||
if (field && expression) {
|
||||
if ((expression_expanded = switch_channel_expand_variables(channel, expression)) == expression) {
|
||||
expression_expanded = NULL;
|
||||
} else {
|
||||
expression = expression_expanded;
|
||||
}
|
||||
|
||||
if (strchr(field, '$')) {
|
||||
if ((field_expanded = switch_channel_expand_variables(channel, field)) == field) {
|
||||
field_expanded = NULL;
|
||||
field_data = field;
|
||||
} else {
|
||||
field_data = field_expanded;
|
||||
}
|
||||
} else {
|
||||
field_data = switch_caller_get_field_by_name(caller_profile, field);
|
||||
}
|
||||
if (!field_data) {
|
||||
field_data = "";
|
||||
}
|
||||
switch_safe_free(last_field);
|
||||
last_field = strdup(field_data);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "test conditions %s(%s) =~ /%s/\n", field, field_data, expression);
|
||||
if (!(proceed = switch_regex_perform(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Regex mismatch\n");
|
||||
}
|
||||
|
||||
if (strchr(expression, '(')) {
|
||||
parens++;
|
||||
}
|
||||
|
||||
switch_safe_free(field_expanded);
|
||||
switch_safe_free(expression_expanded);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (nv == 0) {
|
||||
if (!strcasecmp(scalar_data, "exit")) {
|
||||
yaml_event_delete(&event);
|
||||
goto end;
|
||||
}
|
||||
switch_set_string(name, scalar_data);
|
||||
nv++;
|
||||
} else {
|
||||
switch_set_string(value, scalar_data);
|
||||
nv = 0;
|
||||
if (proceed) {
|
||||
uint32_t len = 0;
|
||||
char *substituted = NULL;
|
||||
char *app_data;
|
||||
|
||||
|
||||
if (!extension) {
|
||||
extension = switch_caller_extension_new(session, "YAML", caller_profile->destination_number);
|
||||
switch_assert(extension);
|
||||
}
|
||||
|
||||
if (parens) {
|
||||
len = (uint32_t) (strlen(value) + strlen(last_field) + 10) * proceed;
|
||||
switch_zmalloc(substituted, len);
|
||||
switch_perform_substitution(re, proceed, value, last_field, substituted, len, ovector);
|
||||
app_data = substituted;
|
||||
} else {
|
||||
app_data = value;
|
||||
}
|
||||
|
||||
switch_caller_extension_add_application(session, extension, name, app_data);
|
||||
switch_safe_free(substituted);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
yaml_event_delete(&event);
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
switch_safe_free(last_field);
|
||||
switch_regex_safe_free(re);
|
||||
yaml_parser_delete(&parser);
|
||||
|
||||
if (input) {
|
||||
fclose(input);
|
||||
}
|
||||
#ifdef DEBUG_XML
|
||||
if (xml) {
|
||||
char *foo = switch_xml_toxml(xml, SWITCH_FALSE);
|
||||
printf("%s\n", foo);
|
||||
free(foo);
|
||||
}
|
||||
#endif
|
||||
|
||||
return extension;
|
||||
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_DIALPLAN(yaml_dialplan_hunt)
|
||||
{
|
||||
switch_caller_extension_t *extension = NULL;
|
||||
char *alt_path = (char *) arg;
|
||||
char *path = NULL;
|
||||
FILE *input;
|
||||
|
||||
if (!zstr(alt_path)) {
|
||||
path = strdup(alt_path);
|
||||
} else {
|
||||
path = switch_mprintf("%s/yaml/extensions.yaml", SWITCH_GLOBAL_dirs.conf_dir);
|
||||
}
|
||||
|
||||
if ((input = fopen(path, "r"))) {
|
||||
extension = parse_dp(input, session, caller_profile);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening %s\n", path);
|
||||
}
|
||||
|
||||
switch_safe_free(path);
|
||||
return extension;
|
||||
}
|
||||
|
||||
|
||||
static switch_status_t do_config(void)
|
||||
{
|
||||
yaml_parser_t parser;
|
||||
yaml_event_t event = { 0 };
|
||||
char *path;
|
||||
const char *cfg = "mod_yaml.yaml";
|
||||
FILE *input;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
char *scalar_data;
|
||||
int done = 0;
|
||||
int depth = 0;
|
||||
char name[128] = "";
|
||||
char value[128] = "";
|
||||
char category[128] = "";
|
||||
int nv = 0;
|
||||
|
||||
path = switch_mprintf("%s/yaml/%s", SWITCH_GLOBAL_dirs.conf_dir, cfg);
|
||||
|
||||
if (!(input = fopen(path, "r"))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening %s\n", path);
|
||||
goto end;
|
||||
}
|
||||
|
||||
yaml_parser_initialize(&parser);
|
||||
yaml_parser_set_input_file(&parser, input);
|
||||
|
||||
while (!done) {
|
||||
if (!yaml_parser_parse(&parser, &event)) {
|
||||
print_error(&parser);
|
||||
break;
|
||||
} else {
|
||||
switch (event.type) {
|
||||
case YAML_MAPPING_START_EVENT:
|
||||
depth++;
|
||||
break;
|
||||
case YAML_MAPPING_END_EVENT:
|
||||
depth--;
|
||||
break;
|
||||
case YAML_STREAM_END_EVENT:
|
||||
done = 1;
|
||||
break;
|
||||
case YAML_SCALAR_EVENT:
|
||||
scalar_data = (char *) event.data.scalar.value;
|
||||
switch (depth) {
|
||||
case 1:
|
||||
switch_set_string(category, scalar_data);
|
||||
nv = 0;
|
||||
break;
|
||||
case 2:
|
||||
if (nv == 0) {
|
||||
switch_set_string(name, scalar_data);
|
||||
nv++;
|
||||
} else {
|
||||
switch_set_string(value, scalar_data);
|
||||
if (!strcasecmp(category, "settings")) {
|
||||
if (!strcasecmp(name, "bind_config") && switch_true_buf(value)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Binding To XML Config\n");
|
||||
switch_xml_bind_search_function(yaml_fetch, switch_xml_parse_section_string("config"), NULL);
|
||||
}
|
||||
}
|
||||
nv = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
yaml_event_delete(&event);
|
||||
}
|
||||
|
||||
yaml_parser_delete(&parser);
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
end:
|
||||
|
||||
if (input) {
|
||||
fclose(input);
|
||||
}
|
||||
|
||||
switch_safe_free(path);
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_yaml_load)
|
||||
{
|
||||
switch_dialplan_interface_t *dp_interface;
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
if (do_config() != SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
|
||||
SWITCH_ADD_DIALPLAN(dp_interface, "YAML", yaml_dialplan_hunt);
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
|
@ -31,6 +31,7 @@
|
|||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <errno.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
|
@ -228,8 +229,16 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_timerfd_runtime)
|
|||
|
||||
do {
|
||||
r = epoll_wait(interval_poll_fd, e, sizeof(e) / sizeof(e[0]), 1000);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
/* if we had an interrupted system call due to process pause via SIGSTOP, do not exit the timer loop */
|
||||
if (errno == EINTR) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "epoll_wait interrupted by SIGINT, continue...\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < r; i++) {
|
||||
it = e[i].data.ptr;
|
||||
if ((e[i].events & EPOLLIN) &&
|
||||
|
|
Loading…
Reference in New Issue