mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-23 12:42:02 +00:00
Merge branch 'master' into v1.4.beta
This commit is contained in:
@@ -11,6 +11,11 @@
|
||||
<param name="record-file-prefix" value="$${recordings_dir}/"/>
|
||||
</record>
|
||||
|
||||
<!-- input component params -->
|
||||
<input>
|
||||
<param name="default-recognizer" value="pocketsphinx"/>
|
||||
</input>
|
||||
|
||||
<!-- 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 -->
|
||||
@@ -42,4 +47,211 @@
|
||||
<dial-gateway uriprefix="sofia" dialprefix="" strip=""/>
|
||||
</dial-gateways>
|
||||
|
||||
<!-- IQ request aliases. Used mainly for testing purposes or for controlling a rayo call via the console -->
|
||||
<aliases>
|
||||
<alias name="ping" target="external"><![CDATA[<iq type="get"><ping xmlns="urn:xmpp:ping"/></iq>]]></alias>
|
||||
<alias name="answer" target="call"><![CDATA[<answer xmlns="urn:xmpp:rayo:1"/>]]></alias>
|
||||
<alias name="hangup" target="call"><![CDATA[<hangup xmlns="urn:xmpp:rayo:1"/>]]></alias>
|
||||
<alias name="join_mixer_duplex" target="call"><![CDATA[<join xmlns="urn:xmpp:rayo:1" mixer-name="test" direction="duplex"/>]]></alias>
|
||||
<alias name="join_mixer_send" target="call"><![CDATA[<join xmlns="urn:xmpp:rayo:1" mixer-name="test" direction="send"/>]]></alias>
|
||||
<alias name="join_mixer_recv" target="call"><![CDATA[<join xmlns="urn:xmpp:rayo:1" mixer-name="test" direction="recv"/>]]></alias>
|
||||
<alias name="unjoin_mixer" target="call"><![CDATA[<unjoin xmlns="urn:xmpp:rayo:1" mixer-name="test"/>]]></alias>
|
||||
<alias name="unjoin" target="call"><![CDATA[<unjoin xmlns="urn:xmpp:rayo:1"/>]]></alias>
|
||||
<alias name="stop" target="component"><![CDATA[<stop xmlns="urn:xmpp:rayo:ext:1"/>]]></alias>
|
||||
<alias name="output_bad" target="call"><![CDATA[<output xmlns="urn:xmpp:rayo:output:1" repeat-time="100"></output>]]></alias>
|
||||
<alias name="pause" target="output"><![CDATA[<pause xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
|
||||
<alias name="resume" target="output"><![CDATA[<resume xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
|
||||
<alias name="speed-up" target="output"><![CDATA[<speed-up xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
|
||||
<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="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>
|
||||
<alias name="prompt_barge" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-times="5">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="prompt_no_barge" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="false">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-times="5">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="prompt_long" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-times="100">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="prompt_multi_digit" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-times="100">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><item repeat="1-4"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></item></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="prompt_terminator" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-times="100">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000" terminator="#">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><item repeat="1-4"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></item></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="prompt_input_bad" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-times="100">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtf" initial-timeout="5000" inter-digit-timeout="3000" terminator="#">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><item repeat="1-4"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></item></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="prompt_output_bad" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-time="100">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000" terminator="#">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><item repeat="1-4"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></item></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="input" target="call">
|
||||
<![CDATA[
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="input_voice_yesno_unimrcp" target="call">
|
||||
<![CDATA[
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="voice" recognizer="unimrcp">
|
||||
<grammar content-type="application/srgs+xml>
|
||||
<![CDATA[
|
||||
<grammar xmlns="http://www.w3.org/2001/06/grammar"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.w3.org/2001/06/grammar http://www.w3.org/TR/speech-grammar/grammar.xsd"
|
||||
xml:lang="en-US" version="1.0">
|
||||
<rule id="yesno"><one-of><item>yes</item><item>no</item></one-of></rule></grammar>
|
||||
]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="input_voice_yesno_unimrcp_timeout" target="call">
|
||||
<![CDATA[
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="voice" recognizer="unimrcp" max-silence="5000" initial-timeout="5000">
|
||||
<grammar content-type="application/srgs+xml>
|
||||
<![CDATA[
|
||||
<grammar xmlns="http://www.w3.org/2001/06/grammar"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.w3.org/2001/06/grammar http://www.w3.org/TR/speech-grammar/grammar.xsd"
|
||||
xml:lang="en-US" version="1.0">
|
||||
<rule id="yesno"><one-of><item>yes</item><item>no</item></one-of></rule></grammar>
|
||||
]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
]]>
|
||||
</alias>
|
||||
|
||||
<alias name="input_voice_yesno_pocketsphinx" target="call">
|
||||
<![CDATA[
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="voice" recognizer="pocketsphinx" max-silence="5000" initial-timeout="5000">
|
||||
<grammar content-type="application/srgs+xml>
|
||||
<![CDATA[
|
||||
<grammar xmlns="http://www.w3.org/2001/06/grammar"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.w3.org/2001/06/grammar http://www.w3.org/TR/speech-grammar/grammar.xsd"
|
||||
xml:lang="en-US" version="1.0">
|
||||
<rule id="yesno"><one-of><item>yes</item><item>no</item></one-of></rule></grammar>
|
||||
]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
]]>
|
||||
</alias>
|
||||
|
||||
<alias name="input_voice_yesno_default" target="call">
|
||||
<![CDATA[
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="voice" max-silence="5000" initial-timeout="5000">
|
||||
<grammar content-type="application/srgs+xml>
|
||||
<![CDATA[
|
||||
<grammar xmlns="http://www.w3.org/2001/06/grammar"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.w3.org/2001/06/grammar http://www.w3.org/TR/speech-grammar/grammar.xsd"
|
||||
xml:lang="en-US" version="1.0">
|
||||
<rule id="yesno"><one-of><item>yes</item><item>no</item></one-of></rule></grammar>
|
||||
]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
]]>
|
||||
</alias>
|
||||
|
||||
</aliases>
|
||||
|
||||
</configuration>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<include>
|
||||
<!-- Vestec VASRE MRCP Server -->
|
||||
<profile name="vestec-mrcp-v1" version="1">
|
||||
<param name="server-ip" value="127.0.0.1"/>
|
||||
<param name="server-port" value="1554"/>
|
||||
<param name="resource-location" value=""/>
|
||||
<param name="speechsynth" value="speechsynthesizer"/>
|
||||
<param name="speechrecog" value="speechrecognizer"/>
|
||||
<param name="rtp-ip" value="auto"/>
|
||||
<param name="rtp-port-min" value="14000"/>
|
||||
<param name="rtp-port-max" value="15000"/>
|
||||
<!--param name="playout-delay" value="50"/-->
|
||||
<!--param name="max-playout-delay" value="200"/-->
|
||||
<!--param name="ptime" value="20"/-->
|
||||
<param name="codecs" value="PCMU PCMA L16/96/8000"/>
|
||||
|
||||
<!-- Add any default MRCP params for SPEAK requests here -->
|
||||
<synthparams>
|
||||
</synthparams>
|
||||
|
||||
<!-- Add any default MRCP params for RECOGNIZE requests here -->
|
||||
<recogparams>
|
||||
<!--param name="start-input-timers" value="false"/-->
|
||||
</recogparams>
|
||||
</profile>
|
||||
</include>
|
||||
@@ -14,6 +14,28 @@
|
||||
-->
|
||||
<X-PRE-PROCESS cmd="set" data="default_password=1234"/>
|
||||
<!-- Did you change it yet? -->
|
||||
<!--
|
||||
The following variables are set dynamically - calculated if possible by freeswitch - and
|
||||
are available to the config as $${variable}. You can see their calculated value via fs_cli
|
||||
by entering eval $${variable}
|
||||
|
||||
hostname
|
||||
local_ip_v4
|
||||
local_mask_v4
|
||||
local_ip_v6
|
||||
switch_serial
|
||||
base_dir
|
||||
recordings_dir
|
||||
sound_prefix
|
||||
sounds_dir
|
||||
core_uuid
|
||||
zrtp_enabled
|
||||
nat_public_addr
|
||||
nat_private_addr
|
||||
nat_type
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<X-PRE-PROCESS cmd="set" data="sound_prefix=$${sounds_dir}/en/us/callie"/>
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
Wed Nov 7 10:37:54 CST 2012
|
||||
Tue Aug 27 13:58:18 EDT 2013
|
||||
|
||||
@@ -32,6 +32,10 @@ static apr_status_t socket_cleanup(void *sock)
|
||||
{
|
||||
apr_socket_t *thesocket = sock;
|
||||
|
||||
if (thesocket && thesocket->socketdes == -1) {
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
if (close(thesocket->socketdes) == 0) {
|
||||
thesocket->socketdes = -1;
|
||||
return APR_SUCCESS;
|
||||
|
||||
@@ -98,6 +98,8 @@ static const char *EVENT_NAMES[] = {
|
||||
"MESSAGE",
|
||||
"PRESENCE_IN",
|
||||
"NOTIFY_IN",
|
||||
"PHONE_FEATURE",
|
||||
"PHONE_FEATURE_SUBSCRIBE",
|
||||
"PRESENCE_OUT",
|
||||
"PRESENCE_PROBE",
|
||||
"MESSAGE_WAITING",
|
||||
|
||||
@@ -2241,7 +2241,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
|
||||
{
|
||||
switch_core_session_t *session = NULL;
|
||||
switch_channel_t *channel = NULL;
|
||||
ftdm_status_t status;
|
||||
ftdm_status_t status = FTDM_SUCCESS;
|
||||
uint32_t spanid;
|
||||
uint32_t chanid;
|
||||
ftdm_caller_data_t *caller_data;
|
||||
@@ -2296,6 +2296,45 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
|
||||
break;
|
||||
case FTDM_SIGEVENT_SIGSTATUS_CHANGED:
|
||||
case FTDM_SIGEVENT_COLLECTED_DIGIT: /* Analog E&M */
|
||||
{
|
||||
int span_id = ftdm_channel_get_span_id(sigmsg->channel);
|
||||
char *dtmf = sigmsg->ev_data.collected.digits;
|
||||
char *regex = SPAN_CONFIG[span_id].dial_regex;
|
||||
char *fail_regex = SPAN_CONFIG[span_id].fail_dial_regex;
|
||||
ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(sigmsg->channel);
|
||||
|
||||
if (zstr(regex)) {
|
||||
regex = NULL;
|
||||
}
|
||||
|
||||
if (zstr(fail_regex)) {
|
||||
fail_regex = NULL;
|
||||
}
|
||||
|
||||
ftdm_log(FTDM_LOG_DEBUG, "got DTMF sig [%s]\n", dtmf);
|
||||
switch_set_string(caller_data->collected, dtmf);
|
||||
|
||||
if ((regex || fail_regex) && !zstr(dtmf)) {
|
||||
switch_regex_t *re = NULL;
|
||||
int ovector[30];
|
||||
int match = 0;
|
||||
|
||||
if (fail_regex) {
|
||||
match = switch_regex_perform(dtmf, fail_regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
|
||||
status = match ? FTDM_SUCCESS : FTDM_BREAK;
|
||||
switch_regex_safe_free(re);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "DTMF [%s] vs fail regex %s %s\n", dtmf, fail_regex, match ? "matched" : "did not match");
|
||||
}
|
||||
|
||||
if (status == FTDM_SUCCESS && regex) {
|
||||
match = switch_regex_perform(dtmf, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
|
||||
status = match ? FTDM_BREAK : FTDM_SUCCESS;
|
||||
switch_regex_safe_free(re);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "DTMF [%s] vs dial regex %s %s\n", dtmf, regex, match ? "matched" : "did not match");
|
||||
}
|
||||
ftdm_log(FTDM_LOG_DEBUG, "returning %s to COLLECT event with DTMF %s\n", status == FTDM_SUCCESS ? "success" : "break", dtmf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
@@ -2305,7 +2344,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
|
||||
break;
|
||||
}
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
return status;
|
||||
}
|
||||
|
||||
static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
|
||||
@@ -3785,7 +3824,10 @@ static switch_status_t load_config(void)
|
||||
char *hold_music = NULL;
|
||||
char *fail_dial_regex = NULL;
|
||||
char str_false[] = "false";
|
||||
char str_empty[] = "";
|
||||
char *answer_supervision = str_false;
|
||||
char *immediate_ringback = str_false;
|
||||
char *ringback_file = str_empty;
|
||||
uint32_t span_id = 0, to = 0, max = 0, dial_timeout_int = 0;
|
||||
ftdm_span_t *span = NULL;
|
||||
analog_option_t analog_options = ANALOG_OPTION_NONE;
|
||||
@@ -3814,6 +3856,10 @@ static switch_status_t load_config(void)
|
||||
max_digits = val;
|
||||
} else if (!strcasecmp(var, "answer-supervision")) {
|
||||
answer_supervision = val;
|
||||
} else if (!strcasecmp(var, "immediate-ringback")) {
|
||||
immediate_ringback = val;
|
||||
} else if (!strcasecmp(var, "ringback-file")) {
|
||||
ringback_file = val;
|
||||
} else if (!strcasecmp(var, "enable-analog-option")) {
|
||||
analog_options = enable_analog_option(val, analog_options);
|
||||
}
|
||||
@@ -3867,6 +3913,8 @@ static switch_status_t load_config(void)
|
||||
if (ftdm_configure_span(span, "analog_em", on_analog_signal,
|
||||
"tonemap", tonegroup,
|
||||
"answer_supervision", answer_supervision,
|
||||
"immediate_ringback", immediate_ringback,
|
||||
"ringback_file", ringback_file,
|
||||
"digit_timeout", &to,
|
||||
"dial_timeout", &dial_timeout_int,
|
||||
"max_dialstr", &max,
|
||||
|
||||
@@ -6089,6 +6089,7 @@ static void execute_safety_hangup(void *data)
|
||||
FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t *sigmsg)
|
||||
{
|
||||
ftdm_channel_t *fchan = NULL;
|
||||
ftdm_status_t status = FTDM_SUCCESS;
|
||||
if (sigmsg->channel) {
|
||||
fchan = sigmsg->channel;
|
||||
ftdm_channel_lock(fchan);
|
||||
@@ -6193,7 +6194,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
|
||||
if (ftdm_test_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE)) {
|
||||
ftdm_span_queue_signal(span, sigmsg);
|
||||
} else {
|
||||
ftdm_span_trigger_signal(span, sigmsg);
|
||||
status = ftdm_span_trigger_signal(span, sigmsg);
|
||||
}
|
||||
|
||||
done:
|
||||
@@ -6202,7 +6203,7 @@ done:
|
||||
ftdm_channel_unlock(fchan);
|
||||
}
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
return status;
|
||||
}
|
||||
|
||||
static void *ftdm_cpu_monitor_run(ftdm_thread_t *me, void *obj)
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
* Contributor(s):
|
||||
*
|
||||
* John Wehle (john@feith.com)
|
||||
* Moises Silva (moy@sangoma.com)
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -53,6 +54,8 @@ struct ftdm_analog_data {
|
||||
uint32_t digit_timeout;
|
||||
uint32_t dial_timeout;
|
||||
ftdm_bool_t answer_supervision;
|
||||
ftdm_bool_t immediate_ringback;
|
||||
char ringback_file[512];
|
||||
};
|
||||
|
||||
static void *ftdm_analog_em_run(ftdm_thread_t *me, void *obj);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
* Contributor(s):
|
||||
*
|
||||
* John Wehle (john@feith.com)
|
||||
* Moises Silva (moy@sangoma.com)
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -43,6 +44,106 @@
|
||||
struct tm * localtime_r(const time_t *clock, struct tm *result);
|
||||
#endif
|
||||
|
||||
/* check if the given file is a wave file and skip the header if it is */
|
||||
#define WAVE_CHUNK_ID "RIFF"
|
||||
#define WAVE_FMT "WAVEfmt "
|
||||
#define WAVE_HEADER_LEN 44
|
||||
static int skip_wave_header(const char *fname, FILE *f)
|
||||
{
|
||||
char rbuff[10] = { 0 };
|
||||
unsigned int hz = 0;
|
||||
unsigned int hs = 0;
|
||||
unsigned short fmt = 0;
|
||||
unsigned short chans = 0;
|
||||
unsigned int size = 0;
|
||||
|
||||
/* check chunk id */
|
||||
if (fread(rbuff, 1, 4, f) != 4) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unable to read wav chunk id from file %s\n", fname);
|
||||
goto error;
|
||||
}
|
||||
rbuff[4] = 0;
|
||||
|
||||
if (strncasecmp(rbuff, WAVE_CHUNK_ID, sizeof(WAVE_CHUNK_ID)-1)) {
|
||||
goto notwave;
|
||||
}
|
||||
|
||||
/* read chunk size */
|
||||
if (fread(&size, 1, 4, f) != 4) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unable to read wav chunk size from file %s\n", fname);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* check format and sub chunk id */
|
||||
if (fread(rbuff, 1, 8, f) != 8) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unable to read wav format and sub chunk id from file %s\n", fname);
|
||||
goto error;
|
||||
}
|
||||
rbuff[8] = 0;
|
||||
|
||||
if (strncasecmp(rbuff, WAVE_FMT, sizeof(WAVE_FMT)-1)) {
|
||||
goto notwave;
|
||||
}
|
||||
|
||||
/* At this point we know is a wav file ... */
|
||||
|
||||
/* validate sub chunk size */
|
||||
if (fread(&hs, 1, 4, f) != 4) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unable to read wav sub chunk size from file %s\n", fname);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (hs != 16) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unsupported wav sub chunk size %d from file %s\n", hs, fname);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* validate audio format */
|
||||
if (fread(&fmt, 1, 2, f) != 2) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unable to read wav audio format from file %s\n", fname);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fmt != 1) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unsupported wav audio format %d in file %s, we only support PCM\n", fmt, fname);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* validate channels */
|
||||
if (fread(&chans, 1, 2, f) != 2) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unable to read wav channels from file %s\n", fname);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (chans != 1) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unsupported number of channels %d in file %s, we only support 1 (mono)\n", chans, fname);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* validate sampling rate */
|
||||
if (fread(&hz, 1, 2, f) != 2) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unable to read wav sampling rate from file %s\n", fname);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (hz != 8000) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Invalid input wav sampling rate %dHz, only 8000Hz supported\n", hz);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Found input file %s. PCM mono wav of %d bytes at %dHz, skipping header ...\n", fname, size, hz);
|
||||
fseek(f, WAVE_HEADER_LEN, SEEK_SET);
|
||||
|
||||
return 0;
|
||||
|
||||
notwave:
|
||||
ftdm_log(FTDM_LOG_ERROR, "File %s is not a wav file\n", fname);
|
||||
return -1;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj);
|
||||
|
||||
/**
|
||||
@@ -70,6 +171,19 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_em_outgoing_call)
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
static ftdm_status_t ftdm_analog_em_sig_write(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size)
|
||||
{
|
||||
ftdm_analog_em_data_t *analog_data = ftdmchan->span->signal_data;
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA
|
||||
&& analog_data->immediate_ringback
|
||||
&& ftdmchan->call_data) {
|
||||
/* DO NOT USE ftdmchan->call_data, as is a dummy non-null pointer */
|
||||
/* ringback is being played in the analog thread, ignore user data for now */
|
||||
return FTDM_BREAK;
|
||||
}
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Starts an EM span thread (monitor)
|
||||
* \param span Span to monitor
|
||||
@@ -82,6 +196,19 @@ static ftdm_status_t ftdm_analog_em_start(ftdm_span_t *span)
|
||||
return ftdm_thread_create_detached(ftdm_analog_em_run, span);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Stops EM span thread (monitor)
|
||||
* \param span Span to monitor
|
||||
* \return Success or failure
|
||||
*/
|
||||
static ftdm_status_t ftdm_analog_em_stop(ftdm_span_t *span)
|
||||
{
|
||||
ftdm_analog_em_data_t *analog_data = span->signal_data;
|
||||
ftdm_clear_flag(analog_data, FTDM_ANALOG_EM_RUNNING);
|
||||
ftdm_sleep(100);
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the signalling status on a channel
|
||||
* \param ftdmchan Channel to get status on
|
||||
@@ -120,8 +247,10 @@ static FIO_SPAN_GET_SIG_STATUS_FUNCTION(analog_em_get_span_sig_status)
|
||||
static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
|
||||
//ftdm_status_t ftdm_analog_em_configure_span(ftdm_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, fio_signal_cb_t sig_cb)
|
||||
{
|
||||
ftdm_analog_em_data_t *analog_data;
|
||||
ftdm_analog_em_data_t *analog_data = NULL;
|
||||
const char *tonemap = "us";
|
||||
const char *ringback_file = "";
|
||||
ftdm_bool_t immediate_ringback = FTDM_FALSE;
|
||||
uint32_t digit_timeout = 2000;
|
||||
uint32_t max_dialstr = 11;
|
||||
uint32_t dial_timeout = 0;
|
||||
@@ -136,9 +265,8 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
analog_data = ftdm_malloc(sizeof(*analog_data));
|
||||
analog_data = ftdm_calloc(1, sizeof(*analog_data));
|
||||
assert(analog_data != NULL);
|
||||
memset(analog_data, 0, sizeof(*analog_data));
|
||||
|
||||
while((var = va_arg(ap, char *))) {
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Parsing analog em parameter '%s'\n", var);
|
||||
@@ -147,6 +275,16 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
|
||||
break;
|
||||
}
|
||||
tonemap = val;
|
||||
} else if (!strcasecmp(var, "immediate_ringback")) {
|
||||
if (!(val = va_arg(ap, char *))) {
|
||||
break;
|
||||
}
|
||||
immediate_ringback = ftdm_true(val);
|
||||
} else if (!strcasecmp(var, "ringback_file")) {
|
||||
if (!(val = va_arg(ap, char *))) {
|
||||
break;
|
||||
}
|
||||
ringback_file = val;
|
||||
} else if (!strcasecmp(var, "answer_supervision")) {
|
||||
if (!(val = va_arg(ap, char *))) {
|
||||
break;
|
||||
@@ -184,6 +322,8 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
|
||||
}
|
||||
|
||||
span->start = ftdm_analog_em_start;
|
||||
span->stop = ftdm_analog_em_stop;
|
||||
span->sig_write = ftdm_analog_em_sig_write;
|
||||
analog_data->digit_timeout = digit_timeout;
|
||||
analog_data->max_dialstr = max_dialstr;
|
||||
analog_data->dial_timeout = dial_timeout;
|
||||
@@ -195,6 +335,10 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
|
||||
span->get_channel_sig_status = analog_em_get_channel_sig_status;
|
||||
span->get_span_sig_status = analog_em_get_span_sig_status;
|
||||
ftdm_span_load_tones(span, tonemap);
|
||||
if (immediate_ringback || !ftdm_strlen_zero(ringback_file)) {
|
||||
analog_data->immediate_ringback = FTDM_TRUE;
|
||||
ftdm_set_string(analog_data->ringback_file, ringback_file);
|
||||
}
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
|
||||
@@ -241,6 +385,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||
int cas_bits = 0;
|
||||
uint32_t cas_answer = 0;
|
||||
int cas_answer_ms = 500;
|
||||
FILE *ringback_f = NULL;
|
||||
ftdm_bool_t digits_sent = FTDM_FALSE;
|
||||
|
||||
ftdm_unused_arg(me);
|
||||
@@ -283,6 +428,18 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||
assert(interval != 0);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "IO Interval: %u\n", interval);
|
||||
|
||||
if (analog_data->immediate_ringback && !ftdm_strlen_zero(analog_data->ringback_file)) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Using ringback file '%s'\n", analog_data->ringback_file);
|
||||
ringback_f = fopen(analog_data->ringback_file, "rb");
|
||||
if (!ringback_f) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to open ringback file '%s'\n", analog_data->ringback_file);
|
||||
} else {
|
||||
if (skip_wave_header(analog_data->ringback_file, ringback_f)) {
|
||||
ringback_f = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (ftdm_running() && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
|
||||
ftdm_wait_flag_t flags = FTDM_READ;
|
||||
ftdm_size_t dlen = 0;
|
||||
@@ -464,9 +621,11 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||
break;
|
||||
case FTDM_CHANNEL_STATE_RINGING:
|
||||
{
|
||||
ftdm_buffer_zero(dt_buffer);
|
||||
teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
|
||||
indicate = 1;
|
||||
if (!analog_data->immediate_ringback) {
|
||||
ftdm_buffer_zero(dt_buffer);
|
||||
teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
|
||||
indicate = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FTDM_CHANNEL_STATE_BUSY:
|
||||
@@ -515,7 +674,6 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) > analog_data->max_dialstr))) {
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
|
||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
|
||||
@@ -531,7 +689,8 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||
continue;
|
||||
}
|
||||
|
||||
len = sizeof(frame);
|
||||
/* Do not try to read more than the proper interval size */
|
||||
len = ftdmchan->packet_len * 2;
|
||||
if (ftdm_channel_read(ftdmchan, frame, &len) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "READ ERROR [%s]\n", ftdmchan->last_error);
|
||||
goto done;
|
||||
@@ -542,6 +701,11 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len >= (sizeof(frame)/2)) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "Ignoring big read of %zd bytes!\n", len);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ftdmchan->detected_tones[0]) {
|
||||
int i;
|
||||
|
||||
@@ -576,6 +740,20 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||
ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (analog_data->immediate_ringback &&
|
||||
(ftdmchan->state == FTDM_CHANNEL_STATE_COLLECT ||
|
||||
ftdmchan->state == FTDM_CHANNEL_STATE_RING ||
|
||||
ftdmchan->state == FTDM_CHANNEL_STATE_RINGING ||
|
||||
ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS ||
|
||||
ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA
|
||||
)) {
|
||||
indicate = 1;
|
||||
if (!ringback_f) {
|
||||
ftdm_buffer_zero(dt_buffer);
|
||||
teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!indicate) {
|
||||
continue;
|
||||
@@ -585,7 +763,25 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||
len *= 2;
|
||||
}
|
||||
|
||||
rlen = ftdm_buffer_read_loop(dt_buffer, frame, len);
|
||||
if (ringback_f) {
|
||||
uint8_t failed_read = 0;
|
||||
read_try:
|
||||
rlen = fread(frame, 1, len, ringback_f);
|
||||
if (rlen != len) {
|
||||
if (!feof(ringback_f)) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Error reading from ringback file: %zd != %zd\n", rlen, len);
|
||||
}
|
||||
if (failed_read) {
|
||||
continue;
|
||||
}
|
||||
/* return cursor to start of wav file */
|
||||
fseek(ringback_f, WAVE_HEADER_LEN, SEEK_SET);
|
||||
failed_read++;
|
||||
goto read_try;
|
||||
}
|
||||
} else {
|
||||
rlen = ftdm_buffer_read_loop(dt_buffer, frame, len);
|
||||
}
|
||||
|
||||
if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
|
||||
fio_codec_t codec_func = NULL;
|
||||
@@ -599,12 +795,17 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||
if (codec_func) {
|
||||
codec_func(frame, sizeof(frame), &rlen);
|
||||
} else {
|
||||
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
|
||||
ftdm_log(FTDM_LOG_ERROR, "codec error, no codec function for native codec %d!", ftdmchan->native_codec);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* we must lock the channel and make sure we let our own generated audio thru (ftdmchan->call_data is tested in the ftdm_analog_em_sig_write handler)*/
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
ftdmchan->call_data = (void *)0xFF; /* ugh! */
|
||||
ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
|
||||
ftdmchan->call_data = NULL;
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
}
|
||||
|
||||
done:
|
||||
@@ -624,6 +825,10 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||
ftdm_buffer_destroy(&dt_buffer);
|
||||
}
|
||||
|
||||
if (ringback_f) {
|
||||
fclose(ringback_f);
|
||||
}
|
||||
|
||||
ftdm_clear_flag(closed_chan, FTDM_CHANNEL_INTHREAD);
|
||||
|
||||
ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM CHANNEL thread ended.\n");
|
||||
|
||||
@@ -1 +1 @@
|
||||
Mon Apr 16 11:52:47 CDT 2012
|
||||
Wed Aug 28 03:22:32 CDT 2013
|
||||
|
||||
@@ -100,6 +100,9 @@ int
|
||||
psf_fclose (SF_PRIVATE *psf)
|
||||
{ int retval ;
|
||||
|
||||
if (psf->filedes == -1)
|
||||
return -1; /* already closed */
|
||||
|
||||
if (psf->virtual_io)
|
||||
return 0 ;
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
Mon Jul 29 16:07:25 CDT 2013
|
||||
Fri Aug 23 04:09:44 CDT 2013
|
||||
|
||||
@@ -228,8 +228,8 @@ int tport_recv_stream_ws(tport_t *self)
|
||||
}
|
||||
if (N < 0) {
|
||||
err = errno = EHOSTDOWN;
|
||||
SU_DEBUG_1(("%s(%p): su_getmsgsize(): %s (%d)\n", __func__, (void *)self,
|
||||
su_strerror(err), err));
|
||||
SU_DEBUG_1(("%s(%p): su_getmsgsize(): %s (%d) N=%ld\n", __func__, (void *)self,
|
||||
su_strerror(err), err, N));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -459,7 +459,6 @@ int tport_ws_init_secondary(tport_t *self, int socket, int accepted,
|
||||
|
||||
if (ws_init(&wstp->ws, socket, wstp->ws_secure ? wspri->ssl_ctx : NULL, 0) < 0) {
|
||||
ws_destroy(&wstp->ws);
|
||||
su_close(socket);
|
||||
wstp->ws_initialized = -1;
|
||||
return *return_reason = "WS_INIT", -1;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,64 @@
|
||||
<!-- Global PSTN supervisory tones -->
|
||||
<!ELEMENT global-tones (tone-set)* >
|
||||
<!ELEMENT tone-set (dial-tone|ringback-tone|busy-tone|congestion-tone|number-unobtainable-tone|special-information-tone|call-waiting-tone|waiting-tone|payphone-recognition-tone|test-number-tone|end-of-three-party-service-tone|service-activated-tone|record-tone|facilities-tone|offering-tone|positive-indication-tone|negative-indication-tone|route-tone|pay-tone|confirmation-tone|intrusion-tone|intercept-tone|warning-tone|holding-tone|search-tone|acceptance-tone|executive-override-tone|function-acknowledge-tone|queue-tone|valid-tone-radio-paging|notify-tone|re-order-tone|preemption-tone|comfort-tone|connection-tone|refusal-tone|line-lockout-tone|permanent-signal-tone|identification-tone|reorder-tone|recall-dial-tone|special-ringback-tone|busy-verification-tone)* >
|
||||
|
||||
<!ELEMENT tone-set (dial-tone
|
||||
|ringing-tone
|
||||
|busy-tone
|
||||
|congestion-tone
|
||||
|number-unobtainable-tone
|
||||
|special-information-tone
|
||||
|call-waiting-tone
|
||||
|waiting-tone
|
||||
|pay-tone
|
||||
|payphone-recognition-tone
|
||||
|warning-tone
|
||||
|test-number-tone
|
||||
|end-of-three-party-service-tone
|
||||
|service-activated-tone
|
||||
|record-tone
|
||||
|facilities-tone
|
||||
|offering-tone
|
||||
|route-tone
|
||||
|confirmation-tone
|
||||
|intrusion-tone
|
||||
|intercept-tone
|
||||
|reorder-tone
|
||||
|holding-tone
|
||||
|search-tone
|
||||
|acceptance-tone
|
||||
|executive-override-tone
|
||||
|function-acknowledge-tone
|
||||
|queue-tone
|
||||
|valid-tone-radio-paging
|
||||
|notify-tone
|
||||
|preemption-tone
|
||||
|comfort-tone
|
||||
|connection-tone
|
||||
|refusal-tone
|
||||
|line-lockout-tone
|
||||
|permanent-signal-tone
|
||||
|identification-tone
|
||||
|positive-indication-tone
|
||||
|negative-indication-tone)* >
|
||||
<!ATTLIST tone-set
|
||||
country CDATA #REQUIRED
|
||||
uncode CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!-- Dialing tones -->
|
||||
<!ELEMENT dial-tone (step)* >
|
||||
<!ATTLIST dial-tone
|
||||
domain CDATA #IMPLIED
|
||||
type CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT ringback-tone (step)* >
|
||||
<!ATTLIST ringback-tone
|
||||
|
||||
<!-- Post-dialing tones -->
|
||||
<!ELEMENT ringing-tone (step)* >
|
||||
<!ATTLIST ringing-tone
|
||||
domain CDATA #IMPLIED
|
||||
type CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!-- Dial result tones -->
|
||||
<!ELEMENT busy-tone (step)* >
|
||||
<!ATTLIST busy-tone
|
||||
domain CDATA #IMPLIED
|
||||
@@ -32,11 +75,14 @@
|
||||
<!ATTLIST special-information-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT call-waiting-tone (step)* >
|
||||
<!ATTLIST call-waiting-tone
|
||||
domain CDATA #IMPLIED
|
||||
type CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!-- Payment related tones -->
|
||||
<!ELEMENT pay-tone (step)* >
|
||||
<!ATTLIST pay-tone
|
||||
domain CDATA #IMPLIED
|
||||
@@ -45,6 +91,7 @@
|
||||
<!ATTLIST payphone-recognition-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT warning-tone (step)* >
|
||||
<!ATTLIST warning-tone
|
||||
type CDATA #IMPLIED
|
||||
@@ -54,19 +101,6 @@
|
||||
<!ATTLIST reorder-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT recall-dial-tone (step)* >
|
||||
<!ATTLIST recall-dial-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT special-ringback-tone (step)* >
|
||||
<!ATTLIST special-ringback-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT busy-verification-tone (step)* >
|
||||
<!ATTLIST busy-verification-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT waiting-tone (step)* >
|
||||
<!ATTLIST waiting-tone
|
||||
domain CDATA #IMPLIED
|
||||
@@ -95,14 +129,6 @@
|
||||
<!ATTLIST offering-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT positive-indication-tone (step)* >
|
||||
<!ATTLIST positive-indication-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT negative-indication-tone (step)* >
|
||||
<!ATTLIST negative-indication-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT route-tone (step)* >
|
||||
<!ATTLIST route-tone
|
||||
domain CDATA #IMPLIED
|
||||
@@ -151,10 +177,6 @@
|
||||
<!ATTLIST notify-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT re-order-tone (step)* >
|
||||
<!ATTLIST re-order-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT preemption-tone (step)* >
|
||||
<!ATTLIST preemption-tone
|
||||
domain CDATA #IMPLIED
|
||||
@@ -183,6 +205,14 @@
|
||||
<!ATTLIST identification-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT positive-indication-tone (step)* >
|
||||
<!ATTLIST positive-indication-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT negative-indication-tone (step)* >
|
||||
<!ATTLIST negative-indication-tone
|
||||
domain CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT step (step|EMPTY)* >
|
||||
<!ATTLIST step
|
||||
|
||||
@@ -2534,7 +2534,7 @@
|
||||
<!-- UNKNOWN_BCS_3 -->
|
||||
<step dir="T" type="PREAMBLE" modem="V.21" value="37"/>
|
||||
<step dir="T" type="HDLC" tag="GARBAGE" value="A2 02 B5 C9 7E 67"/>
|
||||
|
||||
|
||||
<step dir="R" type="HDLC" modem="V.21" tag="DIS" value="FF C8 01 ..." timeout="60000"/>
|
||||
<step dir="R" type="SILENCE"/>
|
||||
|
||||
@@ -6123,7 +6123,7 @@
|
||||
<step type="ANSWER" value="etsi_300_242_a4_white.tif"/>
|
||||
|
||||
<step dir="R" type="CNG"/>
|
||||
|
||||
|
||||
<step dir="T" type="CED"/>
|
||||
<step type="WAIT" value="75"/>
|
||||
<step dir="T" type="PREAMBLE" modem="V.21"/>
|
||||
|
||||
@@ -294,6 +294,9 @@ nobase_include_HEADERS = spandsp/ademco_contactid.h \
|
||||
spandsp/private/modem_echo.h \
|
||||
spandsp/private/noise.h \
|
||||
spandsp/private/oki_adpcm.h \
|
||||
spandsp/private/playout.h \
|
||||
spandsp/private/plc.h \
|
||||
spandsp/private/power_meter.h \
|
||||
spandsp/private/queue.h \
|
||||
spandsp/private/schedule.h \
|
||||
spandsp/private/sig_tone.h \
|
||||
|
||||
@@ -337,6 +337,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
|
||||
double int_part;
|
||||
double frac_row;
|
||||
double frac_col;
|
||||
double width_scaling;
|
||||
#endif
|
||||
uint8_t *row8[2];
|
||||
uint16_t *row16[2];
|
||||
@@ -352,17 +353,13 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
|
||||
input_width = s->input_width - 1;
|
||||
input_length = s->input_length - 1;
|
||||
|
||||
skip = s->raw_output_row*input_length/output_length;
|
||||
skip = s->raw_output_row*input_length/output_length + 1;
|
||||
if (skip >= s->raw_input_row)
|
||||
{
|
||||
skip++;
|
||||
while (skip >= s->raw_input_row)
|
||||
{
|
||||
if (s->raw_input_row >= s->input_length)
|
||||
{
|
||||
s->raw_output_row = -1;
|
||||
break;
|
||||
}
|
||||
row_len = get_and_scrunch_row(s, s->raw_pixel_row[0]);
|
||||
if (row_len != s->output_width)
|
||||
{
|
||||
@@ -380,6 +377,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
|
||||
frac_row = ((s->raw_output_row*256*input_length)/output_length) & 0xFF;
|
||||
#else
|
||||
frac_row = modf((double) s->raw_output_row*input_length/output_length, &int_part);
|
||||
width_scaling = (double) input_width/output_width;
|
||||
#endif
|
||||
|
||||
switch (s->output_format)
|
||||
@@ -402,7 +400,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
|
||||
buf[3*i + j] = saturateu8(c1 + (((c2 - c1)*frac_row) >> 8));
|
||||
}
|
||||
#else
|
||||
frac_col = modf((double) i*input_width/output_width, &int_part);
|
||||
frac_col = modf(width_scaling*i, &int_part);
|
||||
x = 3*int_part;
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
@@ -431,7 +429,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
|
||||
buf16[3*i + j] = saturateu16(c1 + (((c2 - c1)*frac_row) >> 8));
|
||||
}
|
||||
#else
|
||||
frac_col = modf((double) i*input_width/output_width, &int_part);
|
||||
frac_col = modf(width_scaling*i, &int_part);
|
||||
x = 3*int_part;
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
@@ -456,7 +454,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
|
||||
c2 = row8[1][x] + (((row8[1][x + 1] - row8[1][x])*frac_col) >> 8);
|
||||
buf[i] = saturateu8(c1 + (((c2 - c1)*frac_row) >> 8));
|
||||
#else
|
||||
frac_col = modf((double) i*input_width/output_width, &int_part);
|
||||
frac_col = modf(width_scaling*i, &int_part);
|
||||
x = int_part;
|
||||
c1 = row8[0][x] + (row8[0][x + 1] - row8[0][x])*frac_col;
|
||||
c2 = row8[1][x] + (row8[1][x + 1] - row8[1][x])*frac_col;
|
||||
@@ -478,7 +476,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[])
|
||||
c2 = row16[1][x] + (((row16[1][x + 1] - row16[1][x])*frac_col) >> 8);
|
||||
buf[i] = saturateu8(c1 + (((c2 - c1)*frac_row) >> 8));
|
||||
#else
|
||||
frac_col = modf((double) i*input_width/output_width, &int_part);
|
||||
frac_col = modf(width_scaling*i, &int_part);
|
||||
x = int_part;
|
||||
c1 = row16[0][x] + (row16[0][x + 1] - row16[0][x])*frac_col;
|
||||
c2 = row16[1][x] + (row16[1][x + 1] - row16[1][x])*frac_col;
|
||||
|
||||
+176
-176
@@ -1,177 +1,177 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* MODULE NAME : GETOPT.C
|
||||
*
|
||||
* COPYRIGHTS:
|
||||
* This module contains code made available by IBM
|
||||
* Corporation on an AS IS basis. Any one receiving the
|
||||
* module is considered to be licensed under IBM copyrights
|
||||
* to use the IBM-provided source code in any way he or she
|
||||
* deems fit, including copying it, compiling it, modifying
|
||||
* it, and redistributing it, with or without
|
||||
* modifications. No license under any IBM patents or
|
||||
* patent applications is to be implied from this copyright
|
||||
* license.
|
||||
*
|
||||
* A user of the module should understand that IBM cannot
|
||||
* provide technical support for the module and will not be
|
||||
* responsible for any consequences of use of the program.
|
||||
*
|
||||
* Any notices, including this one, are not to be removed
|
||||
* from the module without the prior written consent of
|
||||
* IBM.
|
||||
*
|
||||
* AUTHOR: Original author:
|
||||
* G. R. Blair (BOBBLAIR at AUSVM1)
|
||||
* Internet: bobblair@bobblair.austin.ibm.com
|
||||
*
|
||||
* Extensively revised by:
|
||||
* John Q. Walker II, Ph.D. (JOHHQ at RALVM6)
|
||||
* Internet: johnq@ralvm6.vnet.ibm.com
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
* getopt()
|
||||
*
|
||||
* The getopt() function is a command line parser. It returns the next
|
||||
* option character in argv that matches an option character in opstring.
|
||||
*
|
||||
* The argv argument points to an array of argc+1 elements containing argc
|
||||
* pointers to character strings followed by a null pointer.
|
||||
*
|
||||
* The opstring argument points to a string of option characters; if an
|
||||
* option character is followed by a colon, the option is expected to have
|
||||
* an argument that may or may not be separated from it by white space.
|
||||
* The external variable optarg is set to point to the start of the option
|
||||
* argument on return from getopt().
|
||||
*
|
||||
* The getopt() function places in optind the argv index of the next argument
|
||||
* to be processed. The system initializes the external variable optind to
|
||||
* 1 before the first call to getopt().
|
||||
*
|
||||
* When all options have been processed (that is, up to the first nonoption
|
||||
* argument), getopt() returns EOF. The special option "--" may be used to
|
||||
* delimit the end of the options; EOF will be returned, and "--" will be
|
||||
* skipped.
|
||||
*
|
||||
* The getopt() function returns a question mark (?) when it encounters an
|
||||
* option character not included in opstring. This error message can be
|
||||
* disabled by setting opterr to zero. Otherwise, it returns the option
|
||||
* character that was detected.
|
||||
*
|
||||
* If the special option "--" is detected, or all options have been
|
||||
* processed, EOF is returned.
|
||||
*
|
||||
* Options are marked by either a minus sign (-) or a slash (/).
|
||||
*
|
||||
* No errors are defined.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h> /* for EOF */
|
||||
#include <string.h> /* for strchr() */
|
||||
|
||||
|
||||
/* static (global) variables that are specified as exported by getopt() */
|
||||
char *optarg = NULL; /* pointer to the start of the option argument */
|
||||
int optind = 1; /* number of the next argv[] to be evaluated */
|
||||
int opterr = 1; /* non-zero if a question mark should be returned
|
||||
when a non-valid option character is detected */
|
||||
|
||||
/* handle possible future character set concerns by putting this in a macro */
|
||||
#define _next_char(string) (char)(*(string+1))
|
||||
|
||||
int getopt(int argc, char *argv[], char *opstring)
|
||||
{
|
||||
static char *pIndexPosition = NULL; /* place inside current argv string */
|
||||
char *pArgString = NULL; /* where to start from next */
|
||||
char *pOptString; /* the string in our program */
|
||||
|
||||
|
||||
if (pIndexPosition != NULL) {
|
||||
/* we last left off inside an argv string */
|
||||
if (*(++pIndexPosition)) {
|
||||
/* there is more to come in the most recent argv */
|
||||
pArgString = pIndexPosition;
|
||||
}
|
||||
}
|
||||
|
||||
if (pArgString == NULL) {
|
||||
/* we didn't leave off in the middle of an argv string */
|
||||
if (optind >= argc) {
|
||||
/* more command-line arguments than the argument count */
|
||||
pIndexPosition = NULL; /* not in the middle of anything */
|
||||
return EOF; /* used up all command-line arguments */
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* If the next argv[] is not an option, there can be no more options.
|
||||
*-------------------------------------------------------------------*/
|
||||
pArgString = argv[optind++]; /* set this to the next argument ptr */
|
||||
|
||||
if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */
|
||||
('-' != *pArgString)) {
|
||||
--optind; /* point to current arg once we're done */
|
||||
optarg = NULL; /* no argument follows the option */
|
||||
pIndexPosition = NULL; /* not in the middle of anything */
|
||||
return EOF; /* used up all the command-line flags */
|
||||
}
|
||||
|
||||
/* check for special end-of-flags markers */
|
||||
if ((strcmp(pArgString, "-") == 0) ||
|
||||
(strcmp(pArgString, "--") == 0)) {
|
||||
optarg = NULL; /* no argument follows the option */
|
||||
pIndexPosition = NULL; /* not in the middle of anything */
|
||||
return EOF; /* encountered the special flag */
|
||||
}
|
||||
|
||||
pArgString++; /* look past the / or - */
|
||||
}
|
||||
|
||||
if (':' == *pArgString) { /* is it a colon? */
|
||||
/*---------------------------------------------------------------------
|
||||
* Rare case: if opterr is non-zero, return a question mark;
|
||||
* otherwise, just return the colon we're on.
|
||||
*-------------------------------------------------------------------*/
|
||||
return (opterr ? (int)'?' : (int)':');
|
||||
}
|
||||
else if ((pOptString = strchr(opstring, *pArgString)) == 0) {
|
||||
/*---------------------------------------------------------------------
|
||||
* The letter on the command-line wasn't any good.
|
||||
*-------------------------------------------------------------------*/
|
||||
optarg = NULL; /* no argument follows the option */
|
||||
pIndexPosition = NULL; /* not in the middle of anything */
|
||||
return (opterr ? (int)'?' : (int)*pArgString);
|
||||
}
|
||||
else {
|
||||
/*---------------------------------------------------------------------
|
||||
* The letter on the command-line matches one we expect to see
|
||||
*-------------------------------------------------------------------*/
|
||||
if (':' == _next_char(pOptString)) { /* is the next letter a colon? */
|
||||
/* It is a colon. Look for an argument string. */
|
||||
if ('\0' != _next_char(pArgString)) { /* argument in this argv? */
|
||||
optarg = &pArgString[1]; /* Yes, it is */
|
||||
}
|
||||
else {
|
||||
/*-------------------------------------------------------------
|
||||
* The argument string must be in the next argv.
|
||||
* But, what if there is none (bad input from the user)?
|
||||
* In that case, return the letter, and optarg as NULL.
|
||||
*-----------------------------------------------------------*/
|
||||
if (optind < argc)
|
||||
optarg = argv[optind++];
|
||||
else {
|
||||
optarg = NULL;
|
||||
return (opterr ? (int)'?' : (int)*pArgString);
|
||||
}
|
||||
}
|
||||
pIndexPosition = NULL; /* not in the middle of anything */
|
||||
}
|
||||
else {
|
||||
/* it's not a colon, so just return the letter */
|
||||
optarg = NULL; /* no argument follows the option */
|
||||
pIndexPosition = pArgString; /* point to the letter we're on */
|
||||
}
|
||||
return (int)*pArgString; /* return the letter that matched */
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* MODULE NAME : GETOPT.C
|
||||
*
|
||||
* COPYRIGHTS:
|
||||
* This module contains code made available by IBM
|
||||
* Corporation on an AS IS basis. Any one receiving the
|
||||
* module is considered to be licensed under IBM copyrights
|
||||
* to use the IBM-provided source code in any way he or she
|
||||
* deems fit, including copying it, compiling it, modifying
|
||||
* it, and redistributing it, with or without
|
||||
* modifications. No license under any IBM patents or
|
||||
* patent applications is to be implied from this copyright
|
||||
* license.
|
||||
*
|
||||
* A user of the module should understand that IBM cannot
|
||||
* provide technical support for the module and will not be
|
||||
* responsible for any consequences of use of the program.
|
||||
*
|
||||
* Any notices, including this one, are not to be removed
|
||||
* from the module without the prior written consent of
|
||||
* IBM.
|
||||
*
|
||||
* AUTHOR: Original author:
|
||||
* G. R. Blair (BOBBLAIR at AUSVM1)
|
||||
* Internet: bobblair@bobblair.austin.ibm.com
|
||||
*
|
||||
* Extensively revised by:
|
||||
* John Q. Walker II, Ph.D. (JOHHQ at RALVM6)
|
||||
* Internet: johnq@ralvm6.vnet.ibm.com
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
* getopt()
|
||||
*
|
||||
* The getopt() function is a command line parser. It returns the next
|
||||
* option character in argv that matches an option character in opstring.
|
||||
*
|
||||
* The argv argument points to an array of argc+1 elements containing argc
|
||||
* pointers to character strings followed by a null pointer.
|
||||
*
|
||||
* The opstring argument points to a string of option characters; if an
|
||||
* option character is followed by a colon, the option is expected to have
|
||||
* an argument that may or may not be separated from it by white space.
|
||||
* The external variable optarg is set to point to the start of the option
|
||||
* argument on return from getopt().
|
||||
*
|
||||
* The getopt() function places in optind the argv index of the next argument
|
||||
* to be processed. The system initializes the external variable optind to
|
||||
* 1 before the first call to getopt().
|
||||
*
|
||||
* When all options have been processed (that is, up to the first nonoption
|
||||
* argument), getopt() returns EOF. The special option "--" may be used to
|
||||
* delimit the end of the options; EOF will be returned, and "--" will be
|
||||
* skipped.
|
||||
*
|
||||
* The getopt() function returns a question mark (?) when it encounters an
|
||||
* option character not included in opstring. This error message can be
|
||||
* disabled by setting opterr to zero. Otherwise, it returns the option
|
||||
* character that was detected.
|
||||
*
|
||||
* If the special option "--" is detected, or all options have been
|
||||
* processed, EOF is returned.
|
||||
*
|
||||
* Options are marked by either a minus sign (-) or a slash (/).
|
||||
*
|
||||
* No errors are defined.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h> /* for EOF */
|
||||
#include <string.h> /* for strchr() */
|
||||
|
||||
|
||||
/* static (global) variables that are specified as exported by getopt() */
|
||||
char *optarg = NULL; /* pointer to the start of the option argument */
|
||||
int optind = 1; /* number of the next argv[] to be evaluated */
|
||||
int opterr = 1; /* non-zero if a question mark should be returned
|
||||
when a non-valid option character is detected */
|
||||
|
||||
/* handle possible future character set concerns by putting this in a macro */
|
||||
#define _next_char(string) (char)(*(string+1))
|
||||
|
||||
int getopt(int argc, char *argv[], char *opstring)
|
||||
{
|
||||
static char *pIndexPosition = NULL; /* place inside current argv string */
|
||||
char *pArgString = NULL; /* where to start from next */
|
||||
char *pOptString; /* the string in our program */
|
||||
|
||||
|
||||
if (pIndexPosition != NULL) {
|
||||
/* we last left off inside an argv string */
|
||||
if (*(++pIndexPosition)) {
|
||||
/* there is more to come in the most recent argv */
|
||||
pArgString = pIndexPosition;
|
||||
}
|
||||
}
|
||||
|
||||
if (pArgString == NULL) {
|
||||
/* we didn't leave off in the middle of an argv string */
|
||||
if (optind >= argc) {
|
||||
/* more command-line arguments than the argument count */
|
||||
pIndexPosition = NULL; /* not in the middle of anything */
|
||||
return EOF; /* used up all command-line arguments */
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* If the next argv[] is not an option, there can be no more options.
|
||||
*-------------------------------------------------------------------*/
|
||||
pArgString = argv[optind++]; /* set this to the next argument ptr */
|
||||
|
||||
if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */
|
||||
('-' != *pArgString)) {
|
||||
--optind; /* point to current arg once we're done */
|
||||
optarg = NULL; /* no argument follows the option */
|
||||
pIndexPosition = NULL; /* not in the middle of anything */
|
||||
return EOF; /* used up all the command-line flags */
|
||||
}
|
||||
|
||||
/* check for special end-of-flags markers */
|
||||
if ((strcmp(pArgString, "-") == 0) ||
|
||||
(strcmp(pArgString, "--") == 0)) {
|
||||
optarg = NULL; /* no argument follows the option */
|
||||
pIndexPosition = NULL; /* not in the middle of anything */
|
||||
return EOF; /* encountered the special flag */
|
||||
}
|
||||
|
||||
pArgString++; /* look past the / or - */
|
||||
}
|
||||
|
||||
if (':' == *pArgString) { /* is it a colon? */
|
||||
/*---------------------------------------------------------------------
|
||||
* Rare case: if opterr is non-zero, return a question mark;
|
||||
* otherwise, just return the colon we're on.
|
||||
*-------------------------------------------------------------------*/
|
||||
return (opterr ? (int)'?' : (int)':');
|
||||
}
|
||||
else if ((pOptString = strchr(opstring, *pArgString)) == 0) {
|
||||
/*---------------------------------------------------------------------
|
||||
* The letter on the command-line wasn't any good.
|
||||
*-------------------------------------------------------------------*/
|
||||
optarg = NULL; /* no argument follows the option */
|
||||
pIndexPosition = NULL; /* not in the middle of anything */
|
||||
return (opterr ? (int)'?' : (int)*pArgString);
|
||||
}
|
||||
else {
|
||||
/*---------------------------------------------------------------------
|
||||
* The letter on the command-line matches one we expect to see
|
||||
*-------------------------------------------------------------------*/
|
||||
if (':' == _next_char(pOptString)) { /* is the next letter a colon? */
|
||||
/* It is a colon. Look for an argument string. */
|
||||
if ('\0' != _next_char(pArgString)) { /* argument in this argv? */
|
||||
optarg = &pArgString[1]; /* Yes, it is */
|
||||
}
|
||||
else {
|
||||
/*-------------------------------------------------------------
|
||||
* The argument string must be in the next argv.
|
||||
* But, what if there is none (bad input from the user)?
|
||||
* In that case, return the letter, and optarg as NULL.
|
||||
*-----------------------------------------------------------*/
|
||||
if (optind < argc)
|
||||
optarg = argv[optind++];
|
||||
else {
|
||||
optarg = NULL;
|
||||
return (opterr ? (int)'?' : (int)*pArgString);
|
||||
}
|
||||
}
|
||||
pIndexPosition = NULL; /* not in the middle of anything */
|
||||
}
|
||||
else {
|
||||
/* it's not a colon, so just return the letter */
|
||||
optarg = NULL; /* no argument follows the option */
|
||||
pIndexPosition = pArgString; /* point to the letter we're on */
|
||||
}
|
||||
return (int)*pArgString; /* return the letter that matched */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@
|
||||
#include <math.h>
|
||||
#include <tiffio.h>
|
||||
|
||||
#if !defined(__cplusplus)
|
||||
#include <spandsp/stdbool.h>
|
||||
#endif
|
||||
#include <spandsp/telephony.h>
|
||||
#include <spandsp/fast_convert.h>
|
||||
#include <spandsp/logging.h>
|
||||
|
||||
@@ -40,10 +40,13 @@ struct lab_params_s
|
||||
float offset_b;
|
||||
int ab_are_signed;
|
||||
|
||||
/* Illuminant */
|
||||
/* Illuminant, forward and reverse */
|
||||
float x_n;
|
||||
float y_n;
|
||||
float z_n;
|
||||
float x_rn;
|
||||
float y_rn;
|
||||
float z_rn;
|
||||
};
|
||||
|
||||
/* State of a working instance of the T.42 JPEG FAX encoder */
|
||||
|
||||
@@ -70,6 +70,12 @@ typedef enum
|
||||
T4_COMPRESSION_SYCC_T81 = 0x200,
|
||||
/*! T.88 monochrome JBIG2 compression */
|
||||
T4_COMPRESSION_T88 = 0x400,
|
||||
/*! Uncompressed image. This compression cannot be used for FAXes. It is provided for specifying
|
||||
output formats for received images. */
|
||||
T4_COMPRESSION_UNCOMPRESSED = 0x1000,
|
||||
/*! Conventional JPEG. This compression cannot be used for FAXes. It is provided for specifying
|
||||
output formats for received images. */
|
||||
T4_COMPRESSION_JPEG = 0x2000,
|
||||
/*! Support solour compression without sub-sampling */
|
||||
T4_COMPRESSION_NO_SUBSAMPLING = 0x800000,
|
||||
/*! Gray-scale support by multi-level codecs */
|
||||
|
||||
@@ -1804,8 +1804,8 @@ static int analyze_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED))
|
||||
s->mutual_colour_resolutions &= ~T4_RESOLUTION_200_200;
|
||||
//if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED))
|
||||
// s->mutual_colour_resolutions &= ~T4_RESOLUTION_200_200;
|
||||
}
|
||||
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED))
|
||||
s->mutual_bilevel_resolutions &= ~T4_RESOLUTION_200_100;
|
||||
@@ -2589,7 +2589,7 @@ static int start_sending_document(t30_state_t *s)
|
||||
t30_set_status(s, T30_ERR_NORESSUPPORT);
|
||||
break;
|
||||
default:
|
||||
span_log(&s->logging, SPAN_LOG_WARNING, "Cannot negotiate an image format\n");
|
||||
span_log(&s->logging, SPAN_LOG_WARNING, "Cannot negotiate an image mode\n");
|
||||
t30_set_status(s, T30_ERR_BADTIFF);
|
||||
break;
|
||||
}
|
||||
@@ -6706,9 +6706,9 @@ SPAN_DECLARE(t30_state_t *) t30_init(t30_state_t *s,
|
||||
| T4_SUPPORT_LENGTH_A4
|
||||
| T4_SUPPORT_LENGTH_B4
|
||||
| T4_SUPPORT_LENGTH_UNLIMITED;
|
||||
/* Set the output encoding to something safe. Most things get 1D and 2D
|
||||
encoding right. Quite a lot get other things wrong. */
|
||||
s->supported_output_compressions = T4_COMPRESSION_T4_2D | T4_COMPRESSION_T42_T81;
|
||||
/* Set the output encoding to something safe. For bi-level images ost things get
|
||||
1D and 2D encoding right. Quite a lot get other things wrong. */
|
||||
s->supported_output_compressions = T4_COMPRESSION_T4_2D | T4_COMPRESSION_JPEG;
|
||||
s->local_min_scan_time_code = T30_MIN_SCAN_0MS;
|
||||
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
|
||||
span_log_set_protocol(&s->logging, "T.30");
|
||||
|
||||
+31
-33
@@ -72,6 +72,11 @@
|
||||
#include "spandsp/private/t85.h"
|
||||
#include "spandsp/private/t42.h"
|
||||
|
||||
/* The open_memstream() and fmemopen() in older versions of glibc seems quirky */
|
||||
#if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 12))
|
||||
#undef OPEN_MEMSTREAM
|
||||
#endif
|
||||
|
||||
#define T42_USE_LUTS
|
||||
|
||||
#include "t42_t43_local.h"
|
||||
@@ -97,23 +102,23 @@ typedef struct
|
||||
|
||||
static const illuminant_t illuminants[] =
|
||||
{
|
||||
{"\0D50", "CIE D50/2°", 96.422f, 100.000f, 82.521f},
|
||||
{"\0D50", "CIE D50/2°", 96.422f, 100.000f, 82.521f}, /* Horizon Light. ICC profile PCS */
|
||||
{"", "CIE D50/10°", 96.720f, 100.000f, 81.427f},
|
||||
{"", "CIE D55/2°", 95.682f, 100.000f, 92.149f},
|
||||
{"", "CIE D55/2°", 95.682f, 100.000f, 92.149f}, /* Mid-morning/mid-afternoon daylight */
|
||||
{"", "CIE D55/10°", 95.799f, 100.000f, 90.926f},
|
||||
{"\0D65", "CIE D65/2°", 95.047f, 100.000f, 108.883f},
|
||||
{"\0D65", "CIE D65/2°", 95.047f, 100.000f, 108.883f}, /* Noon daylight, television, sRGB color space */
|
||||
{"", "CIE D65/10°", 94.811f, 100.000f, 107.304f},
|
||||
{"\0D75", "CIE D75/2°", 94.972f, 100.000f, 122.638f},
|
||||
{"\0D75", "CIE D75/2°", 94.972f, 100.000f, 122.638f}, /* North sky daylight */
|
||||
{"", "CIE D75/10°", 94.416f, 100.000f, 120.641f},
|
||||
{"\0\0F2", "F02/2°", 99.186f, 100.000f, 67.393f},
|
||||
{"\0\0F2", "F02/2°", 99.186f, 100.000f, 67.393f}, /* Cool white fluorescent */
|
||||
{"", "F02/10°", 103.279f, 100.000f, 69.027f},
|
||||
{"\0\0F7", "F07/2°", 95.041f, 100.000f, 108.747f},
|
||||
{"\0\0F7", "F07/2°", 95.041f, 100.000f, 108.747f}, /* D65 simulator, daylight simulator */
|
||||
{"", "F07/10°", 95.792f, 100.000f, 107.686f},
|
||||
{"\0F11", "F11/2°", 100.962f, 100.000f, 64.350f},
|
||||
{"\0F11", "F11/2°", 100.962f, 100.000f, 64.350f}, /* Philips TL84, Ultralume 40 */
|
||||
{"", "F11/10°", 103.863f, 100.000f, 65.607f},
|
||||
{"\0\0SA", "A/2°", 109.850f, 100.000f, 35.585f},
|
||||
{"\0\0SA", "A/2°", 109.850f, 100.000f, 35.585f}, /* Incandescent/tungsten */
|
||||
{"", "A/10°", 111.144f, 100.000f, 35.200f},
|
||||
{"\0\0SC", "C/2°", 98.074f, 100.000f, 118.232f},
|
||||
{"\0\0SC", "C/2°", 98.074f, 100.000f, 118.232f}, /* {obsolete} average/north sky daylight */
|
||||
{"", "C/10°", 97.285f, 100.000f, 116.145f},
|
||||
{"", "", 0.000f, 0.000f, 0.000f}
|
||||
};
|
||||
@@ -304,6 +309,9 @@ SPAN_DECLARE(void) set_lab_illuminant(lab_params_t *lab, float new_xn, float new
|
||||
lab->y_n = new_yn;
|
||||
lab->z_n = new_zn;
|
||||
}
|
||||
lab->x_rn = 1.0f/lab->x_n;
|
||||
lab->y_rn = 1.0f/lab->y_n;
|
||||
lab->z_rn = 1.0f/lab->z_n;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
@@ -470,9 +478,9 @@ SPAN_DECLARE(void) srgb_to_lab(lab_params_t *s, uint8_t lab[], const uint8_t srg
|
||||
z = 0.0193f*r + 0.1192f*g + 0.9505f*b;
|
||||
|
||||
/* Normalise for the illuminant */
|
||||
x /= s->x_n;
|
||||
y /= s->y_n;
|
||||
z /= s->z_n;
|
||||
x *= s->x_rn;
|
||||
y *= s->y_rn;
|
||||
z *= s->z_rn;
|
||||
|
||||
/* XYZ to Lab */
|
||||
xx = (x <= 0.008856f) ? (7.787f*x + 0.1379f) : cbrtf(x);
|
||||
@@ -941,14 +949,16 @@ SPAN_DECLARE(int) t42_encode_restart(t42_encode_state_t *s, uint32_t image_width
|
||||
{
|
||||
/* ITU-YCC */
|
||||
/* Illuminant D65 */
|
||||
set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f);
|
||||
//set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f);
|
||||
set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f);
|
||||
set_lab_gamut(&s->lab, 0, 100, -127, 127, -127, 127, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ITULAB */
|
||||
/* Illuminant D50 */
|
||||
set_lab_illuminant(&s->lab, 96.422f, 100.000f, 82.521f);
|
||||
//set_lab_illuminant(&s->lab, 96.422f, 100.000f, 82.521f);
|
||||
set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f);
|
||||
set_lab_gamut(&s->lab, 0, 100, -85, 85, -75, 125, false);
|
||||
}
|
||||
s->compressed_image_size = 0;
|
||||
@@ -965,12 +975,6 @@ SPAN_DECLARE(int) t42_encode_restart(t42_encode_state_t *s, uint32_t image_width
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n");
|
||||
return -1;
|
||||
}
|
||||
if (fseek(s->out, 0, SEEK_SET) != 0)
|
||||
{
|
||||
fclose(s->out);
|
||||
s->out = NULL;
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
if ((s->out = tmpfile()) == NULL)
|
||||
{
|
||||
@@ -1114,14 +1118,6 @@ static int t42_itulab_jpeg_to_srgb(t42_decode_state_t *s)
|
||||
for (i = 0; i < 16; i++)
|
||||
jpeg_save_markers(&s->decompressor, JPEG_APP0 + i, 0xFFFF);
|
||||
|
||||
/* Rewind the file */
|
||||
if (fseek(s->in, 0, SEEK_SET) != 0)
|
||||
{
|
||||
fclose(s->in);
|
||||
s->in = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Take the header */
|
||||
jpeg_read_header(&s->decompressor, false);
|
||||
/* Sanity check and parameter check */
|
||||
@@ -1222,7 +1218,7 @@ SPAN_DECLARE(void) t42_decode_rx_status(t42_decode_state_t *s, int status)
|
||||
{
|
||||
if (t42_itulab_jpeg_to_srgb(s))
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Failed to convert from ITULAB.\n");
|
||||
s->end_of_data = 1;
|
||||
s->end_of_data = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1242,7 +1238,7 @@ SPAN_DECLARE(int) t42_decode_put(t42_decode_state_t *s, const uint8_t data[], si
|
||||
{
|
||||
if (t42_itulab_jpeg_to_srgb(s))
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Failed to convert from ITULAB.\n");
|
||||
s->end_of_data = 1;
|
||||
s->end_of_data = true;
|
||||
}
|
||||
return T4_DECODE_OK;
|
||||
}
|
||||
@@ -1320,18 +1316,20 @@ SPAN_DECLARE(int) t42_decode_restart(t42_decode_state_t *s)
|
||||
{
|
||||
/* ITU-YCC */
|
||||
/* Illuminant D65 */
|
||||
set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f);
|
||||
//set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f);
|
||||
set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f);
|
||||
set_lab_gamut(&s->lab, 0, 100, -127, 127, -127, 127, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ITULAB */
|
||||
/* Illuminant D50 */
|
||||
set_lab_illuminant(&s->lab, 96.422f, 100.000f, 82.521f);
|
||||
//set_lab_illuminant(&s->lab, 96.422f, 100.000f, 82.521f);
|
||||
set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f);
|
||||
set_lab_gamut(&s->lab, 0, 100, -85, 85, -75, 125, false);
|
||||
}
|
||||
|
||||
s->end_of_data = 0;
|
||||
s->end_of_data = false;
|
||||
s->compressed_image_size = 0;
|
||||
|
||||
s->error_message[0] = '\0';
|
||||
|
||||
@@ -123,6 +123,11 @@ SPAN_DECLARE(const char *) t4_compression_to_str(int compression)
|
||||
return "T.43";
|
||||
case T4_COMPRESSION_T45:
|
||||
return "T.45";
|
||||
/* Compressions which can only be used in TIFF files */
|
||||
case T4_COMPRESSION_UNCOMPRESSED:
|
||||
return "Uncompressed";
|
||||
case T4_COMPRESSION_JPEG:
|
||||
return "JPEG";
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
@@ -238,13 +243,27 @@ static int set_tiff_directory_info(t4_rx_state_t *s)
|
||||
break;
|
||||
#endif
|
||||
#if defined(SPANDSP_SUPPORT_T42)
|
||||
case T4_COMPRESSION_JPEG:
|
||||
output_compression = COMPRESSION_JPEG;
|
||||
bits_per_sample = 8;
|
||||
if (t->image_type == T4_IMAGE_TYPE_COLOUR_8BIT)
|
||||
{
|
||||
samples_per_pixel = 3;
|
||||
photometric = PHOTOMETRIC_YCBCR;
|
||||
}
|
||||
else
|
||||
{
|
||||
samples_per_pixel = 1;
|
||||
photometric = PHOTOMETRIC_MINISBLACK;
|
||||
}
|
||||
break;
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
output_compression = COMPRESSION_JPEG;
|
||||
bits_per_sample = 8;
|
||||
if (t->image_type == T4_IMAGE_TYPE_COLOUR_8BIT)
|
||||
{
|
||||
samples_per_pixel = 3;
|
||||
photometric = PHOTOMETRIC_YCBCR; //PHOTOMETRIC_ITULAB;
|
||||
photometric = PHOTOMETRIC_ITULAB;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -306,12 +325,20 @@ static int set_tiff_directory_info(t4_rx_state_t *s)
|
||||
TIFFSetField(t->tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
||||
TIFFSetField(t->tiff_file, TIFFTAG_PHOTOMETRIC, photometric);
|
||||
TIFFSetField(t->tiff_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
|
||||
if (t->compression == T4_COMPRESSION_T42_T81)
|
||||
switch (t->compression)
|
||||
{
|
||||
case T4_COMPRESSION_JPEG:
|
||||
TIFFSetField(t->tiff_file, TIFFTAG_YCBCRSUBSAMPLING, 2, 2);
|
||||
//TIFFSetField(t->tiff_file, TIFFTAG_YCBCRSUBSAMPLING, 1, 1);
|
||||
TIFFSetField(t->tiff_file, TIFFTAG_JPEGQUALITY, 75);
|
||||
TIFFSetField(t->tiff_file, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
|
||||
break;
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
TIFFSetField(t->tiff_file, TIFFTAG_YCBCRSUBSAMPLING, 2, 2);
|
||||
//TIFFSetField(t->tiff_file, TIFFTAG_YCBCRSUBSAMPLING, 1, 1);
|
||||
TIFFSetField(t->tiff_file, TIFFTAG_JPEGQUALITY, 75);
|
||||
TIFFSetField(t->tiff_file, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
|
||||
break;
|
||||
}
|
||||
/* TIFFTAG_STRIPBYTECOUNTS and TIFFTAG_STRIPOFFSETS are added automatically */
|
||||
|
||||
@@ -815,10 +842,14 @@ static void select_tiff_compression(t4_rx_state_t *s, int output_image_type)
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((s->supported_tiff_compressions & T4_COMPRESSION_T42_T81))
|
||||
if ((s->supported_tiff_compressions & T4_COMPRESSION_JPEG))
|
||||
s->tiff.compression = T4_COMPRESSION_JPEG;
|
||||
else if ((s->supported_tiff_compressions & T4_COMPRESSION_T42_T81))
|
||||
s->tiff.compression = T4_COMPRESSION_T42_T81;
|
||||
else if ((s->supported_tiff_compressions & T4_COMPRESSION_T43))
|
||||
s->tiff.compression = T4_COMPRESSION_T43;
|
||||
else if ((s->supported_tiff_compressions & T4_COMPRESSION_UNCOMPRESSED))
|
||||
s->tiff.compression = T4_COMPRESSION_UNCOMPRESSED;
|
||||
}
|
||||
s->tiff.image_type = output_image_type;
|
||||
}
|
||||
@@ -1020,7 +1051,7 @@ SPAN_DECLARE(void) t4_rx_get_transfer_statistics(t4_rx_state_t *s, t4_stats_t *t
|
||||
break;
|
||||
#endif
|
||||
case T4_COMPRESSION_T42_T81:
|
||||
t->type = T4_IMAGE_TYPE_GRAY_8BIT; //T4_IMAGE_TYPE_COLOUR_8BIT;
|
||||
t->type = T4_IMAGE_TYPE_COLOUR_8BIT; //T4_IMAGE_TYPE_GRAY_8BIT;
|
||||
t->width = t42_decode_get_image_width(&s->decoder.t42);
|
||||
t->length = t42_decode_get_image_length(&s->decoder.t42);
|
||||
t->image_type = t->type;
|
||||
|
||||
@@ -2009,6 +2009,8 @@ SPAN_DECLARE(int) t4_tx_set_tx_image_format(t4_tx_state_t *s,
|
||||
/* We can't rework a bilevel image that fits none of the patterns */
|
||||
if (s->tiff.image_type == T4_IMAGE_TYPE_BILEVEL)
|
||||
return T4_IMAGE_FORMAT_NORESSUPPORT;
|
||||
if (!(supported_compressions & T4_COMPRESSION_RESCALING))
|
||||
return T4_IMAGE_FORMAT_NORESSUPPORT;
|
||||
res = T4_IMAGE_FORMAT_OK;
|
||||
/* Any other kind of image might be resizable */
|
||||
s->metadata.image_width = T4_WIDTH_200_A4;
|
||||
@@ -2022,8 +2024,18 @@ SPAN_DECLARE(int) t4_tx_set_tx_image_format(t4_tx_state_t *s,
|
||||
|
||||
if (s->metadata.image_type != s->tiff.image_type || s->metadata.image_width != s->tiff.image_width)
|
||||
{
|
||||
if (image_translate_init(&s->translator, s->metadata.image_type, s->metadata.image_width, -1, s->tiff.image_type, s->tiff.image_width, s->tiff.image_length, translate_row_read2, s) == NULL)
|
||||
if (image_translate_init(&s->translator,
|
||||
s->metadata.image_type,
|
||||
s->metadata.image_width,
|
||||
-1,
|
||||
s->tiff.image_type,
|
||||
s->tiff.image_width,
|
||||
s->tiff.image_length,
|
||||
translate_row_read2,
|
||||
s) == NULL)
|
||||
{
|
||||
return T4_IMAGE_FORMAT_INCOMPATIBLE;
|
||||
}
|
||||
s->metadata.image_length = image_translate_get_output_length(&s->translator);
|
||||
}
|
||||
|
||||
|
||||
@@ -926,7 +926,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
t30_set_supported_colour_resolutions(t30_state[i], 0);
|
||||
}
|
||||
//t30_set_supported_output_compressions(t30_state[i], T4_COMPRESSION_T85);
|
||||
t30_set_supported_output_compressions(t30_state[i], T4_COMPRESSION_T6 | T4_COMPRESSION_JPEG);
|
||||
t30_set_ecm_capability(t30_state[i], use_ecm);
|
||||
t30_set_supported_compressions(t30_state[i],
|
||||
T4_COMPRESSION_T4_1D
|
||||
|
||||
@@ -83,11 +83,11 @@ typedef struct {
|
||||
#else /* BIG_ENDIAN */
|
||||
|
||||
typedef struct {
|
||||
unsigned char version:2; /* protocol version */
|
||||
unsigned char p:1; /* padding flag */
|
||||
unsigned char x:1; /* header extension flag */
|
||||
unsigned char cc:4; /* CSRC count */
|
||||
unsigned char m:1; /* marker bit */
|
||||
unsigned version:2; /* protocol version */
|
||||
unsigned p:1; /* padding flag */
|
||||
unsigned x:1; /* header extension flag */
|
||||
unsigned cc:4; /* CSRC count */
|
||||
unsigned m:1; /* marker bit */
|
||||
unsigned pt:7; /* payload type */
|
||||
unsigned seq:16; /* sequence number */
|
||||
unsigned ts:32; /* timestamp */
|
||||
@@ -131,10 +131,10 @@ typedef struct {
|
||||
#else /* BIG_ENDIAN */
|
||||
|
||||
typedef struct {
|
||||
unsigned char version:2; /* protocol version */
|
||||
unsigned char p:1; /* padding flag */
|
||||
unsigned char rc:5; /* reception report count */
|
||||
unsigned char pt:8; /* payload type */
|
||||
unsigned version:2; /* protocol version */
|
||||
unsigned p:1; /* padding flag */
|
||||
unsigned rc:5; /* reception report count */
|
||||
unsigned pt:8; /* payload type */
|
||||
uint16_t len; /* length */
|
||||
uint32_t ssrc; /* synchronization source */
|
||||
} srtcp_hdr_t;
|
||||
|
||||
@@ -447,6 +447,10 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint16_t seq, uin
|
||||
|
||||
|
||||
if (i->max_drift) {
|
||||
if (i->drift_dropped_packets > 500) {
|
||||
stfu_n_reset(i);
|
||||
}
|
||||
|
||||
if (i->ts_drift < i->max_drift) {
|
||||
if (++i->drift_dropped_packets < i->drift_max_dropped) {
|
||||
stfu_log(STFU_LOG_EMERG, "%s TOO LATE !!! %u \n\n\n", i->name, ts);
|
||||
|
||||
+12
-4
@@ -7,7 +7,7 @@ export KEY_SIZE=${KEY_SIZE}
|
||||
|
||||
TMPFILE="/tmp/fs-ca-$$-$(date +%Y%m%d%H%M%S)"
|
||||
|
||||
COMMON_NAME="FreesSWITCH CA"
|
||||
COMMON_NAME="FreeSWITCH CA"
|
||||
ALT_NAME="DNS:test.freeswitch.org"
|
||||
ORG_NAME="FreeSWITCH"
|
||||
OUTFILE="agent.pem"
|
||||
@@ -47,6 +47,7 @@ setup_ca() {
|
||||
default_bits = \$ENV::KEY_SIZE
|
||||
prompt = no
|
||||
distinguished_name = req_dn
|
||||
x509_extensions = v3_ca
|
||||
|
||||
[ req_dn ]
|
||||
commonName = %CN%
|
||||
@@ -69,6 +70,12 @@ setup_ca() {
|
||||
subjectAltName=%ALTNAME%
|
||||
nsCertType=client
|
||||
extendedKeyUsage=clientAuth
|
||||
|
||||
[ v3_ca ]
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid:always,issuer
|
||||
basicConstraints=CA:TRUE
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
@@ -80,10 +87,12 @@ setup_ca() {
|
||||
"${CONFDIR}/CA/config.tpl" \
|
||||
> "${TMPFILE}.cfg" || exit 1
|
||||
|
||||
openssl ecparam -name secp160r2 -out CA_CURVE.pem
|
||||
openssl req -out "${CONFDIR}/CA/cacert.pem" \
|
||||
-new -x509 -keyout "${CONFDIR}/CA/cakey.pem" \
|
||||
-new -x509 -keyout "${CONFDIR}/CA/cakey.pem" -newkey ec:CA_CURVE.pem \
|
||||
-config "${TMPFILE}.cfg" -nodes -days ${DAYS} -sha1 >/dev/null || exit 1
|
||||
cat "${CONFDIR}/CA/cacert.pem" > "${CONFDIR}/cafile.pem"
|
||||
cp $TMPFILE.cfg /tmp/ssl.cfg
|
||||
rm "${TMPFILE}.cfg"
|
||||
|
||||
echo "DONE"
|
||||
@@ -122,7 +131,7 @@ generate_cert() {
|
||||
> "${TMPFILE}.cfg" || exit 1
|
||||
|
||||
openssl req -new -out "${TMPFILE}.req" \
|
||||
-newkey rsa:${KEY_SIZE} -keyout "${TMPFILE}.key" \
|
||||
-newkey ec:CA_CURVE.pem -keyout "${TMPFILE}.key" \
|
||||
-config "${TMPFILE}.cfg" -nodes -sha1 >/dev/null || exit 1
|
||||
|
||||
openssl x509 -req -CAkey "${CONFDIR}/CA/cakey.pem" -CA "${CONFDIR}/CA/cacert.pem" -CAcreateserial \
|
||||
@@ -148,7 +157,6 @@ remove_ca() {
|
||||
}
|
||||
OUTFILESET="0"
|
||||
command="$1"
|
||||
shift
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
-- zrtp_sas_proxy.lua
|
||||
--
|
||||
-- Copyright (c) 2011-2013 Travis Cross
|
||||
--
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
--
|
||||
-- The above copyright notice and this permission notice shall be included in
|
||||
-- all copies or substantial portions of the Software.
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
-- THE SOFTWARE.
|
||||
--
|
||||
--
|
||||
-- When we're acting as a ZRTP man-in-the-middle, proxy the SAS (Short
|
||||
-- Authentication String) from one leg of the call to the other.
|
||||
--
|
||||
-- This script should be called asynchonously with luarun. e.g.:
|
||||
--
|
||||
-- <action application="export" data="nolocal:api_on_answer=luarun zrtp_sas_proxy.lua ${uuid}"/>
|
||||
--
|
||||
aleg=argv[1]
|
||||
api=freeswitch.API()
|
||||
|
||||
function log(level,msg) return freeswitch.consoleLog(level,"zrtp_sas: "..msg.."\n") end
|
||||
function sleep(sec) return freeswitch.msleep(sec*1000) end
|
||||
function ready() return api:execute("uuid_exists",aleg)=="true" end
|
||||
function getvar(uuid,var)
|
||||
local x=api:execute("uuid_getvar",uuid.." "..var)
|
||||
if x=="_undef_" then return nil end
|
||||
return x
|
||||
end
|
||||
function getvarp(uuid,var) return getvar(uuid,var)=="true" end
|
||||
function display(uuid,msg)
|
||||
local cidn=getvar(uuid,"caller_id_name")
|
||||
return api:execute("uuid_display",uuid.." "..msg.." "..cidn)
|
||||
end
|
||||
|
||||
function mk_sas(sas1,sas2)
|
||||
if sas1 and sas2 then return sas1.." "..sas2
|
||||
else return sas1 or sas2 or "" end
|
||||
end
|
||||
|
||||
function get_sas(uuid)
|
||||
return mk_sas(getvar(uuid,"zrtp_sas1_string_audio"),
|
||||
getvar(uuid,"zrtp_sas2_string"))
|
||||
end
|
||||
|
||||
function log_sas(leg,uuid)
|
||||
return log("notice",leg..": "..uuid.." sas: "..get_sas(uuid))
|
||||
end
|
||||
|
||||
function display_sas(to,from)
|
||||
return display(to," ("..get_sas(from)..")")
|
||||
end
|
||||
|
||||
function get_bleg(aleg)
|
||||
local retries=15 bleg=nil
|
||||
while ready() do
|
||||
if retries<1 then return nil end
|
||||
local bleg=getvar(aleg,"signal_bond")
|
||||
if bleg then return bleg end
|
||||
log("debug","waiting for bleg uuid...")
|
||||
sleep(1)
|
||||
retries=retries-1
|
||||
end
|
||||
end
|
||||
|
||||
function handle_sas(aleg,bleg)
|
||||
local retries=45 af=false bf=false
|
||||
while ready() do
|
||||
if retries<1 then return nil end
|
||||
if not af and getvarp(aleg,"zrtp_secure_media_confirmed_audio") then
|
||||
af=true
|
||||
log_sas("aleg",aleg)
|
||||
display_sas(bleg,aleg)
|
||||
end
|
||||
if not bf and getvarp(bleg,"zrtp_secure_media_confirmed_audio") then
|
||||
bf=true
|
||||
log_sas("bleg",bleg)
|
||||
display_sas(aleg,bleg)
|
||||
end
|
||||
if (af and bf) then break
|
||||
elseif af then log("debug","waiting on bleg zrtp...")
|
||||
elseif bf then log("debug","waiting on aleg zrtp...")
|
||||
else log("debug","waiting for zrtp...") end
|
||||
sleep(1)
|
||||
retries=retries-1
|
||||
end
|
||||
end
|
||||
|
||||
if not (getvarp(aleg,"zrtp_passthru") or getvarp(aleg,"proxy_media")) then
|
||||
handle_sas(aleg,get_bleg(aleg))
|
||||
end
|
||||
@@ -83,6 +83,7 @@ SWITCH_DECLARE(switch_status_t) switch_console_add_complete_func(const char *nam
|
||||
SWITCH_DECLARE(switch_status_t) switch_console_del_complete_func(const char *name);
|
||||
SWITCH_DECLARE(switch_status_t) switch_console_run_complete_func(const char *func, const char *line,
|
||||
const char *last_word, switch_console_callback_match_t **matches);
|
||||
SWITCH_DECLARE(void) switch_console_push_match_unique(switch_console_callback_match_t **matches, const char *new_val);
|
||||
SWITCH_DECLARE(void) switch_console_push_match(switch_console_callback_match_t **matches, const char *new_val);
|
||||
SWITCH_DECLARE(void) switch_console_free_matches(switch_console_callback_match_t **matches);
|
||||
SWITCH_DECLARE(unsigned char) switch_console_complete(const char *line, const char *last_word,
|
||||
|
||||
@@ -878,6 +878,8 @@ SWITCH_DECLARE(char *) switch_core_get_variable_pdup(_In_z_ const char *varname,
|
||||
SWITCH_DECLARE(const char *) switch_core_get_hostname(void);
|
||||
SWITCH_DECLARE(const char *) switch_core_get_switchname(void);
|
||||
|
||||
SWITCH_DECLARE(char *) switch_core_get_domain(switch_bool_t dup);
|
||||
|
||||
/*!
|
||||
\brief Add a global variable to the core
|
||||
\param varname the name of the variable
|
||||
@@ -1015,6 +1017,8 @@ SWITCH_DECLARE(switch_app_log_t *) switch_core_session_get_app_log(_In_ switch_c
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_session_exec(_In_ switch_core_session_t *session,
|
||||
_In_ const switch_application_interface_t *application_interface, _In_opt_z_ const char *arg);
|
||||
|
||||
SWITCH_DECLARE(void) switch_core_session_video_reset(switch_core_session_t *session);
|
||||
/*!
|
||||
\brief Execute an application on a session
|
||||
\param session the current session
|
||||
|
||||
@@ -652,6 +652,7 @@ typedef enum {
|
||||
SWITCH_RTP_FLAG_VIDEO,
|
||||
SWITCH_RTP_FLAG_ENABLE_RTCP,
|
||||
SWITCH_RTP_FLAG_RTCP_MUX,
|
||||
SWITCH_RTP_FLAG_KILL_JB,
|
||||
SWITCH_RTP_FLAG_INVALID
|
||||
} switch_rtp_flag_t;
|
||||
|
||||
@@ -1680,6 +1681,8 @@ typedef uint32_t switch_io_flag_t;
|
||||
SWITCH_EVENT_RE_SCHEDULE - Something scheduled has been rescheduled
|
||||
SWITCH_EVENT_RELOADXML - XML registry has been reloaded
|
||||
SWITCH_EVENT_NOTIFY - Notification
|
||||
SWITCH_EVENT_PHONE_FEATURE - Notification (DND/CFWD/etc)
|
||||
SWITCH_EVENT_PHONE_FEATURE_SUBSCRIBE - Phone feature subscription
|
||||
SWITCH_EVENT_SEND_MESSAGE - Message
|
||||
SWITCH_EVENT_RECV_MESSAGE - Message
|
||||
SWITCH_EVENT_NAT - NAT Management (new/del/status)
|
||||
@@ -1747,6 +1750,8 @@ typedef enum {
|
||||
SWITCH_EVENT_RE_SCHEDULE,
|
||||
SWITCH_EVENT_RELOADXML,
|
||||
SWITCH_EVENT_NOTIFY,
|
||||
SWITCH_EVENT_PHONE_FEATURE,
|
||||
SWITCH_EVENT_PHONE_FEATURE_SUBSCRIBE,
|
||||
SWITCH_EVENT_SEND_MESSAGE,
|
||||
SWITCH_EVENT_RECV_MESSAGE,
|
||||
SWITCH_EVENT_REQUEST_PARAMS,
|
||||
|
||||
@@ -467,14 +467,27 @@ SWITCH_DECLARE(switch_status_t) switch_resolve_host(const char *host, char *buf,
|
||||
|
||||
/*!
|
||||
\brief find local ip of the box
|
||||
\param buf the buffer to write the ip adress found into
|
||||
\param buf the buffer to write the ip address found into
|
||||
\param len the length of the buf
|
||||
\param mask the CIDR found (AF_INET only)
|
||||
\param family the address family to return (AF_INET or AF_INET6)
|
||||
\return SWITCH_STATUS_SUCCESSS for success, otherwise failure
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_find_local_ip(_Out_opt_bytecapcount_(len)
|
||||
char *buf, _In_ int len, _In_opt_ int *mask, _In_ int family);
|
||||
|
||||
/*!
|
||||
\brief find primary ip of the specified interface
|
||||
\param buf the buffer to write the ip address found into
|
||||
\param len the length of the buf
|
||||
\param mask the CIDR found (AF_INET only)
|
||||
\param ifname interface name to check
|
||||
\param family the address family to return (AF_INET or AF_INET6)
|
||||
\return SWITCH_STATUS_SUCCESSS for success, otherwise failure
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_find_interface_ip(_Out_opt_bytecapcount_(len)
|
||||
char *buf, _In_ int len, _In_opt_ int *mask, _In_ const char *ifname, _In_ int family);
|
||||
|
||||
/*!
|
||||
\brief find the char representation of an ip adress
|
||||
\param buf the buffer to write the ip adress found into
|
||||
|
||||
@@ -467,7 +467,7 @@ SWITCH_STANDARD_API(reg_url_function)
|
||||
}
|
||||
|
||||
if (zstr(domain)) {
|
||||
dup_domain = switch_core_get_variable_dup("domain");
|
||||
dup_domain = switch_core_get_domain(SWITCH_TRUE);
|
||||
domain = dup_domain;
|
||||
}
|
||||
|
||||
@@ -886,7 +886,7 @@ SWITCH_STANDARD_API(group_call_function)
|
||||
if (domain) {
|
||||
*domain++ = '\0';
|
||||
} else {
|
||||
if ((dup_domain = switch_core_get_variable_dup("domain"))) {
|
||||
if ((dup_domain = switch_core_get_domain(SWITCH_TRUE))) {
|
||||
domain = dup_domain;
|
||||
}
|
||||
}
|
||||
@@ -1076,7 +1076,7 @@ SWITCH_STANDARD_API(in_group_function)
|
||||
if ((domain = strchr(user, '@'))) {
|
||||
*domain++ = '\0';
|
||||
} else {
|
||||
if ((dup_domain = switch_core_get_variable_dup("domain"))) {
|
||||
if ((dup_domain = switch_core_get_domain(SWITCH_TRUE))) {
|
||||
domain = dup_domain;
|
||||
}
|
||||
}
|
||||
@@ -1131,7 +1131,7 @@ SWITCH_STANDARD_API(user_data_function)
|
||||
if ((domain = strchr(user, '@'))) {
|
||||
*domain++ = '\0';
|
||||
} else {
|
||||
if ((dup_domain = switch_core_get_variable_dup("domain"))) {
|
||||
if ((dup_domain = switch_core_get_domain(SWITCH_TRUE))) {
|
||||
domain = dup_domain;
|
||||
} else {
|
||||
domain = "cluecon.com";
|
||||
@@ -6028,6 +6028,49 @@ SWITCH_STANDARD_API(file_exists_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define INTERFACE_IP_SYNTAX "[auto|ipv4|ipv6] <ifname>"
|
||||
SWITCH_STANDARD_API(interface_ip_function)
|
||||
{
|
||||
char *mydata = NULL, *argv[3] = { 0 };
|
||||
int argc = 0;
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
mydata = strdup(cmd);
|
||||
switch_assert(mydata);
|
||||
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
stream->write_function(stream, "USAGE: interface_ip %s\n", INTERFACE_IP_SYNTAX);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[0], "ipv4")) {
|
||||
if (switch_find_interface_ip(addr, sizeof(addr), NULL, argv[1], AF_INET) == SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "%s", addr);
|
||||
}
|
||||
}
|
||||
else if (!strcasecmp(argv[0], "ipv6")) {
|
||||
if (switch_find_interface_ip(addr, sizeof(addr), NULL, argv[1], AF_INET6) == SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "%s", addr);
|
||||
}
|
||||
}
|
||||
else if (!strcasecmp(argv[0], "auto")) {
|
||||
if (switch_find_interface_ip(addr, sizeof(addr), NULL, argv[1], AF_UNSPEC) == SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "%s", addr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
stream->write_function(stream, "USAGE: interface_ip %s\n", INTERFACE_IP_SYNTAX);
|
||||
}
|
||||
|
||||
end:
|
||||
switch_safe_free(mydata);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
{
|
||||
switch_api_interface_t *commands_api_interface;
|
||||
@@ -6065,6 +6108,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
SWITCH_ADD_API(commands_api_interface, "help", "Show help for all the api commands", help_function, "");
|
||||
SWITCH_ADD_API(commands_api_interface, "host_lookup", "Lookup host", host_lookup_function, "<hostname>");
|
||||
SWITCH_ADD_API(commands_api_interface, "hostname", "Return the system hostname", hostname_api_function, "");
|
||||
SWITCH_ADD_API(commands_api_interface, "interface_ip", "Return the primary IP of an interface", interface_ip_function, INTERFACE_IP_SYNTAX);
|
||||
SWITCH_ADD_API(commands_api_interface, "switchname", "Return the switch name", switchname_api_function, "");
|
||||
SWITCH_ADD_API(commands_api_interface, "hupall", "hupall", hupall_api_function, "<cause> [<var> <value>]");
|
||||
SWITCH_ADD_API(commands_api_interface, "in_group", "Determine if a user is in a group", in_group_function, "<user>[@<domain>] <group_name>");
|
||||
@@ -6217,6 +6261,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
|
||||
switch_console_set_complete("add fsctl flush_db_handles");
|
||||
switch_console_set_complete("add fsctl min_idle_cpu");
|
||||
switch_console_set_complete("add fsctl send_sighup");
|
||||
switch_console_set_complete("add interface_ip auto ::console::list_interfaces");
|
||||
switch_console_set_complete("add interface_ip ipv4 ::console::list_interfaces");
|
||||
switch_console_set_complete("add interface_ip ipv6 ::console::list_interfaces");
|
||||
switch_console_set_complete("add load ::console::list_available_modules");
|
||||
switch_console_set_complete("add nat_map reinit");
|
||||
switch_console_set_complete("add nat_map republish");
|
||||
|
||||
@@ -451,6 +451,7 @@ struct conference_member {
|
||||
conference_cdr_node_t *cdr_node;
|
||||
char *kicked_sound;
|
||||
switch_queue_t *dtmf_queue;
|
||||
switch_thread_t *input_thread;
|
||||
};
|
||||
|
||||
/* Record Node */
|
||||
@@ -642,7 +643,7 @@ static char *conference_rfc4579_render(conference_obj_t *conference, switch_even
|
||||
|
||||
if (!event || !(domain = switch_event_get_header(event, "conference-domain"))) {
|
||||
if (!(domain = conference->domain)) {
|
||||
dup_domain = switch_core_get_variable_dup("domain");
|
||||
dup_domain = switch_core_get_domain(SWITCH_TRUE);
|
||||
if (!(domain = dup_domain)) {
|
||||
domain = "cluecon.com";
|
||||
}
|
||||
@@ -1337,7 +1338,7 @@ static void send_rfc_event(conference_obj_t *conference)
|
||||
}
|
||||
|
||||
if (!(domain = conference->domain)) {
|
||||
dup_domain = switch_core_get_variable_dup("domain");
|
||||
dup_domain = switch_core_get_domain(SWITCH_TRUE);
|
||||
if (!(domain = dup_domain)) {
|
||||
domain = "cluecon.com";
|
||||
}
|
||||
@@ -1376,7 +1377,7 @@ static void send_conference_notify(conference_obj_t *conference, const char *sta
|
||||
}
|
||||
|
||||
if (!(domain = conference->domain)) {
|
||||
dup_domain = switch_core_get_variable_dup("domain");
|
||||
dup_domain = switch_core_get_domain(SWITCH_TRUE);
|
||||
if (!(domain = dup_domain)) {
|
||||
domain = "cluecon.com";
|
||||
}
|
||||
@@ -1607,7 +1608,7 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf
|
||||
conference_member_t *imember;
|
||||
|
||||
for (imember = conference->members; imember; imember = imember->next) {
|
||||
if (imember != conference->video_floor_holder && switch_channel_test_flag(imember->channel, CF_VIDEO)) {
|
||||
if (imember != conference->video_floor_holder && imember->channel && switch_channel_test_flag(imember->channel, CF_VIDEO)) {
|
||||
member = imember;
|
||||
break;
|
||||
}
|
||||
@@ -1658,7 +1659,8 @@ static void conference_set_floor_holder(conference_obj_t *conference, conference
|
||||
int old_id = 0;
|
||||
|
||||
if (!switch_test_flag(conference, CFLAG_VIDEO_BRIDGE) &&
|
||||
((conference->video_floor_holder && !member) || (member && switch_channel_test_flag(member->channel, CF_VIDEO)))) {
|
||||
((conference->video_floor_holder && !member) ||
|
||||
(member && member->channel && switch_channel_test_flag(member->channel, CF_VIDEO)))) {
|
||||
conference_set_video_floor_holder(conference, member, SWITCH_FALSE);
|
||||
}
|
||||
|
||||
@@ -3184,6 +3186,11 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
|
||||
uint32_t hangover = 40, hangunder = 5, hangover_hits = 0, hangunder_hits = 0, diff_level = 400;
|
||||
switch_core_session_t *session = member->session;
|
||||
|
||||
|
||||
if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch_assert(member != NULL);
|
||||
|
||||
switch_clear_flag_locked(member, MFLAG_TALKING);
|
||||
@@ -3480,6 +3487,8 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
|
||||
switch_resample_destroy(&member->read_resampler);
|
||||
switch_clear_flag_locked(member, MFLAG_ITHREAD);
|
||||
|
||||
switch_core_session_rwunlock(session);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3569,17 +3578,15 @@ static void member_add_file_data(conference_member_t *member, int16_t *data, swi
|
||||
/* launch an input thread for the call leg */
|
||||
static void launch_conference_loop_input(conference_member_t *member, switch_memory_pool_t *pool)
|
||||
{
|
||||
switch_thread_t *thread;
|
||||
switch_threadattr_t *thd_attr = NULL;
|
||||
|
||||
if (member == NULL)
|
||||
return;
|
||||
|
||||
switch_threadattr_create(&thd_attr, pool);
|
||||
switch_threadattr_detach_set(thd_attr, 1);
|
||||
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
|
||||
switch_set_flag_locked(member, MFLAG_ITHREAD);
|
||||
switch_thread_create(&thread, thd_attr, conference_loop_input, member, pool);
|
||||
switch_thread_create(&member->input_thread, thd_attr, conference_loop_input, member, pool);
|
||||
}
|
||||
|
||||
/* marshall frames from the conference (or file or tts output) to the call leg */
|
||||
@@ -3599,6 +3606,7 @@ static void conference_loop_output(conference_member_t *member)
|
||||
call_list_t *call_list, *cp;
|
||||
switch_codec_implementation_t read_impl = { 0 };
|
||||
int sanity;
|
||||
switch_status_t st;
|
||||
|
||||
switch_core_session_get_read_impl(member->session, &read_impl);
|
||||
|
||||
@@ -3913,6 +3921,11 @@ static void conference_loop_output(conference_member_t *member)
|
||||
end:
|
||||
|
||||
switch_clear_flag_locked(member, MFLAG_RUNNING);
|
||||
|
||||
if (member->input_thread) {
|
||||
switch_thread_join(&st, member->input_thread);
|
||||
}
|
||||
|
||||
switch_core_timer_destroy(&timer);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Channel leaving conference, cause: %s\n",
|
||||
@@ -7472,6 +7485,8 @@ SWITCH_STANDARD_APP(conference_function)
|
||||
switch_channel_set_app_flag_key("conf_silent", channel, CONF_SILENT_REQ);
|
||||
}
|
||||
|
||||
switch_core_session_video_reset(session);
|
||||
|
||||
switch_channel_set_flag(channel, CF_CONFERENCE);
|
||||
|
||||
if (switch_channel_answer(channel) != SWITCH_STATUS_SUCCESS) {
|
||||
@@ -8028,6 +8043,7 @@ SWITCH_STANDARD_APP(conference_function)
|
||||
|
||||
switch_channel_clear_flag(channel, CF_CONFERENCE);
|
||||
|
||||
switch_core_session_video_reset(session);
|
||||
}
|
||||
|
||||
/* Create a thread for the conference and launch it */
|
||||
@@ -8908,7 +8924,8 @@ static void call_setup_event_handler(switch_event_t *event)
|
||||
|
||||
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "conference_track_status", "true");
|
||||
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "conference_track_call_id", call_id);
|
||||
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "sip_invite_domain", domain);
|
||||
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "sip_invite_domain", domain);
|
||||
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "sip_invite_contact_params", "~isfocus");
|
||||
|
||||
if (!strncasecmp(ostr, "url+", 4)) {
|
||||
ostr += 4;
|
||||
|
||||
@@ -3288,7 +3288,7 @@ static void pickup_send_presence(const char *key_name)
|
||||
}
|
||||
|
||||
if (zstr(domain_name)) {
|
||||
dup_domain_name = switch_core_get_variable_dup("domain");
|
||||
dup_domain_name = switch_core_get_domain(SWITCH_TRUE);
|
||||
domain_name = dup_domain_name;
|
||||
}
|
||||
|
||||
@@ -3363,7 +3363,7 @@ static void pickup_pres_event_handler(switch_event_t *event)
|
||||
if ((domain_name = strchr(key_name, '@'))) {
|
||||
*domain_name++ = '\0';
|
||||
} else {
|
||||
dup_domain_name = switch_core_get_variable_dup("domain");
|
||||
dup_domain_name = switch_core_get_domain(SWITCH_TRUE);
|
||||
domain_name = dup_domain_name;
|
||||
}
|
||||
|
||||
@@ -3422,7 +3422,7 @@ static void pickup_add_session(switch_core_session_t *session, const char *key)
|
||||
char *dup_key = NULL;
|
||||
|
||||
if (!strchr(key, '@')) {
|
||||
dup_key = switch_mprintf("%s@%s", key, switch_core_get_variable("domain"));
|
||||
dup_key = switch_mprintf("%s@%s", key, switch_core_get_domain(SWITCH_FALSE));
|
||||
key = dup_key;
|
||||
}
|
||||
|
||||
@@ -3456,7 +3456,7 @@ static char *pickup_pop_uuid(const char *key, const char *uuid)
|
||||
char *dup_key = NULL;
|
||||
|
||||
if (!strchr(key, '@')) {
|
||||
dup_key = switch_mprintf("%s@%s", key, switch_core_get_variable("domain"));
|
||||
dup_key = switch_mprintf("%s@%s", key, switch_core_get_domain(SWITCH_FALSE));
|
||||
key = dup_key;
|
||||
}
|
||||
|
||||
@@ -3781,7 +3781,7 @@ static switch_call_cause_t group_outgoing_channel(switch_core_session_t *session
|
||||
if ((domain = strchr(group, '@'))) {
|
||||
*domain++ = '\0';
|
||||
} else {
|
||||
domain = switch_core_get_variable_dup("domain");
|
||||
domain = switch_core_get_domain(SWITCH_TRUE);
|
||||
dup_domain = domain;
|
||||
}
|
||||
|
||||
@@ -3904,7 +3904,7 @@ static switch_call_cause_t user_outgoing_channel(switch_core_session_t *session,
|
||||
if ((domain = strchr(user, '@'))) {
|
||||
*domain++ = '\0';
|
||||
} else {
|
||||
domain = switch_core_get_variable_dup("domain");
|
||||
domain = switch_core_get_domain(SWITCH_TRUE);
|
||||
dup_domain = domain;
|
||||
}
|
||||
|
||||
|
||||
@@ -863,7 +863,7 @@ static fifo_node_t *create_node(const char *name, uint32_t importance, switch_mu
|
||||
node->name = switch_core_strdup(node->pool, name);
|
||||
|
||||
if (!strchr(name, '@')) {
|
||||
domain_name = switch_core_get_variable_dup("domain");
|
||||
domain_name = switch_core_get_domain(SWITCH_TRUE);
|
||||
node->domain_name = switch_core_strdup(node->pool, domain_name);
|
||||
}
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@ static switch_status_t parse_voicemail(const char *tag_name, client_t *client, s
|
||||
if (zstr(profile)) profile = "default";
|
||||
|
||||
if (zstr(domain)) {
|
||||
if ((ddom = switch_core_get_variable_dup("domain"))) {
|
||||
if ((ddom = switch_core_get_domain(SWITCH_TRUE))) {
|
||||
domain = ddom;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,17 +274,17 @@ static int oreka_send_sip_message(oreka_session_t *oreka, oreka_recording_status
|
||||
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 (!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 (!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 (!callee_id_name) {
|
||||
if (zstr(callee_id_name)) {
|
||||
callee_id_name = callee_id_number;
|
||||
}
|
||||
|
||||
|
||||
@@ -577,6 +577,26 @@ switch_status_t load_configuration(switch_bool_t reload)
|
||||
spandsp_globals.disable_v17 = 1;
|
||||
else
|
||||
spandsp_globals.disable_v17 = 0;
|
||||
} else if (!strcmp(name, "enable-colour")) {
|
||||
if (switch_true(value))
|
||||
spandsp_globals.enable_colour_fax = 1;
|
||||
else
|
||||
spandsp_globals.enable_colour_fax = 0;
|
||||
} else if (!strcmp(name, "enable-image-resizing")) {
|
||||
if (switch_true(value))
|
||||
spandsp_globals.enable_image_resizing = 1;
|
||||
else
|
||||
spandsp_globals.enable_image_resizing = 0;
|
||||
} else if (!strcmp(name, "enable-colour-to-bilevel")) {
|
||||
if (switch_true(value))
|
||||
spandsp_globals.enable_colour_to_bilevel = 1;
|
||||
else
|
||||
spandsp_globals.enable_colour_to_bilevel = 0;
|
||||
} else if (!strcmp(name, "enable-grayscale-to-bilevel")) {
|
||||
if (switch_true(value))
|
||||
spandsp_globals.enable_grayscale_to_bilevel = 1;
|
||||
else
|
||||
spandsp_globals.enable_grayscale_to_bilevel = 0;
|
||||
} else if (!strcmp(name, "enable-t38")) {
|
||||
if (switch_true(value)) {
|
||||
spandsp_globals.enable_t38= 1;
|
||||
|
||||
@@ -60,6 +60,10 @@ struct spandsp_globals {
|
||||
short int use_ecm;
|
||||
short int verbose;
|
||||
short int disable_v17;
|
||||
short int enable_colour_fax;
|
||||
short int enable_image_resizing;
|
||||
short int enable_colour_to_bilevel;
|
||||
short int enable_grayscale_to_bilevel;
|
||||
short int enable_t38;
|
||||
short int enable_t38_request;
|
||||
short int enable_t38_insist;
|
||||
|
||||
@@ -89,6 +89,10 @@ struct pvt_s {
|
||||
|
||||
int use_ecm;
|
||||
int disable_v17;
|
||||
int enable_colour_fax;
|
||||
int enable_image_resizing;
|
||||
int enable_colour_to_bilevel;
|
||||
int enable_grayscale_to_bilevel;
|
||||
int verbose;
|
||||
int caller;
|
||||
|
||||
@@ -438,7 +442,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int msg)
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "==== Page %s===========================================================\n", pvt->app_mode == FUNCTION_TX ? "Sent ====": "Received ");
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Page no = %d\n", (pvt->app_mode == FUNCTION_TX) ? t30_stats.pages_tx : t30_stats.pages_rx);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Image type = %s (%s in the file)\n", t4_image_type_to_str(t30_stats.type), t4_image_type_to_str(t30_stats.image_type));
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Image type = %s (%s in the file)\n", t4_image_type_to_str(t30_stats.type), t4_image_type_to_str(t30_stats.image_type));
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Image size = %d x %d pixels (%d x %d pixels in the file)\n", t30_stats.width, t30_stats.length, t30_stats.image_width, t30_stats.image_length);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Image resolution = %d/m x %d/m (%d/m x %d/m in the file)\n", t30_stats.x_resolution, t30_stats.y_resolution, t30_stats.image_x_resolution, t30_stats.image_y_resolution);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Compression = %s (%d)\n", t4_compression_to_str(t30_stats.compression), t30_stats.compression);
|
||||
@@ -693,6 +697,7 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
|
||||
const char *tz;
|
||||
int fec_entries = DEFAULT_FEC_ENTRIES;
|
||||
int fec_span = DEFAULT_FEC_SPAN;
|
||||
int compressions;
|
||||
|
||||
|
||||
session = (switch_core_session_t *) pvt->session;
|
||||
@@ -872,8 +877,12 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
|
||||
t30_set_phase_b_handler(t30, phase_b_handler, pvt);
|
||||
|
||||
t30_set_supported_image_sizes(t30,
|
||||
T4_SUPPORT_LENGTH_US_LETTER | T4_SUPPORT_LENGTH_US_LEGAL | T4_SUPPORT_LENGTH_UNLIMITED
|
||||
| T4_SUPPORT_WIDTH_215MM | T4_SUPPORT_WIDTH_255MM | T4_SUPPORT_WIDTH_303MM);
|
||||
T4_SUPPORT_LENGTH_US_LETTER
|
||||
| T4_SUPPORT_LENGTH_US_LEGAL
|
||||
| T4_SUPPORT_LENGTH_UNLIMITED
|
||||
| T4_SUPPORT_WIDTH_215MM
|
||||
| T4_SUPPORT_WIDTH_255MM
|
||||
| T4_SUPPORT_WIDTH_303MM);
|
||||
t30_set_supported_bilevel_resolutions(t30,
|
||||
T4_RESOLUTION_R8_STANDARD
|
||||
| T4_RESOLUTION_R8_FINE
|
||||
@@ -883,7 +892,28 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
|
||||
| T4_RESOLUTION_200_200
|
||||
| T4_RESOLUTION_200_400
|
||||
| T4_RESOLUTION_400_400);
|
||||
t30_set_supported_colour_resolutions(t30, 0);
|
||||
compressions = T4_COMPRESSION_T4_1D
|
||||
| T4_COMPRESSION_T4_2D
|
||||
| T4_COMPRESSION_T6
|
||||
| T4_COMPRESSION_T85
|
||||
| T4_COMPRESSION_T85_L0;
|
||||
if (pvt->enable_colour_fax) {
|
||||
t30_set_supported_colour_resolutions(t30, T4_RESOLUTION_100_100
|
||||
| T4_RESOLUTION_200_200
|
||||
| T4_RESOLUTION_300_300
|
||||
| T4_RESOLUTION_400_400);
|
||||
compressions |= (T4_COMPRESSION_COLOUR | T4_COMPRESSION_T42_T81);
|
||||
} else {
|
||||
t30_set_supported_colour_resolutions(t30, 0);
|
||||
}
|
||||
if (pvt->enable_image_resizing)
|
||||
compressions |= T4_COMPRESSION_RESCALING;
|
||||
if (pvt->enable_colour_to_bilevel)
|
||||
compressions |= T4_COMPRESSION_COLOUR_TO_BILEVEL;
|
||||
if (pvt->enable_grayscale_to_bilevel)
|
||||
compressions |= T4_COMPRESSION_GRAY_TO_BILEVEL;
|
||||
|
||||
t30_set_supported_compressions(t30, compressions);
|
||||
|
||||
if (pvt->disable_v17) {
|
||||
t30_set_supported_modems(t30, T30_SUPPORT_V29 | T30_SUPPORT_V27TER);
|
||||
@@ -894,11 +924,10 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
|
||||
}
|
||||
|
||||
if (pvt->use_ecm) {
|
||||
t30_set_supported_compressions(t30, T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6 | T4_COMPRESSION_T85 | T4_COMPRESSION_T85_L0);
|
||||
t30_set_ecm_capability(t30, TRUE);
|
||||
switch_channel_set_variable(channel, "fax_ecm_requested", "1");
|
||||
} else {
|
||||
t30_set_supported_compressions(t30, T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D);
|
||||
t30_set_ecm_capability(t30, FALSE);
|
||||
switch_channel_set_variable(channel, "fax_ecm_requested", "0");
|
||||
}
|
||||
|
||||
@@ -1217,6 +1246,30 @@ static pvt_t *pvt_init(switch_core_session_t *session, mod_spandsp_fax_applicati
|
||||
pvt->disable_v17 = spandsp_globals.disable_v17;
|
||||
}
|
||||
|
||||
if ((tmp = switch_channel_get_variable(channel, "fax_enable_colour"))) {
|
||||
pvt->enable_colour_fax = switch_true(tmp);
|
||||
} else {
|
||||
pvt->enable_colour_fax = spandsp_globals.enable_colour_fax;
|
||||
}
|
||||
|
||||
if ((tmp = switch_channel_get_variable(channel, "fax_enable_image_resizing"))) {
|
||||
pvt->enable_image_resizing = switch_true(tmp);
|
||||
} else {
|
||||
pvt->enable_image_resizing = spandsp_globals.enable_image_resizing;
|
||||
}
|
||||
|
||||
if ((tmp = switch_channel_get_variable(channel, "fax_enable_colour_to_bilevel"))) {
|
||||
pvt->enable_colour_to_bilevel = switch_true(tmp);
|
||||
} else {
|
||||
pvt->enable_colour_to_bilevel = spandsp_globals.enable_colour_to_bilevel;
|
||||
}
|
||||
|
||||
if ((tmp = switch_channel_get_variable(channel, "fax_enable_grayscale_to_bilevel"))) {
|
||||
pvt->enable_grayscale_to_bilevel = switch_true(tmp);
|
||||
} else {
|
||||
pvt->enable_grayscale_to_bilevel = spandsp_globals.enable_grayscale_to_bilevel;
|
||||
}
|
||||
|
||||
if ((tmp = switch_channel_get_variable(channel, "fax_verbose"))) {
|
||||
pvt->verbose = switch_true(tmp);
|
||||
} else {
|
||||
|
||||
@@ -287,7 +287,7 @@ static void valet_send_presence(const char *lot_name, valet_lot_t *lot, valet_to
|
||||
}
|
||||
|
||||
if (zstr(domain_name)) {
|
||||
dup_domain_name = switch_core_get_variable_dup("domain");
|
||||
dup_domain_name = switch_core_get_domain(SWITCH_TRUE);
|
||||
domain_name = dup_domain_name;
|
||||
}
|
||||
|
||||
|
||||
@@ -2876,7 +2876,7 @@ static switch_status_t deliver_vm(vm_profile_t *profile,
|
||||
update_mwi(profile, myid, domain_name, myfolder, MWI_REASON_NEW);
|
||||
}
|
||||
|
||||
if (send_mail && !zstr(vm_email) && switch_file_exists(file_path, pool) == SWITCH_STATUS_SUCCESS) {
|
||||
if (send_mail && (!zstr(vm_email) || !zstr(vm_notify_email)) && switch_file_exists(file_path, pool) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_t *event;
|
||||
char *from;
|
||||
char *body;
|
||||
@@ -3167,7 +3167,7 @@ static switch_status_t voicemail_inject(const char *data, switch_core_session_t
|
||||
}
|
||||
|
||||
if (zstr(domain)) {
|
||||
if ((dup_domain = switch_core_get_variable_dup("domain"))) {
|
||||
if ((dup_domain = switch_core_get_domain(SWITCH_TRUE))) {
|
||||
domain = dup_domain;
|
||||
}
|
||||
profile_name = domain;
|
||||
|
||||
@@ -894,6 +894,7 @@ SWITCH_STANDARD_API(sangoma_function)
|
||||
char *argv[10] = { 0 };
|
||||
int argc = 0;
|
||||
char *mycmd = NULL;
|
||||
switch_bool_t locked = SWITCH_FALSE;
|
||||
|
||||
if (zstr(cmd)) {
|
||||
stream->write_function(stream, "%s", SANGOMA_SYNTAX);
|
||||
@@ -910,6 +911,10 @@ SWITCH_STANDARD_API(sangoma_function)
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Most operations in this API require the global session lock anyways since sessions can disappear at any moment ... */
|
||||
switch_mutex_lock(g_sessions_lock);
|
||||
locked = SWITCH_TRUE;
|
||||
|
||||
if (!strcasecmp(argv[0], "settings")) {
|
||||
char addrbuff[50];
|
||||
int addr;
|
||||
@@ -922,7 +927,6 @@ SWITCH_STANDARD_API(sangoma_function)
|
||||
const void *var;
|
||||
void *val;
|
||||
unsigned totalsess = 0;
|
||||
switch_mutex_lock(g_sessions_lock);
|
||||
#define STATS_FORMAT "%-10.10s %-10.10s %-10.10s %-10.10s %-10.10s %-10.10s %-10.10s %-10.10s %-10.10s %-10.10s %-15.15s %-15.15s\n"
|
||||
stream->write_function(stream, STATS_FORMAT,
|
||||
"Session", "Codec", "Enc", "Dec", "Enc Tx", "Enc Rx", "Dec Tx", "Dec Rx", "Enc Lost", "Dec Lost", "Enc AvgRxMs", "Dec AvgRxMs");
|
||||
@@ -967,7 +971,6 @@ SWITCH_STANDARD_API(sangoma_function)
|
||||
decoder_avgrxus_str);
|
||||
totalsess++;
|
||||
}
|
||||
switch_mutex_unlock(g_sessions_lock);
|
||||
stream->write_function(stream, "Total sessions: %d\n", totalsess);
|
||||
} else if (!strcasecmp(argv[0], "stats")) {
|
||||
struct sangoma_transcoding_session *sess;
|
||||
@@ -983,6 +986,7 @@ SWITCH_STANDARD_API(sangoma_function)
|
||||
stream->write_function(stream, "%s", SANGOMA_SYNTAX);
|
||||
goto done;
|
||||
}
|
||||
|
||||
sess = sangoma_find_session(sessid);
|
||||
if (!sess) {
|
||||
stream->write_function(stream, "Failed to find session %lu\n", sessid);
|
||||
@@ -1076,6 +1080,9 @@ SWITCH_STANDARD_API(sangoma_function)
|
||||
}
|
||||
|
||||
done:
|
||||
if (locked) {
|
||||
switch_mutex_unlock(g_sessions_lock);
|
||||
}
|
||||
switch_safe_free(mycmd);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
@@ -458,10 +458,7 @@ static switch_status_t channel_on_execute(switch_core_session_t *session)
|
||||
if ((find_non_loopback_bridge(tech_pvt->other_session, &other_session, &other_uuid) == SWITCH_STATUS_SUCCESS)) {
|
||||
switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
|
||||
|
||||
if (switch_channel_test_flag(other_channel, CF_BRIDGED)) {
|
||||
/* Wait for real channel to be exchanging media */
|
||||
switch_channel_wait_for_state(other_channel, channel, CS_EXCHANGE_MEDIA);
|
||||
}
|
||||
switch_channel_wait_for_state_timeout(other_channel, CS_EXCHANGE_MEDIA, 5000);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_INFO, "BOWOUT Replacing loopback channel with real channel: %s\n",
|
||||
switch_channel_get_name(other_channel));
|
||||
|
||||
@@ -376,7 +376,7 @@ RTMP_INVOKE_FUNCTION(rtmp_i_login)
|
||||
}
|
||||
|
||||
if (zstr(domain)) {
|
||||
ddomain = switch_core_get_variable_dup("domain");
|
||||
ddomain = switch_core_get_domain(SWITCH_TRUE);
|
||||
domain = ddomain;
|
||||
}
|
||||
|
||||
|
||||
@@ -438,6 +438,7 @@ switch_status_t skinny_session_send_call_info_all(switch_core_session_t *session
|
||||
struct skinny_session_set_variables_helper {
|
||||
private_t *tech_pvt;
|
||||
switch_channel_t *channel;
|
||||
listener_t *listener;
|
||||
uint32_t count;
|
||||
};
|
||||
|
||||
@@ -463,6 +464,9 @@ int skinny_session_set_variables_callback(void *pArg, int argc, char **argv, cha
|
||||
|
||||
struct skinny_session_set_variables_helper *helper = pArg;
|
||||
char *tmp;
|
||||
listener_t *listener;
|
||||
|
||||
switch_xml_t xroot, xdomain, xuser, xvariables, xvariable;
|
||||
|
||||
helper->count++;
|
||||
switch_channel_set_variable_name_printf(helper->channel, device_name, "skinny_device_name_%d", helper->count);
|
||||
@@ -482,6 +486,50 @@ int skinny_session_set_variables_callback(void *pArg, int argc, char **argv, cha
|
||||
switch_channel_set_variable_name_printf(helper->channel, value, "skinny_line_value_%d", helper->count);
|
||||
switch_channel_set_variable_name_printf(helper->channel, caller_name, "skinny_line_caller_name_%d", helper->count);
|
||||
|
||||
listener = helper->listener;
|
||||
|
||||
if ( ! listener ) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(helper->tech_pvt->session), SWITCH_LOG_DEBUG,
|
||||
"no defined listener on channel var setup, will not attempt to set variables\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Process through and extract any variables from the user and set in the channel */
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(helper->tech_pvt->session), SWITCH_LOG_DEBUG,
|
||||
"searching for user (id=%s) in profile %s in channel var setup\n",
|
||||
listener->device_name, listener->profile->domain);
|
||||
|
||||
if (switch_xml_locate_user("id", listener->device_name, listener->profile->domain, "",
|
||||
&xroot, &xdomain, &xuser, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(helper->tech_pvt->session), SWITCH_LOG_WARNING,
|
||||
"unable to find user (id=%s) in channel var setup\n", listener->device_name);
|
||||
}
|
||||
|
||||
if ( xuser ) {
|
||||
char *uid = (char *) switch_xml_attr_soft(xuser, "id");
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(helper->tech_pvt->session), SWITCH_LOG_DEBUG,
|
||||
"found user (id=%s) in channel var setup\n", uid);
|
||||
|
||||
if ((xvariables = switch_xml_child(xuser, "variables"))) {
|
||||
|
||||
for (xvariable = switch_xml_child(xvariables, "variable"); xvariable; xvariable = xvariable->next) {
|
||||
char *name = (char *) switch_xml_attr_soft(xvariable, "name");
|
||||
char *value = (char *) switch_xml_attr_soft(xvariable, "value");
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(helper->tech_pvt->session), SWITCH_LOG_DEBUG,
|
||||
"found variable (%s=%s) for user (%s) in channel var setup\n", name, value, listener->device_name);
|
||||
|
||||
switch_channel_set_variable_name_printf(helper->channel, value, "%s", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( xroot ) {
|
||||
switch_xml_free(xroot);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -492,6 +540,7 @@ switch_status_t skinny_session_set_variables(switch_core_session_t *session, lis
|
||||
|
||||
helper.tech_pvt = switch_core_session_get_private(session);
|
||||
helper.channel = switch_core_session_get_channel(session);
|
||||
helper.listener = listener;
|
||||
helper.count = 0;
|
||||
|
||||
switch_channel_set_variable(helper.channel, "skinny_profile_name", helper.tech_pvt->profile->name);
|
||||
|
||||
@@ -284,11 +284,13 @@ char *generate_pai_str(private_object_t *tech_pvt)
|
||||
pai = switch_core_session_sprintf(tech_pvt->session, "%s: \"%s\" <%s>%s\n"
|
||||
"X-FS-Display-Name: %s\nX-FS-Display-Number: %s\n",
|
||||
header, callee_name, callee_number,
|
||||
tech_pvt->cid_type == CID_TYPE_RPID ? ";party=calling;privacy=off;screen=no" : "",
|
||||
tech_pvt->cid_type == CID_TYPE_RPID && !switch_stristr("aastra", ua) ?
|
||||
";party=calling;privacy=off;screen=no" : "",
|
||||
callee_name, callee_number);
|
||||
} else {
|
||||
pai = switch_core_session_sprintf(tech_pvt->session, "%s: \"%s\" <%s>%s\n", header, callee_name, callee_number,
|
||||
tech_pvt->cid_type == CID_TYPE_RPID ? ";party=calling;privacy=off;screen=no" : "");
|
||||
tech_pvt->cid_type == CID_TYPE_RPID && !switch_stristr("aastra", ua) ?
|
||||
";party=calling;privacy=off;screen=no" : "");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3536,7 +3538,7 @@ SWITCH_STANDARD_API(sofia_contact_function)
|
||||
}
|
||||
|
||||
if (zstr(domain)) {
|
||||
dup_domain = switch_core_get_variable_dup("domain");
|
||||
dup_domain = switch_core_get_domain(SWITCH_TRUE);
|
||||
domain = dup_domain;
|
||||
}
|
||||
|
||||
@@ -3726,7 +3728,7 @@ SWITCH_STANDARD_API(sofia_presence_data_function)
|
||||
}
|
||||
|
||||
if (zstr(domain)) {
|
||||
dup_domain = switch_core_get_variable_dup("domain");
|
||||
dup_domain = switch_core_get_domain(SWITCH_TRUE);
|
||||
domain = dup_domain;
|
||||
}
|
||||
|
||||
@@ -4580,6 +4582,70 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session
|
||||
return cause;
|
||||
}
|
||||
|
||||
static int notify_csta_callback(void *pArg, int argc, char **argv, char **columnNames)
|
||||
{
|
||||
nua_handle_t *nh;
|
||||
sofia_profile_t *ext_profile = NULL, *profile = (sofia_profile_t *) pArg;
|
||||
int i = 0;
|
||||
char *user = argv[i++];
|
||||
char *host = argv[i++];
|
||||
char *contact_in = argv[i++];
|
||||
char *profile_name = argv[i++];
|
||||
char *call_id = argv[i++];
|
||||
char *full_from = argv[i++];
|
||||
char *full_to = argv[i++];
|
||||
int expires = atoi(argv[i++]);
|
||||
char *body = argv[i++];
|
||||
char *ct = argv[i++];
|
||||
char *id = NULL;
|
||||
char *contact;
|
||||
sofia_destination_t *dst = NULL;
|
||||
char *route_uri = NULL;
|
||||
|
||||
time_t epoch_now = switch_epoch_time_now(NULL);
|
||||
time_t expires_in = (expires - epoch_now);
|
||||
char *extra_headers = switch_mprintf("Subscription-State: active, %d\r\n", expires_in);
|
||||
|
||||
if (profile_name && strcasecmp(profile_name, profile->name)) {
|
||||
if ((ext_profile = sofia_glue_find_profile(profile_name))) {
|
||||
profile = ext_profile;
|
||||
}
|
||||
}
|
||||
|
||||
id = switch_mprintf("sip:%s@%s", user, host);
|
||||
switch_assert(id);
|
||||
contact = sofia_glue_get_url_from_contact(contact_in, 1);
|
||||
|
||||
|
||||
dst = sofia_glue_get_destination((char *) contact);
|
||||
|
||||
if (dst->route_uri) {
|
||||
route_uri = sofia_glue_strip_uri(dst->route_uri);
|
||||
}
|
||||
|
||||
//nh = nua_handle(profile->nua, NULL, NUTAG_URL(dst->contact), SIPTAG_FROM_STR(id), SIPTAG_TO_STR(id), SIPTAG_CONTACT_STR(profile->url), TAG_END());
|
||||
nh = nua_handle(profile->nua, NULL, NUTAG_URL(dst->contact), SIPTAG_FROM_STR(full_from), SIPTAG_TO_STR(full_to), SIPTAG_CONTACT_STR(profile->url), TAG_END());
|
||||
|
||||
nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
|
||||
|
||||
nua_notify(nh, NUTAG_NEWSUB(1),
|
||||
TAG_IF(dst->route_uri, NUTAG_PROXY(route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)), TAG_IF(call_id, SIPTAG_CALL_ID_STR(call_id)),
|
||||
SIPTAG_EVENT_STR("as-feature-event"), SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), TAG_END());
|
||||
|
||||
|
||||
|
||||
switch_safe_free(route_uri);
|
||||
sofia_glue_free_destination(dst);
|
||||
|
||||
free(id);
|
||||
free(contact);
|
||||
|
||||
if (ext_profile) {
|
||||
sofia_glue_release_profile(ext_profile);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int notify_callback(void *pArg, int argc, char **argv, char **columnNames)
|
||||
{
|
||||
@@ -4653,22 +4719,69 @@ static void general_event_handler(switch_event_t *event)
|
||||
const char *to_uri = switch_event_get_header(event, "to-uri");
|
||||
const char *from_uri = switch_event_get_header(event, "from-uri");
|
||||
const char *extra_headers = switch_event_get_header(event, "extra-headers");
|
||||
const char *contact_uri = switch_event_get_header(event, "contact-uri");
|
||||
const char *no_sub_state = switch_event_get_header(event, "no-sub-state");
|
||||
|
||||
sofia_profile_t *profile;
|
||||
|
||||
if (contact_uri) {
|
||||
if (!es) {
|
||||
es = "message-summary";
|
||||
}
|
||||
|
||||
if (to_uri || from_uri) {
|
||||
if (!ct) {
|
||||
ct = "application/simple-message-summary";
|
||||
}
|
||||
|
||||
if (!to_uri) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing To-URI header\n");
|
||||
if (!profile_name) {
|
||||
profile_name = "default";
|
||||
}
|
||||
|
||||
if (!(profile = sofia_glue_find_profile(profile_name))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find profile %s\n", profile_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!from_uri) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing From-URI header\n");
|
||||
return;
|
||||
if (to_uri && from_uri) {
|
||||
sofia_destination_t *dst = NULL;
|
||||
nua_handle_t *nh;
|
||||
char *route_uri = NULL;
|
||||
char *sip_sub_st = NULL;
|
||||
|
||||
dst = sofia_glue_get_destination((char *) contact_uri);
|
||||
|
||||
if (dst->route_uri) {
|
||||
route_uri = sofia_glue_strip_uri(dst->route_uri);
|
||||
}
|
||||
|
||||
nh = nua_handle(profile->nua,
|
||||
NULL,
|
||||
NUTAG_URL(dst->contact),
|
||||
SIPTAG_FROM_STR(from_uri),
|
||||
SIPTAG_TO_STR(to_uri),
|
||||
SIPTAG_CONTACT_STR(profile->url),
|
||||
TAG_END());
|
||||
|
||||
nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
|
||||
|
||||
if (!switch_true(no_sub_state)) {
|
||||
sip_sub_st = "terminated;reason=noresource";
|
||||
}
|
||||
|
||||
nua_notify(nh,
|
||||
NUTAG_NEWSUB(1), TAG_IF(sip_sub_st, SIPTAG_SUBSCRIPTION_STATE_STR(sip_sub_st)),
|
||||
TAG_IF(dst->route_uri, NUTAG_PROXY(dst->route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)), TAG_IF(call_id, SIPTAG_CALL_ID_STR(call_id)),
|
||||
SIPTAG_EVENT_STR(es), TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(ct)), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)),
|
||||
TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END());
|
||||
|
||||
switch_safe_free(route_uri);
|
||||
sofia_glue_free_destination(dst);
|
||||
|
||||
sofia_glue_release_profile(profile);
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (to_uri || from_uri) {
|
||||
if (!es) {
|
||||
es = "message-summary";
|
||||
}
|
||||
@@ -4768,6 +4881,96 @@ static void general_event_handler(switch_event_t *event)
|
||||
|
||||
}
|
||||
break;
|
||||
case SWITCH_EVENT_PHONE_FEATURE:
|
||||
{
|
||||
const char *profile_name = switch_event_get_header(event, "profile");
|
||||
const char *user = switch_event_get_header(event, "user");
|
||||
const char *host = switch_event_get_header(event, "host");
|
||||
const char *call_id = switch_event_get_header(event, "call-id");
|
||||
const char *csta_event = switch_event_get_header(event, "csta-event");
|
||||
|
||||
char *ct = "application/x-as-feature-event+xml";
|
||||
|
||||
sofia_profile_t *profile;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Phone Feature NOTIFY\n");
|
||||
if (profile_name && user && host && (profile = sofia_glue_find_profile(profile_name))) {
|
||||
char *sql;
|
||||
switch_stream_handle_t stream = { 0 };
|
||||
SWITCH_STANDARD_STREAM(stream);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "we have all required vars\n");
|
||||
|
||||
if (csta_event) {
|
||||
if (!strcmp(csta_event, "init")) {
|
||||
char *boundary_string = "UniqueFreeSWITCHBoundary";
|
||||
switch_stream_handle_t dnd_stream = { 0 };
|
||||
char *header_name = NULL;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending multipart with DND and CFWD\n");
|
||||
|
||||
if ((header_name = switch_event_get_header(event, "forward_immediate"))) {
|
||||
switch_stream_handle_t fwdi_stream = { 0 };
|
||||
SWITCH_STANDARD_STREAM(fwdi_stream);
|
||||
write_csta_xml_chunk(event, fwdi_stream, "ForwardingEvent", "forwardImmediate");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%s] is %d bytes long\n", (char *)fwdi_stream.data, (int)strlen(fwdi_stream.data));
|
||||
stream.write_function(&stream, "--%s\nContent-Type: application/x-as-feature-event+xml\nContent-Length:%d\nContent-ID:<%s@%s>\n\n%s", boundary_string, strlen(fwdi_stream.data), user, host, fwdi_stream.data);
|
||||
switch_safe_free(fwdi_stream.data);
|
||||
}
|
||||
if ((header_name = switch_event_get_header(event, "forward_busy"))) {
|
||||
switch_stream_handle_t fwdb_stream = { 0 };
|
||||
SWITCH_STANDARD_STREAM(fwdb_stream);
|
||||
write_csta_xml_chunk(event, fwdb_stream, "ForwardingEvent", "forwardBusy");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%s] is %d bytes long\n", (char *)fwdb_stream.data, (int)strlen(fwdb_stream.data));
|
||||
stream.write_function(&stream, "--%s\nContent-Type: application/x-as-feature-event+xml\nContent-Length:%d\nContent-ID:<%s@%s>\n\n%s", boundary_string, strlen(fwdb_stream.data), user, host, fwdb_stream.data);
|
||||
switch_safe_free(fwdb_stream.data);
|
||||
}
|
||||
if ((header_name = switch_event_get_header(event, "forward_no_answer"))) {
|
||||
switch_stream_handle_t fwdna_stream = { 0 };
|
||||
SWITCH_STANDARD_STREAM(fwdna_stream);
|
||||
write_csta_xml_chunk(event, fwdna_stream, "ForwardingEvent", "forwardNoAns");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%s] is %d bytes long\n", (char *)fwdna_stream.data, (int)strlen(fwdna_stream.data));
|
||||
stream.write_function(&stream, "--%s\nContent-Type: application/x-as-feature-event+xml\nContent-Length:%d\nContent-ID:<%s@%s>\n\n%s", boundary_string, strlen(fwdna_stream.data), user, host, fwdna_stream.data);
|
||||
switch_safe_free(fwdna_stream.data);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_STREAM(dnd_stream);
|
||||
write_csta_xml_chunk(event, dnd_stream, "DoNotDisturbEvent", NULL);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%s] is %d bytes long\n", (char *)dnd_stream.data, (int)strlen(dnd_stream.data));
|
||||
stream.write_function(&stream, "--%s\nContent-Type:application/x-as-feature-event+xml\nContent-Length:%d\nContent-ID:<%s@%s>\n\n%s", boundary_string, strlen(dnd_stream.data), user, host, dnd_stream.data);
|
||||
switch_safe_free(dnd_stream.data);
|
||||
|
||||
stream.write_function(&stream, "--%s--\n", boundary_string);
|
||||
|
||||
ct = switch_mprintf("multipart/mixed; boundary=\"%s\"", boundary_string);
|
||||
} else {
|
||||
// this will need some work to handle the different types of forwarding events
|
||||
write_csta_xml_chunk(event, stream, csta_event, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (call_id) {
|
||||
sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,call_id,full_from,full_to,expires,'%q', '%q' "
|
||||
"from sip_subscriptions where event='as-feature-event' and call_id='%q'", stream.data, ct, call_id);
|
||||
} else {
|
||||
sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,call_id,full_from,full_to,expires,'%q', '%q' "
|
||||
"from sip_subscriptions where event='as-feature-event' and sip_user='%s' and sip_host='%q'", stream.data, ct, switch_str_nil(user), switch_str_nil(host)
|
||||
);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query: %s\n", sql);
|
||||
switch_safe_free(stream.data);
|
||||
switch_mutex_lock(profile->ireg_mutex);
|
||||
sofia_glue_execute_sql_callback(profile, NULL, sql, notify_csta_callback, profile);
|
||||
switch_mutex_unlock(profile->ireg_mutex);
|
||||
sofia_glue_release_profile(profile);
|
||||
|
||||
free(sql);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "missing something\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SWITCH_EVENT_SEND_MESSAGE:
|
||||
{
|
||||
const char *profile_name = switch_event_get_header(event, "profile");
|
||||
@@ -5022,6 +5225,57 @@ static void general_event_handler(switch_event_t *event)
|
||||
}
|
||||
}
|
||||
|
||||
void write_csta_xml_chunk(switch_event_t *event, switch_stream_handle_t stream, const char *csta_event, char *fwdtype)
|
||||
{
|
||||
const char *device = switch_event_get_header(event, "device");
|
||||
|
||||
if (csta_event) {
|
||||
stream.write_function(&stream, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<%s xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">\n", csta_event);
|
||||
}
|
||||
|
||||
if (device) {
|
||||
stream.write_function(&stream, " <device>%s</device>\n", device);
|
||||
}
|
||||
|
||||
if (!strcmp(csta_event, "DoNotDisturbEvent")) {
|
||||
const char *dndstatus = switch_event_get_header(event, "doNotDisturbOn");
|
||||
|
||||
if (dndstatus) {
|
||||
stream.write_function(&stream, " <doNotDisturbOn>%s</doNotDisturbOn>\n", dndstatus);
|
||||
}
|
||||
} else if(!strcmp(csta_event, "ForwardingEvent")) {
|
||||
const char *fwdstatus = switch_event_get_header(event, "forwardStatus");
|
||||
const char *fwdto = NULL;
|
||||
const char *ringcount = NULL;
|
||||
|
||||
if (strcmp("forwardImmediate", fwdtype)) {
|
||||
fwdto = switch_event_get_header(event, "forward_immediate");
|
||||
} else if (strcmp("forwardBusy", fwdtype)) {
|
||||
fwdto = switch_event_get_header(event, "forward_busy");
|
||||
} else if (strcmp("fowardNoAns", fwdtype)) {
|
||||
fwdto = switch_event_get_header(event, "forward_no_answer");
|
||||
ringcount = switch_event_get_header(event, "ringCount");
|
||||
}
|
||||
|
||||
if (fwdtype) {
|
||||
stream.write_function(&stream, " <forwardingType>%s</forwardingType>\n", fwdtype);
|
||||
}
|
||||
if (fwdstatus) {
|
||||
stream.write_function(&stream, " <forwardStatus>%s</forwardStatus>\n", fwdstatus);
|
||||
}
|
||||
if (fwdto) {
|
||||
stream.write_function(&stream, " <forwardTo>%s</forwardTo>\n", fwdto);
|
||||
}
|
||||
if (ringcount) {
|
||||
stream.write_function(&stream, " <ringCount>%s</ringCount>\n", ringcount);
|
||||
}
|
||||
}
|
||||
|
||||
if (csta_event) {
|
||||
stream.write_function(&stream, "</%s>\n", csta_event);
|
||||
}
|
||||
}
|
||||
|
||||
switch_status_t list_profiles_full(const char *line, const char *cursor, switch_console_callback_match_t **matches, switch_bool_t show_aliases)
|
||||
{
|
||||
sofia_profile_t *profile = NULL;
|
||||
@@ -5285,6 +5539,11 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_PHONE_FEATURE, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_SEND_MESSAGE, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
@@ -22,14 +22,14 @@
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Ken Rice <krice@freeswitch.org>
|
||||
* Paul D. Tinsley <pdt at jackhammer.org>
|
||||
* Bret McDanel <trixter AT 0xdecafbad.com>
|
||||
* Marcel Barbulescu <marcelbarbulescu@gmail.com>
|
||||
* Raymond Chandler <intralanman@gmail.com>
|
||||
* Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
|
||||
* Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
|
||||
*
|
||||
*
|
||||
* mod_sofia.h -- SOFIA SIP Endpoint
|
||||
@@ -149,9 +149,9 @@ typedef enum {
|
||||
|
||||
typedef struct sofia_dispatch_event_s {
|
||||
nua_saved_event_t event[1];
|
||||
nua_handle_t *nh;
|
||||
nua_event_data_t const *data;
|
||||
su_time_t when;
|
||||
nua_handle_t *nh;
|
||||
nua_event_data_t const *data;
|
||||
su_time_t when;
|
||||
sip_t *sip;
|
||||
nua_t *nua;
|
||||
sofia_profile_t *profile;
|
||||
@@ -353,7 +353,7 @@ struct mod_sofia_globals {
|
||||
int reg_deny_binding_fetch_and_no_lookup; /* backwards compatibility */
|
||||
int auto_nat;
|
||||
int tracelevel;
|
||||
char *capture_server;
|
||||
char *capture_server;
|
||||
int rewrite_multicasted_fs_path;
|
||||
int presence_flush;
|
||||
switch_thread_t *presence_thread;
|
||||
@@ -511,10 +511,10 @@ typedef enum {
|
||||
} sofia_media_options_t;
|
||||
|
||||
typedef enum {
|
||||
PAID_DEFAULT = 0,
|
||||
PAID_USER,
|
||||
PAID_USER_DOMAIN,
|
||||
PAID_VERBATIM
|
||||
PAID_DEFAULT = 0,
|
||||
PAID_USER,
|
||||
PAID_USER_DOMAIN,
|
||||
PAID_VERBATIM
|
||||
} sofia_paid_type_t;
|
||||
|
||||
#define MAX_RTPIP 50
|
||||
@@ -619,7 +619,7 @@ struct sofia_profile {
|
||||
char *pre_trans_execute;
|
||||
char *post_trans_execute;
|
||||
char *inner_pre_trans_execute;
|
||||
char *inner_post_trans_execute;
|
||||
char *inner_post_trans_execute;
|
||||
switch_sql_queue_manager_t *qm;
|
||||
char *acl[SOFIA_MAX_ACL];
|
||||
char *acl_pass_context[SOFIA_MAX_ACL];
|
||||
@@ -678,7 +678,7 @@ struct sofia_profile {
|
||||
sofia_paid_type_t paid_type;
|
||||
uint32_t rtp_digit_delay;
|
||||
switch_queue_t *event_queue;
|
||||
switch_thread_t *thread;
|
||||
switch_thread_t *thread;
|
||||
switch_core_media_vflag_t vflags;
|
||||
char *ws_ip;
|
||||
switch_port_t ws_port;
|
||||
@@ -851,7 +851,7 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t
|
||||
sofia_dispatch_event_t *de, tagi_t tags[]);
|
||||
|
||||
void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, sofia_dispatch_event_t *de, tagi_t tags[]);
|
||||
|
||||
|
||||
|
||||
void sofia_reg_handle_sip_i_register(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t **sofia_private, sip_t const *sip,
|
||||
sofia_dispatch_event_t *de,
|
||||
@@ -868,9 +868,9 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
|
||||
void launch_sofia_profile_thread(sofia_profile_t *profile);
|
||||
|
||||
switch_status_t sofia_presence_chat_send(switch_event_t *message_event);
|
||||
|
||||
|
||||
/*
|
||||
* \brief Sets the "ep_codec_string" channel variable, parsing r_sdp and taing codec_string in consideration
|
||||
* \brief Sets the "ep_codec_string" channel variable, parsing r_sdp and taing codec_string in consideration
|
||||
* \param channel Current channel
|
||||
* \param codec_string The profile's codec string or NULL if inexistant
|
||||
* \param sdp The parsed SDP content
|
||||
@@ -935,7 +935,7 @@ switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status);
|
||||
void sofia_glue_do_xfer_invite(switch_core_session_t *session);
|
||||
uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip,
|
||||
sofia_dispatch_event_t *de,
|
||||
sofia_regtype_t regtype, char *key,
|
||||
sofia_regtype_t regtype, char *key,
|
||||
uint32_t keylen, switch_event_t **v_event, const char *is_nat, sofia_private_t **sofia_private_p, switch_xml_t *user_xml);
|
||||
extern switch_endpoint_interface_t *sofia_endpoint_interface;
|
||||
void sofia_presence_set_chat_hash(private_object_t *tech_pvt, sip_t const *sip);
|
||||
@@ -1044,7 +1044,7 @@ void sofia_glue_restart_all_profiles(void);
|
||||
const char *sofia_state_string(int state);
|
||||
void sofia_wait_for_reply(struct private_object *tech_pvt, nua_event_t event, uint32_t timeout);
|
||||
|
||||
/*
|
||||
/*
|
||||
* Logging control functions
|
||||
*/
|
||||
|
||||
@@ -1117,6 +1117,7 @@ switch_status_t sofia_glue_ext_address_lookup(sofia_profile_t *profile, char **i
|
||||
void sofia_reg_check_socket(sofia_profile_t *profile, const char *call_id, const char *network_addr, const char *network_ip);
|
||||
void sofia_reg_close_handles(sofia_profile_t *profile);
|
||||
|
||||
void write_csta_xml_chunk(switch_event_t *event, switch_stream_handle_t stream, const char *csta_event, char *fwd_type);
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
|
||||
@@ -153,6 +153,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
|
||||
char name[128];
|
||||
crtp_private_t *tech_pvt = NULL;
|
||||
switch_caller_profile_t *caller_profile;
|
||||
switch_rtp_flag_t rtp_flags[SWITCH_RTP_FLAG_INVALID] = {0};
|
||||
|
||||
const char *err;
|
||||
|
||||
@@ -261,7 +262,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
|
||||
|
||||
if (!(tech_pvt->rtp_session = switch_rtp_new(local_addr, local_port, remote_addr, remote_port, tech_pvt->agreed_pt,
|
||||
tech_pvt->read_codec.implementation->samples_per_packet, ptime * 1000,
|
||||
0, "soft", &err, switch_core_session_get_pool(*new_session)))) {
|
||||
rtp_flags, "soft", &err, switch_core_session_get_pool(*new_session)))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't setup RTP session: [%s]\n", err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
+354
-327
File diff suppressed because it is too large
Load Diff
@@ -497,7 +497,12 @@ char *sofia_overcome_sip_uri_weakness(switch_core_session_t *session, const char
|
||||
char *stripped = switch_core_session_strdup(session, uri);
|
||||
char *new_uri = NULL;
|
||||
char *p;
|
||||
const char *url_params = NULL;
|
||||
|
||||
if (!zstr(params) && *params == '~') {
|
||||
url_params = params + 1;
|
||||
params = NULL;
|
||||
}
|
||||
|
||||
stripped = sofia_glue_get_url_from_contact(stripped, 0);
|
||||
|
||||
@@ -542,7 +547,9 @@ char *sofia_overcome_sip_uri_weakness(switch_core_session_t *session, const char
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (url_params && !uri_only) {
|
||||
new_uri = switch_core_session_sprintf(session, "%s;%s", new_uri, url_params);
|
||||
}
|
||||
|
||||
if (!zstr(invite_tel_params)) {
|
||||
char *lhs, *rhs = strchr(new_uri, '@');
|
||||
@@ -913,7 +920,6 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
|
||||
|
||||
switch_channel_set_variable(channel, "sip_outgoing_contact_uri", invite_contact);
|
||||
|
||||
|
||||
/*
|
||||
Does the "genius" who wanted SIP to be "text-based" so it was "easier to read" even use it now,
|
||||
or did he just suggest it to make our lives miserable?
|
||||
|
||||
@@ -154,6 +154,11 @@ switch_status_t sofia_presence_chat_send(switch_event_t *message_event)
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!from) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing From: header.\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!zstr(type)) {
|
||||
ct = type;
|
||||
}
|
||||
@@ -1032,7 +1037,7 @@ static void conference_data_event_handler(switch_event_t *event)
|
||||
sofia_profile_t *profile = NULL;
|
||||
|
||||
if (zstr(host)) {
|
||||
dup_domain = switch_core_get_variable_dup("domain");
|
||||
dup_domain = switch_core_get_domain(SWITCH_TRUE);
|
||||
host = dup_domain;
|
||||
}
|
||||
|
||||
@@ -3653,6 +3658,39 @@ void sofia_presence_handle_sip_i_subscribe(int status,
|
||||
|
||||
switch_snprintf(exp_delta_str, sizeof(exp_delta_str), "%ld", exp_delta);
|
||||
|
||||
if (!strcmp("as-feature-event", event)) {
|
||||
sip_authorization_t const *authorization = NULL;
|
||||
auth_res_t auth_res = AUTH_FORBIDDEN;
|
||||
char key[128] = "";
|
||||
switch_event_t *v_event = NULL;
|
||||
|
||||
|
||||
if (sip->sip_authorization) {
|
||||
authorization = sip->sip_authorization;
|
||||
} else if (sip->sip_proxy_authorization) {
|
||||
authorization = sip->sip_proxy_authorization;
|
||||
}
|
||||
|
||||
if (authorization) {
|
||||
char network_ip[80];
|
||||
sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), NULL);
|
||||
auth_res = sofia_reg_parse_auth(profile, authorization, sip, de,
|
||||
(char *) sip->sip_request->rq_method_name, key, sizeof(key), network_ip, &v_event, 0,
|
||||
REG_REGISTER, to_user, NULL, NULL, NULL);
|
||||
} else if ( sofia_reg_handle_register(nua, profile, nh, sip, de, REG_REGISTER, key, sizeof(key), &v_event, NULL, NULL, NULL)) {
|
||||
if (v_event) {
|
||||
switch_event_destroy(&v_event);
|
||||
}
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((auth_res != AUTH_OK && auth_res != AUTH_RENEWED)) {
|
||||
nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (to_user && strchr(to_user, '+')) {
|
||||
char *h;
|
||||
if ((proto = (d_user = strdup(to_user)))) {
|
||||
@@ -3986,7 +4024,24 @@ void sofia_presence_handle_sip_i_subscribe(int status,
|
||||
|
||||
switch_safe_free(sstr);
|
||||
|
||||
if (!strcasecmp(event, "message-summary")) {
|
||||
if (!strcasecmp(event, "as-feature-event")) {
|
||||
switch_event_t *event;
|
||||
char sip_cseq[40] = "";
|
||||
switch_snprintf(sip_cseq, sizeof(sip_cseq), "%d", sip->sip_cseq->cs_seq);
|
||||
switch_event_create(&event, SWITCH_EVENT_PHONE_FEATURE_SUBSCRIBE);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "user", from_user);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "host", from_host);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "contact", contact_str);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-id", call_id);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "expires", exp_delta_str);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "cseq", sip_cseq);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "profile_name", profile->name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hostname", mod_sofia_globals.hostname);
|
||||
if (sip->sip_payload) {
|
||||
switch_event_add_body(event, "%s", sip->sip_payload->pl_data);
|
||||
}
|
||||
switch_event_fire(&event);
|
||||
} else if (!strcasecmp(event, "message-summary")) {
|
||||
if ((sql = switch_mprintf("select proto,sip_user,'%q',sub_to_user,sub_to_host,event,contact,call_id,full_from,"
|
||||
"full_via,expires,user_agent,accept,profile_name,network_ip"
|
||||
" from sip_subscriptions where hostname='%q' and profile_name='%q' and "
|
||||
|
||||
@@ -1240,10 +1240,12 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
|
||||
to_host = to->a_url->url_host;
|
||||
}
|
||||
|
||||
if (!to_user)
|
||||
if (!to_user) {
|
||||
to_user = from_user;
|
||||
if (!to_host)
|
||||
}
|
||||
if (!to_host) {
|
||||
to_host = from_host;
|
||||
}
|
||||
|
||||
if (!to_user || !to_host) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can not do authorization without a complete header in REGISTER request from %s:%d\n",
|
||||
@@ -2891,7 +2893,7 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
|
||||
|
||||
skip_auth:
|
||||
if (first && (ret == AUTH_OK || ret == AUTH_RENEWED)) {
|
||||
if (!v_event) {
|
||||
if (v_event && !*v_event) {
|
||||
switch_event_create_plain(v_event, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
<param name="record-file-prefix" value="$${recordings_dir}/"/>
|
||||
</record>
|
||||
|
||||
<!-- input component params -->
|
||||
<input>
|
||||
<param name="default-recognizer" value="pocketsphinx"/>
|
||||
</input>
|
||||
|
||||
<!-- 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 -->
|
||||
@@ -42,4 +47,211 @@
|
||||
<dial-gateway uriprefix="sofia" dialprefix="" strip=""/>
|
||||
</dial-gateways>
|
||||
|
||||
<!-- IQ request aliases. Used mainly for testing purposes or for controlling a rayo call via the console -->
|
||||
<aliases>
|
||||
<alias name="ping" target="external"><![CDATA[<iq type="get"><ping xmlns="urn:xmpp:ping"/></iq>]]></alias>
|
||||
<alias name="answer" target="call"><![CDATA[<answer xmlns="urn:xmpp:rayo:1"/>]]></alias>
|
||||
<alias name="hangup" target="call"><![CDATA[<hangup xmlns="urn:xmpp:rayo:1"/>]]></alias>
|
||||
<alias name="join_mixer_duplex" target="call"><![CDATA[<join xmlns="urn:xmpp:rayo:1" mixer-name="test" direction="duplex"/>]]></alias>
|
||||
<alias name="join_mixer_send" target="call"><![CDATA[<join xmlns="urn:xmpp:rayo:1" mixer-name="test" direction="send"/>]]></alias>
|
||||
<alias name="join_mixer_recv" target="call"><![CDATA[<join xmlns="urn:xmpp:rayo:1" mixer-name="test" direction="recv"/>]]></alias>
|
||||
<alias name="unjoin_mixer" target="call"><![CDATA[<unjoin xmlns="urn:xmpp:rayo:1" mixer-name="test"/>]]></alias>
|
||||
<alias name="unjoin" target="call"><![CDATA[<unjoin xmlns="urn:xmpp:rayo:1"/>]]></alias>
|
||||
<alias name="stop" target="component"><![CDATA[<stop xmlns="urn:xmpp:rayo:ext:1"/>]]></alias>
|
||||
<alias name="output_bad" target="call"><![CDATA[<output xmlns="urn:xmpp:rayo:output:1" repeat-time="100"></output>]]></alias>
|
||||
<alias name="pause" target="output"><![CDATA[<pause xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
|
||||
<alias name="resume" target="output"><![CDATA[<resume xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
|
||||
<alias name="speed-up" target="output"><![CDATA[<speed-up xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
|
||||
<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="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>
|
||||
<alias name="prompt_barge" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-times="5">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="prompt_no_barge" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="false">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-times="5">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="prompt_long" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-times="100">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="prompt_multi_digit" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-times="100">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><item repeat="1-4"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></item></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="prompt_terminator" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-times="100">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000" terminator="#">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><item repeat="1-4"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></item></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="prompt_input_bad" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-times="100">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtf" initial-timeout="5000" inter-digit-timeout="3000" terminator="#">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><item repeat="1-4"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></item></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="prompt_output_bad" target="call">
|
||||
<![CDATA[
|
||||
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
|
||||
<output xmlns="urn:xmpp:rayo:output:1" repeat-time="100">
|
||||
<document content-type="application/ssml+xml">
|
||||
<![CDATA[<speak><p>Please press a digit.</p></speak>]]]]><![CDATA[>
|
||||
</document>
|
||||
</output>
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000" terminator="#">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><item repeat="1-4"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></item></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
</prompt>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="input" target="call">
|
||||
<![CDATA[
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="dtmf" initial-timeout="5000" inter-digit-timeout="3000">
|
||||
<grammar content-type="application/srgs+xml">
|
||||
<![CDATA[<grammar mode="dtmf"><rule id="digit" scope="public"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></rule></grammar>]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="input_voice_yesno_unimrcp" target="call">
|
||||
<![CDATA[
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="voice" recognizer="unimrcp">
|
||||
<grammar content-type="application/srgs+xml>
|
||||
<![CDATA[
|
||||
<grammar xmlns="http://www.w3.org/2001/06/grammar"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.w3.org/2001/06/grammar http://www.w3.org/TR/speech-grammar/grammar.xsd"
|
||||
xml:lang="en-US" version="1.0">
|
||||
<rule id="yesno"><one-of><item>yes</item><item>no</item></one-of></rule></grammar>
|
||||
]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
]]>
|
||||
</alias>
|
||||
<alias name="input_voice_yesno_unimrcp_timeout" target="call">
|
||||
<![CDATA[
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="voice" recognizer="unimrcp" max-silence="5000" initial-timeout="5000">
|
||||
<grammar content-type="application/srgs+xml>
|
||||
<![CDATA[
|
||||
<grammar xmlns="http://www.w3.org/2001/06/grammar"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.w3.org/2001/06/grammar http://www.w3.org/TR/speech-grammar/grammar.xsd"
|
||||
xml:lang="en-US" version="1.0">
|
||||
<rule id="yesno"><one-of><item>yes</item><item>no</item></one-of></rule></grammar>
|
||||
]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
]]>
|
||||
</alias>
|
||||
|
||||
<alias name="input_voice_yesno_pocketsphinx" target="call">
|
||||
<![CDATA[
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="voice" recognizer="pocketsphinx" max-silence="5000" initial-timeout="5000">
|
||||
<grammar content-type="application/srgs+xml>
|
||||
<![CDATA[
|
||||
<grammar xmlns="http://www.w3.org/2001/06/grammar"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.w3.org/2001/06/grammar http://www.w3.org/TR/speech-grammar/grammar.xsd"
|
||||
xml:lang="en-US" version="1.0">
|
||||
<rule id="yesno"><one-of><item>yes</item><item>no</item></one-of></rule></grammar>
|
||||
]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
]]>
|
||||
</alias>
|
||||
|
||||
<alias name="input_voice_yesno_default" target="call">
|
||||
<![CDATA[
|
||||
<input xmlns="urn:xmpp:rayo:input:1" mode="voice" max-silence="5000" initial-timeout="5000">
|
||||
<grammar content-type="application/srgs+xml>
|
||||
<![CDATA[
|
||||
<grammar xmlns="http://www.w3.org/2001/06/grammar"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.w3.org/2001/06/grammar http://www.w3.org/TR/speech-grammar/grammar.xsd"
|
||||
xml:lang="en-US" version="1.0">
|
||||
<rule id="yesno"><one-of><item>yes</item><item>no</item></one-of></rule></grammar>
|
||||
]]]]><![CDATA[>
|
||||
</grammar>
|
||||
</input>
|
||||
]]>
|
||||
</alias>
|
||||
|
||||
</aliases>
|
||||
|
||||
</configuration>
|
||||
|
||||
@@ -216,6 +216,17 @@ double iks_find_decimal_attrib(iks *xml, const char *attrib)
|
||||
return atof(iks_find_attrib_soft(xml, attrib));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attribute character value of node
|
||||
* @param xml the XML node to search
|
||||
* @param attrib the Attribute name
|
||||
* @return the attribute value
|
||||
*/
|
||||
char iks_find_char_attrib(iks *xml, const char *attrib)
|
||||
{
|
||||
return iks_find_attrib_soft(xml, attrib)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert iksemel XML node type to string
|
||||
* @param type the XML node type
|
||||
@@ -392,6 +403,54 @@ int iks_attrib_is_decimal_between_zero_and_one(const char *value)
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate dtmf digit
|
||||
* @param value
|
||||
* @return SWITCH_TRUE if 0-9,a,b,c,d,A,B,C,D,*,#
|
||||
*/
|
||||
int iks_attrib_is_dtmf_digit(const char *value)
|
||||
{
|
||||
if (value && *value && strlen(value) == 1) {
|
||||
switch (*value) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case 'A':
|
||||
case 'a':
|
||||
case 'B':
|
||||
case 'b':
|
||||
case 'C':
|
||||
case 'c':
|
||||
case 'D':
|
||||
case 'd':
|
||||
case '*':
|
||||
case '#':
|
||||
return SWITCH_TRUE;
|
||||
}
|
||||
}
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fn to evaluate attribute
|
||||
* @param attrib to evaluate
|
||||
* @return true if not set or is valid
|
||||
*/
|
||||
int validate_optional_attrib(iks_attrib_validation_function fn, const char *attrib)
|
||||
{
|
||||
if (!attrib || !*attrib) {
|
||||
return SWITCH_TRUE;
|
||||
}
|
||||
return fn(attrib);
|
||||
}
|
||||
|
||||
#define IKS_SHA256_HEX_DIGEST_LENGTH ((SHA256_DIGEST_LENGTH * 2) + 1)
|
||||
|
||||
/**
|
||||
|
||||
@@ -63,6 +63,7 @@ extern const char *iks_find_attrib_soft(iks *xml, const char *attrib);
|
||||
extern const char *iks_find_attrib_default(iks *xml, const char *attrib, const char *def);
|
||||
extern int iks_find_bool_attrib(iks *xml, const char *attrib);
|
||||
extern int iks_find_int_attrib(iks *xml, const char *attrib);
|
||||
extern char iks_find_char_attrib(iks *xml, const char *attrib);
|
||||
extern double iks_find_decimal_attrib(iks *xml, const char *attrib);
|
||||
extern const char *iks_node_type_to_string(int type);
|
||||
extern const char *iks_net_error_to_string(int err);
|
||||
@@ -73,9 +74,12 @@ extern char *iks_server_dialback_key(const char *secret, const char *receiving_s
|
||||
/** A function to validate attribute value */
|
||||
typedef int (*iks_attrib_validation_function)(const char *);
|
||||
|
||||
extern int validate_optional_attrib(iks_attrib_validation_function fn, const char *attrib);
|
||||
|
||||
#define ELEMENT_DECL(name) extern int VALIDATE_##name(iks *node);
|
||||
#define ELEMENT(name) int VALIDATE_##name(iks *node) { int result = 1; if (!node) return 0;
|
||||
#define ATTRIB(name, def, rule) result &= iks_attrib_is_##rule(iks_find_attrib_default(node, #name, #def));
|
||||
#define OPTIONAL_ATTRIB(name, def, rule) result &= validate_optional_attrib(iks_attrib_is_##rule, iks_find_attrib_default(node, #name, #def));
|
||||
#define STRING_ATTRIB(name, def, rule) result &= value_matches(iks_find_attrib_default(node, #name, #def), rule);
|
||||
#define ELEMENT_END return result; }
|
||||
|
||||
@@ -87,6 +91,7 @@ extern int iks_attrib_is_positive(const char *value);
|
||||
extern int iks_attrib_is_positive_or_neg_one(const char *value);
|
||||
extern int iks_attrib_is_any(const char *value);
|
||||
extern int iks_attrib_is_decimal_between_zero_and_one(const char *value);
|
||||
extern int iks_attrib_is_dtmf_digit(const char *value);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -239,6 +239,12 @@ static void rayo_console_client_send(struct rayo_actor *client, struct rayo_mess
|
||||
|
||||
static void on_client_presence(struct rayo_client *rclient, iks *node);
|
||||
|
||||
typedef switch_bool_t (* rayo_actor_match_fn)(struct rayo_actor *);
|
||||
|
||||
static switch_bool_t is_call_actor(struct rayo_actor *actor);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param msg to check
|
||||
* @return true if message was sent by admin client (console)
|
||||
@@ -712,6 +718,9 @@ struct rayo_actor *rayo_actor_locate(const char *jid, const char *file, int line
|
||||
{
|
||||
struct rayo_actor *actor = NULL;
|
||||
switch_mutex_lock(globals.actors_mutex);
|
||||
if (!strncmp("xmpp:", jid, 5)) {
|
||||
jid = jid + 5;
|
||||
}
|
||||
actor = (struct rayo_actor *)switch_core_hash_find(globals.actors, jid);
|
||||
if (actor) {
|
||||
if (!actor->destroy) {
|
||||
@@ -818,16 +827,33 @@ int rayo_actor_seq_next(struct rayo_actor *actor)
|
||||
return seq;
|
||||
}
|
||||
|
||||
#define RAYO_CALL_LOCATE(call_uuid) rayo_call_locate(call_uuid, __FILE__, __LINE__)
|
||||
#define RAYO_CALL_LOCATE(call_uri) rayo_call_locate(call_uri, __FILE__, __LINE__)
|
||||
/**
|
||||
* Get exclusive access to Rayo call data. Use to access call data outside channel thread.
|
||||
* Get access to Rayo call data. Use to access call data outside channel thread.
|
||||
* @param call_uri the Rayo XMPP URI
|
||||
* @return the call or NULL.
|
||||
*/
|
||||
static struct rayo_call *rayo_call_locate(const char *call_uri, const char *file, int line)
|
||||
{
|
||||
struct rayo_actor *actor = rayo_actor_locate(call_uri, file, line);
|
||||
if (actor && is_call_actor(actor)) {
|
||||
return RAYO_CALL(actor);
|
||||
} else if (actor) {
|
||||
RAYO_UNLOCK(actor);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define RAYO_CALL_LOCATE_BY_ID(call_uuid) rayo_call_locate_by_id(call_uuid, __FILE__, __LINE__)
|
||||
/**
|
||||
* Get access to Rayo call data. Use to access call data outside channel thread.
|
||||
* @param call_uuid the FreeSWITCH call UUID
|
||||
* @return the call or NULL.
|
||||
*/
|
||||
static struct rayo_call *rayo_call_locate(const char *call_uuid, const char *file, int line)
|
||||
static struct rayo_call *rayo_call_locate_by_id(const char *call_uuid, const char *file, int line)
|
||||
{
|
||||
struct rayo_actor *actor = rayo_actor_locate_by_id(call_uuid, file, line);
|
||||
if (actor && !strcmp(RAT_CALL, actor->type)) {
|
||||
if (actor && is_call_actor(actor)) {
|
||||
return RAYO_CALL(actor);
|
||||
} else if (actor) {
|
||||
RAYO_UNLOCK(actor);
|
||||
@@ -1686,18 +1712,18 @@ static iks *on_rayo_hangup(struct rayo_actor *call, struct rayo_message *msg, vo
|
||||
* @param call the call that joins
|
||||
* @param session the session
|
||||
* @param node the join request
|
||||
* @param call_id to join
|
||||
* @param call_uri to join
|
||||
* @param media mode (direct/bridge)
|
||||
* @return the response
|
||||
*/
|
||||
static iks *join_call(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *call_id, const char *media)
|
||||
static iks *join_call(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *call_uri, const char *media)
|
||||
{
|
||||
iks *response = NULL;
|
||||
/* take call out of media path if media = "direct" */
|
||||
const char *bypass = !strcmp("direct", media) ? "true" : "false";
|
||||
|
||||
/* check if joining to rayo call */
|
||||
struct rayo_call *b_call = RAYO_CALL_LOCATE(call_id);
|
||||
struct rayo_call *b_call = RAYO_CALL_LOCATE(call_uri);
|
||||
if (!b_call) {
|
||||
/* not a rayo call */
|
||||
response = iks_new_error_detailed(node, STANZA_ERROR_SERVICE_UNAVAILABLE, "b-leg is not a rayo call");
|
||||
@@ -1706,18 +1732,17 @@ static iks *join_call(struct rayo_call *call, switch_core_session_t *session, ik
|
||||
response = iks_new_error_detailed(node, STANZA_ERROR_CONFLICT, "multiple joined calls not supported");
|
||||
RAYO_UNLOCK(b_call);
|
||||
} else {
|
||||
RAYO_UNLOCK(b_call);
|
||||
|
||||
/* bridge this call to call-uri */
|
||||
switch_channel_set_variable(switch_core_session_get_channel(session), "bypass_media", bypass);
|
||||
if (switch_false(bypass)) {
|
||||
switch_channel_pre_answer(switch_core_session_get_channel(session));
|
||||
}
|
||||
if (switch_ivr_uuid_bridge(rayo_call_get_uuid(call), call_id) == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_ivr_uuid_bridge(rayo_call_get_uuid(call), rayo_call_get_uuid(b_call)) == SWITCH_STATUS_SUCCESS) {
|
||||
response = iks_new_iq_result(node);
|
||||
} else {
|
||||
response = iks_new_error_detailed(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to bridge call");
|
||||
}
|
||||
RAYO_UNLOCK(b_call);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
@@ -1791,7 +1816,7 @@ static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void
|
||||
iks *join = iks_find(node, "join");
|
||||
const char *join_id;
|
||||
const char *mixer_name;
|
||||
const char *call_id;
|
||||
const char *call_uri;
|
||||
|
||||
/* validate input attributes */
|
||||
if (!VALIDATE_RAYO_JOIN(join)) {
|
||||
@@ -1800,22 +1825,22 @@ static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void
|
||||
goto done;
|
||||
}
|
||||
mixer_name = iks_find_attrib(join, "mixer-name");
|
||||
call_id = iks_find_attrib(join, "call-uri");
|
||||
call_uri = iks_find_attrib(join, "call-uri");
|
||||
|
||||
if (!zstr(mixer_name)) {
|
||||
join_id = mixer_name;
|
||||
} else {
|
||||
join_id = call_id;
|
||||
join_id = call_uri;
|
||||
}
|
||||
|
||||
/* can't join both mixer and call */
|
||||
if (!zstr(mixer_name) && !zstr(call_id)) {
|
||||
if (!zstr(mixer_name) && !zstr(call_uri)) {
|
||||
response = iks_new_error_detailed(node, STANZA_ERROR_BAD_REQUEST, "mixer-name and call-uri are mutually exclusive");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* need to join *something* */
|
||||
if (zstr(mixer_name) && zstr(call_id)) {
|
||||
if (zstr(mixer_name) && zstr(call_uri)) {
|
||||
response = iks_new_error_detailed(node, STANZA_ERROR_BAD_REQUEST, "mixer-name or call-uri is required");
|
||||
goto done;
|
||||
}
|
||||
@@ -1832,7 +1857,7 @@ static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void
|
||||
response = join_mixer(RAYO_CALL(call), session, node, mixer_name, iks_find_attrib(join, "direction"));
|
||||
} else {
|
||||
/* bridge calls */
|
||||
response = join_call(RAYO_CALL(call), session, node, call_id, iks_find_attrib(join, "media"));
|
||||
response = join_call(RAYO_CALL(call), session, node, call_uri, iks_find_attrib(join, "media"));
|
||||
}
|
||||
|
||||
done:
|
||||
@@ -1844,21 +1869,22 @@ done:
|
||||
* @param call the call that unjoined
|
||||
* @param session the session
|
||||
* @param node the unjoin request
|
||||
* @param call_id the b-leg uuid
|
||||
* @param call_uri the b-leg xmpp URI
|
||||
* @return the response
|
||||
*/
|
||||
static iks *unjoin_call(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *call_id)
|
||||
static iks *unjoin_call(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *call_uri)
|
||||
{
|
||||
iks *response = NULL;
|
||||
const char *bleg = switch_channel_get_variable(switch_core_session_get_channel(session), SWITCH_BRIDGE_UUID_VARIABLE);
|
||||
const char *bleg_uuid = switch_channel_get_variable(switch_core_session_get_channel(session), SWITCH_BRIDGE_UUID_VARIABLE);
|
||||
const char *bleg_uri = switch_core_session_sprintf(session, "xmpp:%s@%s", bleg_uuid ? bleg_uuid : "", RAYO_JID(globals.server));
|
||||
|
||||
/* bleg must match call_id */
|
||||
if (!zstr(bleg) && !strcmp(bleg, call_id)) {
|
||||
/* bleg must match call_uri */
|
||||
if (!zstr(bleg_uri) && !strcmp(bleg_uri, call_uri)) {
|
||||
/* unbridge call */
|
||||
response = iks_new_iq_result(node);
|
||||
switch_ivr_park_session(session);
|
||||
} else {
|
||||
/* not bridged or wrong b-leg UUID */
|
||||
/* not bridged or wrong b-leg URI */
|
||||
response = iks_new_error(node, STANZA_ERROR_SERVICE_UNAVAILABLE);
|
||||
}
|
||||
|
||||
@@ -1913,16 +1939,16 @@ static iks *on_rayo_unjoin(struct rayo_actor *call, struct rayo_message *msg, vo
|
||||
switch_core_session_t *session = (switch_core_session_t *)session_data;
|
||||
iks *response = NULL;
|
||||
iks *unjoin = iks_find(node, "unjoin");
|
||||
const char *call_id = iks_find_attrib(unjoin, "call-uri");
|
||||
const char *call_uri = iks_find_attrib(unjoin, "call-uri");
|
||||
const char *mixer_name = iks_find_attrib(unjoin, "mixer-name");
|
||||
|
||||
if (!zstr(call_id) && !zstr(mixer_name)) {
|
||||
if (!zstr(call_uri) && !zstr(mixer_name)) {
|
||||
response = iks_new_error(node, STANZA_ERROR_BAD_REQUEST);
|
||||
} else if (!RAYO_CALL(call)->joined) {
|
||||
/* not joined to anything */
|
||||
response = iks_new_error(node, STANZA_ERROR_SERVICE_UNAVAILABLE);
|
||||
} else if (!zstr(call_id)) {
|
||||
response = unjoin_call(RAYO_CALL(call), session, node, call_id);
|
||||
} else if (!zstr(call_uri)) {
|
||||
response = unjoin_call(RAYO_CALL(call), session, node, call_uri);
|
||||
} else if (!zstr(mixer_name)) {
|
||||
response = unjoin_mixer(RAYO_CALL(call), session, node, mixer_name);
|
||||
} else {
|
||||
@@ -2037,20 +2063,20 @@ static void *SWITCH_THREAD_FUNC rayo_dial_thread(switch_thread_t *thread, void *
|
||||
|
||||
if (join) {
|
||||
/* check join args */
|
||||
const char *call_id = iks_find_attrib(join, "call-uri");
|
||||
const char *call_uri = iks_find_attrib(join, "call-uri");
|
||||
const char *mixer_name = iks_find_attrib(join, "mixer-name");
|
||||
|
||||
if (!zstr(call_id) && !zstr(mixer_name)) {
|
||||
if (!zstr(call_uri) && !zstr(mixer_name)) {
|
||||
/* can't join both */
|
||||
response = iks_new_error(iq, STANZA_ERROR_BAD_REQUEST);
|
||||
goto done;
|
||||
} else if (zstr(call_id) && zstr(mixer_name)) {
|
||||
} else if (zstr(call_uri) && zstr(mixer_name)) {
|
||||
/* nobody to join to? */
|
||||
response = iks_new_error(iq, STANZA_ERROR_BAD_REQUEST);
|
||||
goto done;
|
||||
} else if (!zstr(call_id)) {
|
||||
} else if (!zstr(call_uri)) {
|
||||
/* bridge */
|
||||
struct rayo_call *b_call = RAYO_CALL_LOCATE(call_id);
|
||||
struct rayo_call *b_call = RAYO_CALL_LOCATE(call_uri);
|
||||
/* is b-leg available? */
|
||||
if (!b_call) {
|
||||
response = iks_new_error_detailed(iq, STANZA_ERROR_SERVICE_UNAVAILABLE, "b-leg not found");
|
||||
@@ -2060,8 +2086,8 @@ static void *SWITCH_THREAD_FUNC rayo_dial_thread(switch_thread_t *thread, void *
|
||||
RAYO_UNLOCK(b_call);
|
||||
goto done;
|
||||
}
|
||||
stream.write_function(&stream, "%s%s &rayo(bridge %s)", gateway->dial_prefix, dial_to_stripped, rayo_call_get_uuid(b_call));
|
||||
RAYO_UNLOCK(b_call);
|
||||
stream.write_function(&stream, "%s%s &rayo(bridge %s)", gateway->dial_prefix, dial_to_stripped, call_id);
|
||||
} else {
|
||||
/* conference */
|
||||
stream.write_function(&stream, "%s%s &rayo(conference %s@%s)", gateway->dial_prefix, dial_to_stripped, mixer_name, globals.mixer_conf_profile);
|
||||
@@ -2393,7 +2419,7 @@ static void on_mixer_delete_member_event(struct rayo_mixer *mixer, switch_event_
|
||||
switch_core_hash_delete(mixer->members, uuid);
|
||||
|
||||
/* flag call as available to join another mixer */
|
||||
call = RAYO_CALL_LOCATE(uuid);
|
||||
call = RAYO_CALL_LOCATE_BY_ID(uuid);
|
||||
if (call) {
|
||||
call->joined = 0;
|
||||
call->joined_id = NULL;
|
||||
@@ -2409,7 +2435,7 @@ static void on_mixer_delete_member_event(struct rayo_mixer *mixer, switch_event_
|
||||
/* broadcast member unjoined event to subscribers */
|
||||
delete_member_event = iks_new_presence("unjoined", RAYO_NS, RAYO_JID(mixer), "");
|
||||
x = iks_find(delete_member_event, "unjoined");
|
||||
iks_insert_attrib(x, "call-uri", uuid);
|
||||
iks_insert_attrib_printf(x, "call-uri", "xmpp:%s@%s", uuid, RAYO_JID(globals.server));
|
||||
broadcast_mixer_event(mixer, delete_member_event);
|
||||
iks_delete(delete_member_event);
|
||||
|
||||
@@ -2445,7 +2471,7 @@ static void on_mixer_add_member_event(struct rayo_mixer *mixer, switch_event_t *
|
||||
{
|
||||
iks *add_member_event = NULL, *x;
|
||||
const char *uuid = switch_event_get_header(event, "Unique-ID");
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE(uuid);
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(uuid);
|
||||
|
||||
if (!mixer) {
|
||||
/* new mixer */
|
||||
@@ -2487,7 +2513,7 @@ static void on_mixer_add_member_event(struct rayo_mixer *mixer, switch_event_t *
|
||||
/* broadcast member joined event to subscribers */
|
||||
add_member_event = iks_new_presence("joined", RAYO_NS, RAYO_JID(mixer), "");
|
||||
x = iks_find(add_member_event, "joined");
|
||||
iks_insert_attrib(x, "call-uri", uuid);
|
||||
iks_insert_attrib_printf(x, "call-uri", "xmpp:%s@%s", uuid, RAYO_JID(globals.server));
|
||||
broadcast_mixer_event(mixer, add_member_event);
|
||||
iks_delete(add_member_event);
|
||||
}
|
||||
@@ -2533,7 +2559,7 @@ static void on_call_originate_event(struct rayo_client *rclient, switch_event_t
|
||||
{
|
||||
switch_core_session_t *session = NULL;
|
||||
const char *uuid = switch_event_get_header(event, "Unique-ID");
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE(uuid);
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(uuid);
|
||||
|
||||
if (call && (session = switch_core_session_locate(uuid))) {
|
||||
iks *response, *ref;
|
||||
@@ -2550,11 +2576,7 @@ static void on_call_originate_event(struct rayo_client *rclient, switch_event_t
|
||||
ref = iks_insert(response, "ref");
|
||||
iks_insert_attrib(ref, "xmlns", RAYO_NS);
|
||||
|
||||
#ifdef RAYO_UUID_IN_REF_URI
|
||||
iks_insert_attrib(ref, "uri", uuid);
|
||||
#else
|
||||
iks_insert_attrib_printf(ref, "uri", "xmpp:%s", RAYO_JID(call));
|
||||
#endif
|
||||
RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), response);
|
||||
call->dial_id = NULL;
|
||||
}
|
||||
@@ -2567,7 +2589,7 @@ static void on_call_originate_event(struct rayo_client *rclient, switch_event_t
|
||||
*/
|
||||
static void on_call_end_event(switch_event_t *event)
|
||||
{
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE(switch_event_get_header(event, "Unique-ID"));
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
|
||||
|
||||
if (call) {
|
||||
#if 0
|
||||
@@ -2591,7 +2613,7 @@ static void on_call_end_event(switch_event_t *event)
|
||||
*/
|
||||
static void on_call_answer_event(struct rayo_client *rclient, switch_event_t *event)
|
||||
{
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE(switch_event_get_header(event, "Unique-ID"));
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
|
||||
if (call) {
|
||||
iks *revent = iks_new_presence("answered", RAYO_NS,
|
||||
switch_event_get_header(event, "variable_rayo_call_jid"),
|
||||
@@ -2610,7 +2632,7 @@ static void on_call_ringing_event(struct rayo_client *rclient, switch_event_t *e
|
||||
{
|
||||
const char *call_direction = switch_event_get_header(event, "Call-Direction");
|
||||
if (call_direction && !strcmp(call_direction, "outbound")) {
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE(switch_event_get_header(event, "Unique-ID"));
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
|
||||
if (call) {
|
||||
switch_mutex_lock(RAYO_ACTOR(call)->mutex);
|
||||
if (!call->ringing_sent) {
|
||||
@@ -2635,7 +2657,7 @@ static void on_call_bridge_event(struct rayo_client *rclient, switch_event_t *ev
|
||||
{
|
||||
const char *a_uuid = switch_event_get_header(event, "Unique-ID");
|
||||
const char *b_uuid = switch_event_get_header(event, "Bridge-B-Unique-ID");
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE(a_uuid);
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(a_uuid);
|
||||
struct rayo_call *b_call;
|
||||
|
||||
if (call) {
|
||||
@@ -2644,7 +2666,7 @@ static void on_call_bridge_event(struct rayo_client *rclient, switch_event_t *ev
|
||||
switch_event_get_header(event, "variable_rayo_call_jid"),
|
||||
switch_event_get_header(event, "variable_rayo_dcp_jid"));
|
||||
iks *joined = iks_find(revent, "joined");
|
||||
iks_insert_attrib(joined, "call-uri", b_uuid);
|
||||
iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server));
|
||||
|
||||
call->joined = JOINED_CALL;
|
||||
call->joined_id = switch_core_strdup(RAYO_POOL(call), b_uuid);
|
||||
@@ -2652,11 +2674,11 @@ static void on_call_bridge_event(struct rayo_client *rclient, switch_event_t *ev
|
||||
RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
|
||||
|
||||
/* send B-leg event */
|
||||
b_call = RAYO_CALL_LOCATE(b_uuid);
|
||||
b_call = RAYO_CALL_LOCATE_BY_ID(b_uuid);
|
||||
if (b_call) {
|
||||
revent = iks_new_presence("joined", RAYO_NS, RAYO_JID(b_call), rayo_call_get_dcp_jid(b_call));
|
||||
joined = iks_find(revent, "joined");
|
||||
iks_insert_attrib(joined, "call-uri", a_uuid);
|
||||
iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", a_uuid, RAYO_JID(globals.server));
|
||||
|
||||
b_call->joined = JOINED_CALL;
|
||||
b_call->joined_id = switch_core_strdup(RAYO_POOL(b_call), a_uuid);
|
||||
@@ -2677,7 +2699,7 @@ static void on_call_unbridge_event(struct rayo_client *rclient, switch_event_t *
|
||||
{
|
||||
const char *a_uuid = switch_event_get_header(event, "Unique-ID");
|
||||
const char *b_uuid = switch_event_get_header(event, "Bridge-B-Unique-ID");
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE(a_uuid);
|
||||
struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(a_uuid);
|
||||
struct rayo_call *b_call;
|
||||
|
||||
if (call) {
|
||||
@@ -2686,18 +2708,18 @@ static void on_call_unbridge_event(struct rayo_client *rclient, switch_event_t *
|
||||
switch_event_get_header(event, "variable_rayo_call_jid"),
|
||||
switch_event_get_header(event, "variable_rayo_dcp_jid"));
|
||||
iks *joined = iks_find(revent, "unjoined");
|
||||
iks_insert_attrib(joined, "call-uri", b_uuid);
|
||||
iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server));
|
||||
RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
|
||||
|
||||
call->joined = 0;
|
||||
call->joined_id = NULL;
|
||||
|
||||
/* send B-leg event */
|
||||
b_call = RAYO_CALL_LOCATE(b_uuid);
|
||||
b_call = RAYO_CALL_LOCATE_BY_ID(b_uuid);
|
||||
if (b_call) {
|
||||
revent = iks_new_presence("unjoined", RAYO_NS, RAYO_JID(b_call), rayo_call_get_dcp_jid(b_call));
|
||||
joined = iks_find(revent, "unjoined");
|
||||
iks_insert_attrib(joined, "call-uri", a_uuid);
|
||||
iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", a_uuid, RAYO_JID(globals.server));
|
||||
RAYO_SEND_MESSAGE(b_call, rayo_call_get_dcp_jid(b_call), revent);
|
||||
|
||||
b_call->joined = 0;
|
||||
@@ -3077,6 +3099,21 @@ static void on_xmpp_stream_destroy(struct xmpp_stream *stream)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an alias to an API command
|
||||
* @param alias_name
|
||||
* @param alias_target
|
||||
* @param alias_cmd
|
||||
*/
|
||||
static void rayo_add_cmd_alias(const char *alias_name, const char *alias_target, const char *alias_cmd)
|
||||
{
|
||||
if (zstr(alias_target)) {
|
||||
alias_target = "all";
|
||||
}
|
||||
switch_console_set_complete(switch_core_sprintf(globals.pool, "add rayo %s ::rayo::list_%s", alias_name, alias_target));
|
||||
switch_core_hash_insert(globals.cmd_aliases, alias_name, alias_cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process module XML configuration
|
||||
* @param pool memory pool to allocate from
|
||||
@@ -3262,6 +3299,22 @@ static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_
|
||||
}
|
||||
}
|
||||
|
||||
/* get aliases */
|
||||
{
|
||||
switch_xml_t aliases = switch_xml_child(cfg, "aliases");
|
||||
if (aliases) {
|
||||
switch_xml_t alias;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting configured aliases\n");
|
||||
for (alias = switch_xml_child(aliases, "alias"); alias; alias = alias->next) {
|
||||
const char *alias_name = switch_xml_attr_soft(alias, "name");
|
||||
const char *alias_target = switch_xml_attr_soft(alias, "target");
|
||||
if (!zstr(alias_name) && !zstr(alias->txt)) {
|
||||
rayo_add_cmd_alias(alias_name, alias_target, alias->txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
switch_xml_free(xml);
|
||||
|
||||
@@ -3360,12 +3413,6 @@ static void send_console_command(struct rayo_client *client, const char *to, con
|
||||
iks *command = NULL;
|
||||
iksparser *p = iks_dom_new(&command);
|
||||
|
||||
/* check if aliased */
|
||||
const char *alias = switch_core_hash_find(globals.cmd_aliases, command_str);
|
||||
if (!zstr(alias)) {
|
||||
command_str = alias;
|
||||
}
|
||||
|
||||
if (iks_parse(p, command_str, 0, 1) == IKS_OK && command) {
|
||||
char *str;
|
||||
iks *iq = NULL;
|
||||
@@ -3404,14 +3451,15 @@ static void send_console_command(struct rayo_client *client, const char *to, con
|
||||
/**
|
||||
* Send command to rayo actor
|
||||
*/
|
||||
static int command_api(const char *cmd, switch_stream_handle_t *stream)
|
||||
static int command_api(char *cmd, switch_stream_handle_t *stream)
|
||||
{
|
||||
char *cmd_dup = strdup(cmd);
|
||||
char *argv[2] = { 0 };
|
||||
int argc = switch_separate_string(cmd_dup, ' ', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
|
||||
if (argc != 2) {
|
||||
free(cmd_dup);
|
||||
if (!zstr(cmd)) {
|
||||
int argc = switch_separate_string(cmd, ' ', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
if (argc != 2) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3419,7 +3467,22 @@ static int command_api(const char *cmd, switch_stream_handle_t *stream)
|
||||
send_console_command(globals.console, argv[0], argv[1]);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
|
||||
free(cmd_dup);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send command to rayo actor
|
||||
*/
|
||||
static int alias_api(const char *cmd, char *jid, switch_stream_handle_t *stream)
|
||||
{
|
||||
if (zstr(cmd) || zstr(jid)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* send command */
|
||||
send_console_command(globals.console, jid, cmd);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -3443,14 +3506,15 @@ static void send_console_message(struct rayo_client *client, const char *to, con
|
||||
/**
|
||||
* Send message to rayo actor
|
||||
*/
|
||||
static int message_api(const char *msg, switch_stream_handle_t *stream)
|
||||
static int message_api(char *cmd, switch_stream_handle_t *stream)
|
||||
{
|
||||
char *msg_dup = strdup(msg);
|
||||
char *argv[2] = { 0 };
|
||||
int argc = switch_separate_string(msg_dup, ' ', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
|
||||
if (argc != 2) {
|
||||
free(msg_dup);
|
||||
if (!zstr(cmd)) {
|
||||
int argc = switch_separate_string(cmd, ' ', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
if (argc != 2) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3458,7 +3522,6 @@ static int message_api(const char *msg, switch_stream_handle_t *stream)
|
||||
send_console_message(globals.console, argv[0], argv[1]);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
|
||||
free(msg_dup);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -3484,151 +3547,238 @@ static void send_console_presence(struct rayo_client *client, const char *to, in
|
||||
/**
|
||||
* Send console presence
|
||||
*/
|
||||
static int presence_api(const char *cmd, switch_stream_handle_t *stream)
|
||||
static int presence_api(char *cmd, switch_stream_handle_t *stream)
|
||||
{
|
||||
char *cmd_dup = strdup(cmd);
|
||||
char *argv[2] = { 0 };
|
||||
int argc = switch_separate_string(cmd_dup, ' ', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
int is_online = 0;
|
||||
|
||||
if (argc != 2) {
|
||||
free(cmd_dup);
|
||||
char *argv[2] = { 0 };
|
||||
if (!zstr(cmd)) {
|
||||
int argc = switch_separate_string(cmd, ' ', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
if (argc != 2) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp("online", argv[1])) {
|
||||
is_online = 1;
|
||||
} else if (strcmp("offline", argv[1])) {
|
||||
free(cmd_dup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* send presence */
|
||||
send_console_presence(globals.console, argv[0], is_online);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
free(cmd_dup);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define RAYO_API_SYNTAX "status | (cmd <jid> <command>) | (msg <jid> <message text>) | (presence <jid> <online|offline>)"
|
||||
#define RAYO_API_SYNTAX "status | (<alias> <jid>) | (cmd <jid> <command>) | (msg <jid> <message text>) | (presence <jid> <online|offline>)"
|
||||
SWITCH_STANDARD_API(rayo_api)
|
||||
{
|
||||
const char *alias;
|
||||
char *cmd_dup = strdup(cmd);
|
||||
char *argv[2] = { 0 };
|
||||
int success = 0;
|
||||
if (!strncmp("status", cmd, 6)) {
|
||||
success = dump_api(cmd + 6, stream);
|
||||
} else if (!strncmp("cmd", cmd, 3)) {
|
||||
success = command_api(cmd + 3, stream);
|
||||
} else if (!strncmp("msg", cmd, 3)) {
|
||||
success = message_api(cmd + 3, stream);
|
||||
} else if (!strncmp("presence", cmd, 8)) {
|
||||
success = presence_api(cmd + 8, stream);
|
||||
|
||||
switch_separate_string(cmd_dup, ' ', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
|
||||
/* check if a command alias */
|
||||
alias = switch_core_hash_find(globals.cmd_aliases, argv[0]);
|
||||
|
||||
if (!zstr(alias)) {
|
||||
success = alias_api(alias, argv[1], stream);
|
||||
} else if (!strcmp("cmd", argv[0])) {
|
||||
success = command_api(argv[1], stream);
|
||||
} else if (!strcmp("status", argv[0])) {
|
||||
success = dump_api(argv[1], stream);
|
||||
} else if (!strcmp("msg", argv[0])) {
|
||||
success = message_api(argv[1], stream);
|
||||
} else if (!strcmp("presence", argv[0])) {
|
||||
success = presence_api(argv[1], stream);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
stream->write_function(stream, "-ERR: USAGE %s\n", RAYO_API_SYNTAX);
|
||||
}
|
||||
|
||||
free(cmd_dup);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Console auto-completion for actors given validation function
|
||||
*/
|
||||
static switch_status_t list_actors(const char *line, const char *cursor, switch_console_callback_match_t **matches, rayo_actor_match_fn match)
|
||||
{
|
||||
switch_hash_index_t *hi;
|
||||
void *val;
|
||||
const void *vvar;
|
||||
switch_console_callback_match_t *my_matches = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
struct rayo_actor *actor;
|
||||
|
||||
switch_mutex_lock(globals.actors_mutex);
|
||||
for (hi = switch_hash_first(NULL, globals.actors); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, &vvar, NULL, &val);
|
||||
|
||||
actor = (struct rayo_actor *) val;
|
||||
if (match(actor)) {
|
||||
switch_console_push_match(&my_matches, (const char *) vvar);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(globals.actors_mutex);
|
||||
|
||||
if (my_matches) {
|
||||
*matches = my_matches;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if internal actor
|
||||
*/
|
||||
static switch_bool_t is_internal_actor(struct rayo_actor *actor)
|
||||
{
|
||||
return strcmp(RAT_CLIENT, actor->type) && strcmp(RAT_PEER_SERVER, actor->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Console auto-completion for all internal actors
|
||||
*/
|
||||
switch_status_t list_internal(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
static switch_status_t list_internal(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
{
|
||||
switch_hash_index_t *hi;
|
||||
void *val;
|
||||
const void *vvar;
|
||||
switch_console_callback_match_t *my_matches = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
struct rayo_actor *actor;
|
||||
return list_actors(line, cursor, matches, is_internal_actor);
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.actors_mutex);
|
||||
for (hi = switch_hash_first(NULL, globals.actors); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, &vvar, NULL, &val);
|
||||
|
||||
actor = (struct rayo_actor *) val;
|
||||
if (strcmp(RAT_CLIENT, actor->type) && strcmp(RAT_PEER_SERVER, actor->type)) {
|
||||
switch_console_push_match(&my_matches, (const char *) vvar);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(globals.actors_mutex);
|
||||
|
||||
if (my_matches) {
|
||||
*matches = my_matches;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
/**
|
||||
* @return true if external actor
|
||||
*/
|
||||
static switch_bool_t is_external_actor(struct rayo_actor *actor)
|
||||
{
|
||||
return !strcmp(RAT_CLIENT, actor->type) || !strcmp(RAT_PEER_SERVER, actor->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Console auto-completion for all external actors
|
||||
*/
|
||||
switch_status_t list_external(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
static switch_status_t list_external(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
{
|
||||
switch_hash_index_t *hi;
|
||||
void *val;
|
||||
const void *vvar;
|
||||
switch_console_callback_match_t *my_matches = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
struct rayo_actor *actor;
|
||||
return list_actors(line, cursor, matches, is_external_actor);
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.actors_mutex);
|
||||
for (hi = switch_hash_first(NULL, globals.actors); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, &vvar, NULL, &val);
|
||||
|
||||
actor = (struct rayo_actor *) val;
|
||||
if (!strcmp(RAT_CLIENT, actor->type) || !strcmp(RAT_PEER_SERVER, actor->type)) {
|
||||
switch_console_push_match(&my_matches, (const char *) vvar);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(globals.actors_mutex);
|
||||
|
||||
if (my_matches) {
|
||||
*matches = my_matches;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
/**
|
||||
* @return true
|
||||
*/
|
||||
static switch_bool_t is_any_actor(struct rayo_actor *actor)
|
||||
{
|
||||
return SWITCH_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Console auto-completion for all actors
|
||||
*/
|
||||
switch_status_t list_all(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
static switch_status_t list_all(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
{
|
||||
switch_hash_index_t *hi;
|
||||
void *val;
|
||||
const void *vvar;
|
||||
switch_console_callback_match_t *my_matches = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
switch_mutex_lock(globals.actors_mutex);
|
||||
for (hi = switch_hash_first(NULL, globals.actors); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, &vvar, NULL, &val);
|
||||
switch_console_push_match(&my_matches, (const char *) vvar);
|
||||
}
|
||||
switch_mutex_unlock(globals.actors_mutex);
|
||||
|
||||
if (my_matches) {
|
||||
*matches = my_matches;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
return list_actors(line, cursor, matches, is_any_actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an alias to an API command
|
||||
* @param alias_name
|
||||
* @param alias_cmd
|
||||
* @return true if a server
|
||||
*/
|
||||
static void rayo_add_cmd_alias(const char *alias_name, const char *alias_cmd)
|
||||
static switch_bool_t is_server_actor(struct rayo_actor *actor)
|
||||
{
|
||||
char *cmd = switch_core_sprintf(globals.pool, "add rayo cmd ::rayo::list_actors %s", alias_name);
|
||||
switch_console_set_complete(cmd);
|
||||
switch_core_hash_insert(globals.cmd_aliases, alias_name, alias_cmd);
|
||||
return !strcmp(RAT_SERVER, actor->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Console auto-completion for all servers
|
||||
*/
|
||||
static switch_status_t list_server(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
{
|
||||
return list_actors(line, cursor, matches, is_server_actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a call
|
||||
*/
|
||||
static switch_bool_t is_call_actor(struct rayo_actor *actor)
|
||||
{
|
||||
return !strcmp(RAT_CALL, actor->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Console auto-completion for all calls
|
||||
*/
|
||||
static switch_status_t list_call(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
{
|
||||
return list_actors(line, cursor, matches, is_call_actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a component
|
||||
*/
|
||||
switch_bool_t is_component_actor(struct rayo_actor *actor)
|
||||
{
|
||||
return !strncmp(RAT_COMPONENT, actor->type, strlen(RAT_COMPONENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Console auto-completion for all components
|
||||
*/
|
||||
static switch_status_t list_component(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
{
|
||||
return list_actors(line, cursor, matches, is_component_actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a record component
|
||||
*/
|
||||
static switch_bool_t is_record_actor(struct rayo_actor *actor)
|
||||
{
|
||||
return is_component_actor(actor) && !strcmp(actor->subtype, "record");
|
||||
}
|
||||
|
||||
/**
|
||||
* Console auto-completion for all components
|
||||
*/
|
||||
static switch_status_t list_record(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
{
|
||||
return list_actors(line, cursor, matches, is_record_actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if an output component
|
||||
*/
|
||||
static switch_bool_t is_output_actor(struct rayo_actor *actor)
|
||||
{
|
||||
return is_component_actor(actor) && !strcmp(actor->subtype, "output");
|
||||
}
|
||||
|
||||
/**
|
||||
* Console auto-completion for all components
|
||||
*/
|
||||
static switch_status_t list_output(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
{
|
||||
return list_actors(line, cursor, matches, is_output_actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if an input component
|
||||
*/
|
||||
static switch_bool_t is_input_actor(struct rayo_actor *actor)
|
||||
{
|
||||
return is_component_actor(actor) && !strcmp(actor->subtype, "input");
|
||||
}
|
||||
|
||||
/**
|
||||
* Console auto-completion for all components
|
||||
*/
|
||||
static switch_status_t list_input(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
{
|
||||
return list_actors(line, cursor, matches, is_input_actor);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3708,98 +3858,20 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load)
|
||||
globals.console = rayo_console_client_create();
|
||||
|
||||
switch_console_set_complete("add rayo status");
|
||||
switch_console_set_complete("add rayo cmd ::rayo::list_internal");
|
||||
switch_console_set_complete("add rayo msg ::rayo::list_external");
|
||||
switch_console_set_complete("add rayo presence ::rayo::list_all online");
|
||||
switch_console_set_complete("add rayo presence ::rayo::list_all offline");
|
||||
switch_console_set_complete("add rayo cmd ::rayo::list_all");
|
||||
switch_console_set_complete("add rayo presence ::rayo::list_server online");
|
||||
switch_console_set_complete("add rayo presence ::rayo::list_server offline");
|
||||
switch_console_add_complete_func("::rayo::list_all", list_all);
|
||||
switch_console_add_complete_func("::rayo::list_internal", list_internal);
|
||||
switch_console_add_complete_func("::rayo::list_external", list_external);
|
||||
switch_console_add_complete_func("::rayo::list_all", list_all);
|
||||
switch_console_add_complete_func("::rayo::list_server", list_server);
|
||||
switch_console_add_complete_func("::rayo::list_call", list_call);
|
||||
switch_console_add_complete_func("::rayo::list_component", list_component);
|
||||
switch_console_add_complete_func("::rayo::list_record", list_record);
|
||||
switch_console_add_complete_func("::rayo::list_output", list_output);
|
||||
switch_console_add_complete_func("::rayo::list_input", list_input);
|
||||
|
||||
rayo_add_cmd_alias("ping", "<iq type=\"get\"><ping xmlns=\""IKS_NS_XMPP_PING"\"/></iq>");
|
||||
rayo_add_cmd_alias("answer", "<answer xmlns=\""RAYO_NS"\"/>");
|
||||
rayo_add_cmd_alias("hangup", "<hangup xmlns=\""RAYO_NS"\"/>");
|
||||
rayo_add_cmd_alias("stop", "<stop xmlns=\""RAYO_EXT_NS"\"/>");
|
||||
rayo_add_cmd_alias("pause", "<pause xmlns=\""RAYO_OUTPUT_NS"\"/>");
|
||||
rayo_add_cmd_alias("resume", "<resume xmlns=\""RAYO_OUTPUT_NS"\"/>");
|
||||
rayo_add_cmd_alias("speed-up", "<speed-up xmlns=\""RAYO_OUTPUT_NS"\"/>");
|
||||
rayo_add_cmd_alias("speed-down", "<speed-down xmlns=\""RAYO_OUTPUT_NS"\"/>");
|
||||
rayo_add_cmd_alias("volume-up", "<volume-up xmlns=\""RAYO_OUTPUT_NS"\"/>");
|
||||
rayo_add_cmd_alias("volume-down", "<volume-down xmlns=\""RAYO_OUTPUT_NS"\"/>");
|
||||
rayo_add_cmd_alias("record", "<record xmlns=\""RAYO_RECORD_NS"\"/>");
|
||||
rayo_add_cmd_alias("record_pause", "<pause xmlns=\""RAYO_RECORD_NS"\"/>");
|
||||
rayo_add_cmd_alias("record_resume", "<resume xmlns=\""RAYO_RECORD_NS"\"/>");
|
||||
rayo_add_cmd_alias("prompt_barge", "<prompt xmlns=\""RAYO_PROMPT_NS"\" barge-in=\"true\">"
|
||||
"<output xmlns=\""RAYO_OUTPUT_NS"\" repeat-times=\"5\"><document content-type=\"application/ssml+xml\"><![CDATA[<speak><p>Please press a digit.</p></speak>]]></document></output>"
|
||||
"<input xmlns=\""RAYO_INPUT_NS"\" mode=\"dtmf\" initial-timeout=\"5000\" inter-digit-timeout=\"3000\">"
|
||||
"<grammar content-type=\"application/srgs+xml\">"
|
||||
"<![CDATA[<grammar mode=\"dtmf\"><rule id=\"digit\" scope=\"public\"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></rule></grammar>]]>"
|
||||
"</grammar></input>"
|
||||
"</prompt>");
|
||||
|
||||
rayo_add_cmd_alias("prompt_no_barge", "<prompt xmlns=\""RAYO_PROMPT_NS"\" barge-in=\"false\">"
|
||||
"<output xmlns=\""RAYO_OUTPUT_NS"\" repeat-times=\"2\"><document content-type=\"application/ssml+xml\"><![CDATA[<speak><p>Please press a digit.</p></speak>]]></document></output>"
|
||||
"<input xmlns=\""RAYO_INPUT_NS"\" mode=\"dtmf\" initial-timeout=\"5000\" inter-digit-timeout=\"3000\">"
|
||||
"<grammar content-type=\"application/srgs+xml\">"
|
||||
"<![CDATA[<grammar mode=\"dtmf\"><rule id=\"digit\" scope=\"public\"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></rule></grammar>]]>"
|
||||
"</grammar></input>"
|
||||
"</prompt>");
|
||||
|
||||
rayo_add_cmd_alias("prompt_long", "<prompt xmlns=\""RAYO_PROMPT_NS"\" barge-in=\"true\">"
|
||||
"<output xmlns=\""RAYO_OUTPUT_NS"\" repeat-times=\"100\"><document content-type=\"application/ssml+xml\"><![CDATA[<speak><audio src=\"http://phono.com/audio/troporocks.mp3\"/></speak>]]></document></output>"
|
||||
"<input xmlns=\""RAYO_INPUT_NS"\" mode=\"dtmf\" initial-timeout=\"5000\" inter-digit-timeout=\"3000\">"
|
||||
"<grammar content-type=\"application/srgs+xml\">"
|
||||
"<![CDATA[<grammar mode=\"dtmf\"><rule id=\"digit\" scope=\"public\"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></rule></grammar>]]>"
|
||||
"</grammar></input>"
|
||||
"</prompt>");
|
||||
|
||||
rayo_add_cmd_alias("prompt_multi_digit", "<prompt xmlns=\""RAYO_PROMPT_NS"\" barge-in=\"true\">"
|
||||
"<output xmlns=\""RAYO_OUTPUT_NS"\" repeat-times=\"100\"><document content-type=\"application/ssml+xml\"><![CDATA[<speak><audio src=\"http://phono.com/audio/troporocks.mp3\"/></speak>]]></document></output>"
|
||||
"<input xmlns=\""RAYO_INPUT_NS"\" mode=\"dtmf\" initial-timeout=\"5000\" inter-digit-timeout=\"3000\">"
|
||||
"<grammar content-type=\"application/srgs+xml\">"
|
||||
"<![CDATA[<grammar mode=\"dtmf\"><rule id=\"digits\" scope=\"public\"><item repeat=\"1-4\"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></item></rule></grammar>]]>"
|
||||
"</grammar></input>"
|
||||
"</prompt>");
|
||||
|
||||
rayo_add_cmd_alias("prompt_terminator", "<prompt xmlns=\""RAYO_PROMPT_NS"\" barge-in=\"true\">"
|
||||
"<output xmlns=\""RAYO_OUTPUT_NS"\" repeat-times=\"100\"><document content-type=\"application/ssml+xml\"><![CDATA[<speak><audio src=\"http://phono.com/audio/troporocks.mp3\"/></speak>]]></document></output>"
|
||||
"<input xmlns=\""RAYO_INPUT_NS"\" mode=\"dtmf\" initial-timeout=\"5000\" inter-digit-timeout=\"3000\" terminator=\"#\">"
|
||||
"<grammar content-type=\"application/srgs+xml\">"
|
||||
"<![CDATA[<grammar mode=\"dtmf\"><rule id=\"digits\" scope=\"public\"><item repeat=\"1-4\"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></item></rule></grammar>]]>"
|
||||
"</grammar></input>"
|
||||
"</prompt>");
|
||||
|
||||
rayo_add_cmd_alias("prompt_input_bad", "<prompt xmlns=\""RAYO_PROMPT_NS"\" barge-in=\"true\">"
|
||||
"<output xmlns=\""RAYO_OUTPUT_NS"\" repeat-times=\"100\"><document content-type=\"application/ssml+xml\"><![CDATA[<speak><audio src=\"http://phono.com/audio/troporocks.mp3\"/></speak>]]></document></output>"
|
||||
"<input xmlns=\""RAYO_INPUT_NS"\" mode=\"dtf\" initial-timeout=\"5000\" inter-digit-timeout=\"3000\">"
|
||||
"<grammar content-type=\"application/srgs+xml\">"
|
||||
"<![CDATA[<grammar mode=\"dtmf\"><rule id=\"digits\" scope=\"public\"><item repeat=\"4\"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></item></rule></grammar>]]>"
|
||||
"</grammar></input>"
|
||||
"</prompt>");
|
||||
|
||||
rayo_add_cmd_alias("prompt_output_bad", "<prompt xmlns=\""RAYO_PROMPT_NS"\" barge-in=\"true\">"
|
||||
"<output xmlns=\""RAYO_OUTPUT_NS"\" repeat-time=\"100\"><document content-type=\"application/ssml+xml\"><![CDATA[<speak><audio src=\"http://phono.com/audio/troporocks.mp3\"/></speak>]]></document></output>"
|
||||
"<input xmlns=\""RAYO_INPUT_NS"\" mode=\"dtmf\" initial-timeout=\"5000\" inter-digit-timeout=\"3000\">"
|
||||
"<grammar content-type=\"application/srgs+xml\">"
|
||||
"<![CDATA[<grammar mode=\"dtmf\"><rule id=\"digits\" scope=\"public\"><item repeat=\"4\"><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item></one-of></item></rule></grammar>]]>"
|
||||
"</grammar></input>"
|
||||
"</prompt>");
|
||||
rayo_add_cmd_alias("input", "<input xmlns=\""RAYO_INPUT_NS"\" mode=\"dtmf\" initial-timeout=\"5000\" inter-digit-timeout=\"3000\">"
|
||||
"<grammar content-type=\"application/srgs+xml\">"
|
||||
"<![CDATA[<grammar mode=\"dtmf\"><rule id=\"digits\" scope=\"public\"><item><one-of><item>0</item><item>1</item><item>2</item><item>3</item><item>4</item><item>5</item><item>6</item><item>7</item><item>8</item><item>9</item><item>*</item><item>#</item></one-of></item></rule></grammar>]]>"
|
||||
"</grammar></input>");
|
||||
rayo_add_cmd_alias("output_bad",
|
||||
"<output xmlns=\""RAYO_OUTPUT_NS"\" repeat-time=\"100\"></output>");
|
||||
rayo_add_cmd_alias("join_mixer_duplex",
|
||||
"<join xmlns=\""RAYO_NS"\" mixer-name=\"test\" direction=\"duplex\"/>");
|
||||
rayo_add_cmd_alias("join_mixer_send",
|
||||
"<join xmlns=\""RAYO_NS"\" mixer-name=\"test\" direction=\"send\"/>");
|
||||
rayo_add_cmd_alias("join_mixer_recv",
|
||||
"<join xmlns=\""RAYO_NS"\" mixer-name=\"test\" direction=\"recv\"/>");
|
||||
rayo_add_cmd_alias("unjoin_mixer",
|
||||
"<unjoin xmlns=\""RAYO_NS"\" mixer-name=\"test\"/>");
|
||||
rayo_add_cmd_alias("unjoin",
|
||||
"<unjoin xmlns=\""RAYO_NS"\"/>");
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -3808,9 +3880,15 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load)
|
||||
*/
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_rayo_shutdown)
|
||||
{
|
||||
switch_console_del_complete_func("::rayo::list_all");
|
||||
switch_console_del_complete_func("::rayo::list_internal");
|
||||
switch_console_del_complete_func("::rayo::list_external");
|
||||
switch_console_del_complete_func("::rayo::list_all");
|
||||
switch_console_del_complete_func("::rayo::list_server");
|
||||
switch_console_del_complete_func("::rayo::list_call");
|
||||
switch_console_del_complete_func("::rayo::list_component");
|
||||
switch_console_del_complete_func("::rayo::list_record");
|
||||
switch_console_del_complete_func("::rayo::list_output");
|
||||
switch_console_del_complete_func("::rayo::list_input");
|
||||
switch_console_set_complete("del rayo");
|
||||
|
||||
/* stop XMPP streams */
|
||||
|
||||
@@ -51,9 +51,6 @@
|
||||
#define RAT_PEER_SERVER "PEER_SERVER"
|
||||
#define RAT_CLIENT "CLIENT"
|
||||
|
||||
/* these are support punchblock.. undefine once punchblock is fixed */
|
||||
#define RAYO_UUID_IN_REF_URI
|
||||
|
||||
struct rayo_actor;
|
||||
struct rayo_call;
|
||||
struct rayo_mixer;
|
||||
@@ -162,6 +159,7 @@ extern const char *rayo_call_get_dcp_jid(struct rayo_call *call);
|
||||
|
||||
#define rayo_component_init(component, pool, type, subtype, id, parent, client_jid) _rayo_component_init(component, pool, type, subtype, id, parent, client_jid, __FILE__, __LINE__)
|
||||
extern struct rayo_component *_rayo_component_init(struct rayo_component *component, switch_memory_pool_t *pool, const char *type, const char *subtype, const char *id, struct rayo_actor *parent, const char *client_jid, const char *file, int line);
|
||||
extern switch_bool_t is_component_actor(struct rayo_actor *);
|
||||
|
||||
typedef iks *(*rayo_actor_xmpp_handler)(struct rayo_actor *, struct rayo_message *, void *);
|
||||
extern void rayo_actor_command_handler_add(const char *type, const char *subtype, const char *name, rayo_actor_xmpp_handler fn);
|
||||
|
||||
@@ -412,7 +412,6 @@ iks *nlsml_create_dtmf_match(const char *digits)
|
||||
|
||||
iks *interpretation = iks_insert(result, "interpretation");
|
||||
iks *input = iks_insert(interpretation, "input");
|
||||
input = iks_insert(input, "input");
|
||||
iks_insert_attrib(input, "mode", "dtmf");
|
||||
iks_insert_attrib(input, "confidence", "100");
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
struct rayo_component *rayo_component_locate(const char *id, const char *file, int line)
|
||||
{
|
||||
struct rayo_actor *actor = rayo_actor_locate_by_id(id, file, line);
|
||||
if (actor && !strncmp(RAT_COMPONENT, actor->type, strlen(RAT_COMPONENT))) {
|
||||
if (actor && is_component_actor(actor)) {
|
||||
return RAYO_COMPONENT(actor);
|
||||
} else if (actor) {
|
||||
RAYO_UNLOCK(actor);
|
||||
@@ -58,11 +58,7 @@ void rayo_component_send_start(struct rayo_component *component, iks *iq)
|
||||
iks *response = iks_new_iq_result(iq);
|
||||
iks *ref = iks_insert(response, "ref");
|
||||
iks_insert_attrib(ref, "xmlns", RAYO_NS);
|
||||
#ifdef RAYO_UUID_IN_REF_URI
|
||||
iks_insert_attrib(ref, "uri", component->ref);
|
||||
#else
|
||||
iks_insert_attrib_printf(ref, "uri", "xmpp:%s", RAYO_JID(component));
|
||||
#endif
|
||||
RAYO_SEND_REPLY(component, iks_find_attrib(response, "to"), response);
|
||||
}
|
||||
|
||||
@@ -227,15 +223,10 @@ void rayo_component_api_execute_async(struct rayo_component *component, const ch
|
||||
*/
|
||||
switch_status_t rayo_components_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file)
|
||||
{
|
||||
rayo_input_component_load();
|
||||
rayo_output_component_load(module_interface, pool);
|
||||
rayo_prompt_component_load();
|
||||
rayo_record_component_load(pool, config_file);
|
||||
|
||||
if (rayo_input_component_load() != SWITCH_STATUS_SUCCESS ||
|
||||
rayo_output_component_load(module_interface, pool) != SWITCH_STATUS_SUCCESS ||
|
||||
rayo_prompt_component_load() != SWITCH_STATUS_SUCCESS ||
|
||||
rayo_record_component_load(pool, config_file) != SWITCH_STATUS_SUCCESS) {
|
||||
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) {
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
@@ -54,10 +54,10 @@
|
||||
#define COMPONENT_COMPLETE_HANGUP "hangup", RAYO_EXT_COMPLETE_NS
|
||||
|
||||
extern switch_status_t rayo_components_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
|
||||
extern switch_status_t rayo_input_component_load(void);
|
||||
extern switch_status_t rayo_output_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool);
|
||||
extern switch_status_t rayo_prompt_component_load(void);
|
||||
extern switch_status_t rayo_record_component_load(switch_memory_pool_t *pool, const char *config_file);
|
||||
extern switch_status_t rayo_input_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
|
||||
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_components_shutdown(void);
|
||||
extern switch_status_t rayo_input_component_shutdown(void);
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
*/
|
||||
ELEMENT(RAYO_INPUT)
|
||||
STRING_ATTRIB(mode, any, "any,dtmf,voice")
|
||||
ATTRIB(terminator,, any)
|
||||
OPTIONAL_ATTRIB(terminator,, dtmf_digit)
|
||||
ATTRIB(recognizer,, any)
|
||||
ATTRIB(language, en-US, any)
|
||||
ATTRIB(initial-timeout, -1, positive_or_neg_one)
|
||||
|
||||
@@ -45,6 +45,8 @@ struct input_handler;
|
||||
static struct {
|
||||
/** grammar parser */
|
||||
struct srgs_parser *parser;
|
||||
/** default recognizer to use if none specified */
|
||||
const char *default_recognizer;
|
||||
} globals;
|
||||
|
||||
/**
|
||||
@@ -57,8 +59,8 @@ struct input_component {
|
||||
int speech_mode;
|
||||
/** Number of collected digits */
|
||||
int num_digits;
|
||||
/** Terminating digits */
|
||||
int term_digit_mask;
|
||||
/** Terminating digit */
|
||||
char term_digit;
|
||||
/** The collected digits */
|
||||
char digits[MAX_DTMF + 1];
|
||||
/** grammar to match */
|
||||
@@ -70,7 +72,9 @@ struct input_component {
|
||||
/** maximum silence allowed */
|
||||
int max_silence;
|
||||
/** minimum speech detection confidence */
|
||||
int min_confidence;
|
||||
double min_confidence;
|
||||
/** sensitivity to background noise */
|
||||
double sensitivity;
|
||||
/** timeout after first digit is received */
|
||||
int inter_digit_timeout;
|
||||
/** stop flag */
|
||||
@@ -79,6 +83,10 @@ struct input_component {
|
||||
int start_timers;
|
||||
/** true if event fired for first digit / start of speech */
|
||||
int barge_event;
|
||||
/** optional language to use */
|
||||
const char *language;
|
||||
/** optional recognizer to use */
|
||||
const char *recognizer;
|
||||
/** global data */
|
||||
struct input_handler *handler;
|
||||
};
|
||||
@@ -91,77 +99,24 @@ struct input_component {
|
||||
struct input_handler {
|
||||
/** media bug to monitor frames / control input lifecycle */
|
||||
switch_media_bug_t *bug;
|
||||
/** active input component - TODO multiple inputs */
|
||||
struct input_component *component;
|
||||
/** active voice input component */
|
||||
struct input_component *voice_component;
|
||||
/** active dtmf input component */
|
||||
struct input_component *dtmf_component;
|
||||
/** synchronizes media bug and dtmf callbacks */
|
||||
switch_mutex_t *mutex;
|
||||
/** last recognizer used */
|
||||
const char *last_recognizer;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return digit mask
|
||||
* @param digit1 to match
|
||||
* @param digit2 to match
|
||||
* @return true if matching
|
||||
*/
|
||||
static int get_digit_mask(char digit)
|
||||
static int digit_test(char digit1, char digit2)
|
||||
{
|
||||
switch(digit) {
|
||||
case '0': return 1;
|
||||
case '1': return 1 << 1;
|
||||
case '2': return 1 << 2;
|
||||
case '3': return 1 << 3;
|
||||
case '4': return 1 << 4;
|
||||
case '5': return 1 << 5;
|
||||
case '6': return 1 << 6;
|
||||
case '7': return 1 << 7;
|
||||
case '8': return 1 << 8;
|
||||
case '9': return 1 << 9;
|
||||
case 'A':
|
||||
case 'a': return 1 << 10;
|
||||
case 'B':
|
||||
case 'b': return 1 << 11;
|
||||
case 'C':
|
||||
case 'c': return 1 << 12;
|
||||
case 'D':
|
||||
case 'd': return 1 << 13;
|
||||
case '#': return 1 << 14;
|
||||
case '*': return 1 << 15;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param digit_mask to check
|
||||
* @param digit to look for
|
||||
* @return true if set
|
||||
*/
|
||||
static int digit_mask_test(int digit_mask, char digit)
|
||||
{
|
||||
return digit_mask & get_digit_mask(digit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param digit_mask to set digit in
|
||||
* @param digit to set
|
||||
* @return the digit mask with the set digit
|
||||
*/
|
||||
static int digit_mask_set(int digit_mask, char digit)
|
||||
{
|
||||
return digit_mask | get_digit_mask(digit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param digit_mask to set digits in
|
||||
* @param digits to add to mask
|
||||
* @return the digit mask with the set digits
|
||||
*/
|
||||
static int digit_mask_set_from_digits(int digit_mask, const char *digits)
|
||||
{
|
||||
if (!zstr(digits)) {
|
||||
int digits_len = strlen(digits);
|
||||
int i;
|
||||
for (i = 0; i < digits_len; i++) {
|
||||
digit_mask = digit_mask_set(digit_mask, digits[i]);
|
||||
}
|
||||
}
|
||||
return digit_mask;
|
||||
return digit1 && digit2 && tolower(digit1) == tolower(digit2);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -205,15 +160,14 @@ static switch_status_t input_component_on_dtmf(switch_core_session_t *session, c
|
||||
|
||||
switch_mutex_lock(handler->mutex);
|
||||
|
||||
component = handler->component;
|
||||
component = handler->dtmf_component;
|
||||
/* additional paranoia check */
|
||||
if (!component) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Received DTMF without active input component\n");
|
||||
switch_mutex_unlock(handler->mutex);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
is_term_digit = digit_mask_test(component->term_digit_mask, dtmf->digit);
|
||||
is_term_digit = digit_test(component->term_digit, dtmf->digit);
|
||||
|
||||
if (!is_term_digit) {
|
||||
component->digits[component->num_digits] = dtmf->digit;
|
||||
@@ -247,7 +201,7 @@ static switch_status_t input_component_on_dtmf(switch_core_session_t *session, c
|
||||
}
|
||||
case SMT_NO_MATCH: {
|
||||
/* notify of no-match and remove input component */
|
||||
handler->component = NULL;
|
||||
handler->dtmf_component = NULL;
|
||||
switch_core_media_bug_remove(session, &handler->bug);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "NO MATCH = %s\n", component->digits);
|
||||
rayo_component_send_complete(RAYO_COMPONENT(component), INPUT_NOMATCH);
|
||||
@@ -256,7 +210,7 @@ static switch_status_t input_component_on_dtmf(switch_core_session_t *session, c
|
||||
case SMT_MATCH_END: {
|
||||
iks *result = nlsml_create_dtmf_match(component->digits);
|
||||
/* notify of match and remove input component */
|
||||
handler->component = NULL;
|
||||
handler->dtmf_component = NULL;
|
||||
switch_core_media_bug_remove(session, &handler->bug);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "MATCH = %s\n", component->digits);
|
||||
send_match_event(RAYO_COMPONENT(component), result);
|
||||
@@ -279,7 +233,7 @@ static switch_bool_t input_component_bug_callback(switch_media_bug_t *bug, void
|
||||
struct input_component *component;
|
||||
|
||||
switch_mutex_lock(handler->mutex);
|
||||
component = handler->component;
|
||||
component = handler->dtmf_component;
|
||||
|
||||
switch(type) {
|
||||
case SWITCH_ABC_TYPE_INIT: {
|
||||
@@ -294,7 +248,7 @@ static switch_bool_t input_component_bug_callback(switch_media_bug_t *bug, void
|
||||
int elapsed_ms = (switch_micro_time_now() - component->last_digit_time) / 1000;
|
||||
if (component->num_digits && component->inter_digit_timeout > 0 && elapsed_ms > component->inter_digit_timeout) {
|
||||
enum srgs_match_type match;
|
||||
handler->component = NULL;
|
||||
handler->dtmf_component = NULL;
|
||||
switch_core_media_bug_set_flag(bug, SMBF_PRUNE);
|
||||
|
||||
/* we got some input, check for match */
|
||||
@@ -310,7 +264,7 @@ static switch_bool_t input_component_bug_callback(switch_media_bug_t *bug, void
|
||||
rayo_component_send_complete(RAYO_COMPONENT(component), INPUT_NOMATCH);
|
||||
}
|
||||
} else if (!component->num_digits && component->initial_timeout > 0 && elapsed_ms > component->initial_timeout) {
|
||||
handler->component = NULL;
|
||||
handler->dtmf_component = NULL;
|
||||
switch_core_media_bug_set_flag(bug, SMBF_PRUNE);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "initial-timeout\n");
|
||||
rayo_component_send_complete(RAYO_COMPONENT(component), INPUT_NOINPUT);
|
||||
@@ -323,10 +277,10 @@ static switch_bool_t input_component_bug_callback(switch_media_bug_t *bug, void
|
||||
/* check for hangup */
|
||||
if (component) {
|
||||
if (component->stop) {
|
||||
handler->component = NULL;
|
||||
handler->dtmf_component = NULL;
|
||||
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_STOP);
|
||||
} else {
|
||||
handler->component = NULL;
|
||||
handler->dtmf_component = NULL;
|
||||
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_HANGUP);
|
||||
}
|
||||
}
|
||||
@@ -396,34 +350,53 @@ static iks *start_call_input(struct input_component *component, switch_core_sess
|
||||
handler = switch_core_session_alloc(session, sizeof(*handler));
|
||||
switch_mutex_init(&handler->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
|
||||
switch_channel_set_private(switch_core_session_get_channel(session), RAYO_INPUT_COMPONENT_PRIVATE_VAR, handler);
|
||||
handler->last_recognizer = "";
|
||||
}
|
||||
handler->component = component;
|
||||
|
||||
/* TODO break up this function by mode... dtmf/voice/fax/etc */
|
||||
component->speech_mode = strcmp(iks_find_attrib_soft(input, "mode"), "dtmf");
|
||||
if (component->speech_mode && handler->voice_component) {
|
||||
/* don't allow multi voice input */
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_CONFLICT, "Multiple voice input is not allowed");
|
||||
}
|
||||
if (!component->speech_mode && handler->dtmf_component) {
|
||||
/* don't allow multi dtmf input */
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_CONFLICT, "Multiple dtmf input is not allowed");
|
||||
}
|
||||
|
||||
if (component->speech_mode) {
|
||||
handler->voice_component = component;
|
||||
} else {
|
||||
handler->dtmf_component = component;
|
||||
}
|
||||
|
||||
component->grammar = NULL;
|
||||
component->num_digits = 0;
|
||||
component->digits[0] = '\0';
|
||||
component->stop = 0;
|
||||
component->speech_mode = 0;
|
||||
component->initial_timeout = iks_find_int_attrib(input, "initial-timeout");
|
||||
component->inter_digit_timeout = iks_find_int_attrib(input, "inter-digit-timeout");
|
||||
component->max_silence = iks_find_int_attrib(input, "max-silence");
|
||||
component->min_confidence = (int)ceil(iks_find_decimal_attrib(input, "min-confidence") * 100.0);
|
||||
component->min_confidence = iks_find_decimal_attrib(input, "min-confidence");
|
||||
component->sensitivity = iks_find_decimal_attrib(input, "sensitivity");
|
||||
component->barge_event = iks_find_bool_attrib(input, "barge-event");
|
||||
component->start_timers = iks_find_bool_attrib(input, "start-timers");
|
||||
/* TODO this should just be a single digit terminator? */
|
||||
component->term_digit_mask = digit_mask_set_from_digits(0, iks_find_attrib_soft(input, "terminator"));
|
||||
/* TODO recognizer ignored */
|
||||
/* TODO language ignored */
|
||||
component->term_digit = iks_find_char_attrib(input, "terminator");
|
||||
component->recognizer = iks_find_attrib(input, "recognizer");
|
||||
component->language = iks_find_attrib(input, "language");
|
||||
component->handler = handler;
|
||||
|
||||
/* parse the grammar */
|
||||
if (!(component->grammar = srgs_parse(globals.parser, iks_find_cdata(input, "grammar")))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Failed to parse grammar body\n");
|
||||
RAYO_UNLOCK(component);
|
||||
RAYO_DESTROY(component);
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Failed to parse grammar body");
|
||||
}
|
||||
|
||||
/* is this voice or dtmf srgs grammar? */
|
||||
if (!strcasecmp("dtmf", iks_find_attrib_soft(input, "mode"))) {
|
||||
if (!component->speech_mode) {
|
||||
|
||||
/* parse the grammar */
|
||||
if (!(component->grammar = srgs_parse(globals.parser, iks_find_cdata(input, "grammar")))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Failed to parse grammar body\n");
|
||||
RAYO_UNLOCK(component);
|
||||
RAYO_DESTROY(component);
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Failed to parse grammar body");
|
||||
}
|
||||
|
||||
component->last_digit_time = switch_micro_time_now();
|
||||
|
||||
/* acknowledge command */
|
||||
@@ -431,38 +404,124 @@ static iks *start_call_input(struct input_component *component, switch_core_sess
|
||||
|
||||
/* start dtmf input detection */
|
||||
if (switch_core_media_bug_add(session, "rayo_input_component", NULL, input_component_bug_callback, handler, 0, SMBF_READ_REPLACE, &handler->bug) != SWITCH_STATUS_SUCCESS) {
|
||||
handler->dtmf_component = NULL;
|
||||
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_ERROR);
|
||||
}
|
||||
} else {
|
||||
char *grammar = NULL;
|
||||
const char *jsgf_path;
|
||||
component->speech_mode = 1;
|
||||
jsgf_path = srgs_grammar_to_jsgf_file(component->grammar, SWITCH_GLOBAL_dirs.grammar_dir, "gram");
|
||||
if (!jsgf_path) {
|
||||
switch_stream_handle_t grammar = { 0 };
|
||||
SWITCH_STANDARD_STREAM(grammar);
|
||||
|
||||
if (zstr(component->recognizer)) {
|
||||
component->recognizer = globals.default_recognizer;
|
||||
}
|
||||
|
||||
/* if recognition engine is different, we can't handle this request */
|
||||
if (!zstr(handler->last_recognizer) && strcmp(component->recognizer, handler->last_recognizer)) {
|
||||
handler->voice_component = NULL;
|
||||
RAYO_UNLOCK(component);
|
||||
RAYO_DESTROY(component);
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Grammar error");
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Must use the same recognizer for the entire call");
|
||||
}
|
||||
handler->last_recognizer = switch_core_session_strdup(session, component->recognizer);
|
||||
|
||||
if (!strcmp(component->recognizer, "pocketsphinx")) {
|
||||
const char *jsgf_path;
|
||||
|
||||
/* transform SRGS grammar to JSGF */
|
||||
if (!(component->grammar = srgs_parse(globals.parser, iks_find_cdata(input, "grammar")))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Failed to parse grammar body\n");
|
||||
handler->voice_component = NULL;
|
||||
RAYO_UNLOCK(component);
|
||||
RAYO_DESTROY(component);
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Failed to parse grammar body");
|
||||
}
|
||||
jsgf_path = srgs_grammar_to_jsgf_file(component->grammar, SWITCH_GLOBAL_dirs.grammar_dir, "gram");
|
||||
if (!jsgf_path) {
|
||||
handler->voice_component = NULL;
|
||||
RAYO_UNLOCK(component);
|
||||
RAYO_DESTROY(component);
|
||||
return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Grammar conversion to JSGF error");
|
||||
}
|
||||
|
||||
/* build pocketsphinx grammar string */
|
||||
grammar.write_function(&grammar,
|
||||
"{start-input-timers=%s,no-input-timeout=%d,speech-timeout=%d,confidence-threshold=%d}%s",
|
||||
component->start_timers ? "true" : "false",
|
||||
component->initial_timeout,
|
||||
component->max_silence,
|
||||
(int)ceil(component->min_confidence * 100.0),
|
||||
jsgf_path);
|
||||
} else if (!strncmp(component->recognizer, "unimrcp", strlen("unimrcp"))) {
|
||||
/* send inline grammar to unimrcp */
|
||||
grammar.write_function(&grammar, "{start-input-timers=%s,confidence-threshold=%f,sensitivity-level=%f",
|
||||
component->start_timers ? "true" : "false",
|
||||
component->min_confidence,
|
||||
component->sensitivity);
|
||||
|
||||
if (component->initial_timeout > 0) {
|
||||
grammar.write_function(&grammar, ",no-input-timeout=%d",
|
||||
component->initial_timeout);
|
||||
}
|
||||
|
||||
if (component->max_silence > 0) {
|
||||
grammar.write_function(&grammar, ",speech-complete-timeout=%d,speech-incomplete-timeout=%d",
|
||||
component->max_silence,
|
||||
component->max_silence);
|
||||
}
|
||||
|
||||
if (!zstr(component->language)) {
|
||||
grammar.write_function(&grammar, ",speech-language=%s", component->language);
|
||||
}
|
||||
|
||||
if (!strcmp(iks_find_attrib_soft(input, "mode"), "any")) {
|
||||
/* set dtmf params */
|
||||
if (component->inter_digit_timeout > 0) {
|
||||
grammar.write_function(&grammar, ",dtmf-interdigit-timeout=%d", component->inter_digit_timeout);
|
||||
}
|
||||
if (component->term_digit) {
|
||||
grammar.write_function(&grammar, ",dtmf-term-char=%c", component->term_digit);
|
||||
}
|
||||
}
|
||||
|
||||
grammar.write_function(&grammar, "}inline:%s", iks_find_cdata(input, "grammar"));
|
||||
} else {
|
||||
/* passthrough to unknown ASR module */
|
||||
grammar.write_function(&grammar, "%s", iks_find_cdata(input, "grammar"));
|
||||
}
|
||||
|
||||
/* acknowledge command */
|
||||
rayo_component_send_start(RAYO_COMPONENT(component), iq);
|
||||
|
||||
/* TODO configurable speech detection - different engines, grammar passthrough, dtmf handled by recognizer */
|
||||
grammar = switch_mprintf("{no-input-timeout=%s,speech-timeout=%s,start-input-timers=%s,confidence-threshold=%d}%s",
|
||||
component->initial_timeout, component->max_silence,
|
||||
component->start_timers ? "true" : "false",
|
||||
component->min_confidence, jsgf_path);
|
||||
/* start speech detection */
|
||||
switch_channel_set_variable(switch_core_session_get_channel(session), "fire_asr_events", "true");
|
||||
if (switch_ivr_detect_speech(session, "pocketsphinx", grammar, "mod_rayo_grammar", "", NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_ivr_detect_speech(session, component->recognizer, grammar.data, "mod_rayo_grammar", "", NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
handler->voice_component = NULL;
|
||||
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_ERROR);
|
||||
}
|
||||
switch_safe_free(grammar);
|
||||
switch_safe_free(grammar.data);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create input component id for session.
|
||||
* @param session requesting component
|
||||
* @param input request
|
||||
* @return the ID
|
||||
*/
|
||||
static char *create_input_component_id(switch_core_session_t *session, iks *input)
|
||||
{
|
||||
const char *mode = "unk";
|
||||
if (input) {
|
||||
mode = iks_find_attrib_soft(input, "mode");
|
||||
if (!strcmp(mode, "any")) {
|
||||
mode = "voice";
|
||||
}
|
||||
}
|
||||
return switch_core_session_sprintf(session, "%s-input-%s", switch_core_session_get_uuid(session), mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start execution of input component
|
||||
*/
|
||||
@@ -470,10 +529,10 @@ static iks *start_call_input_component(struct rayo_actor *call, struct rayo_mess
|
||||
{
|
||||
iks *iq = msg->payload;
|
||||
switch_core_session_t *session = (switch_core_session_t *)session_data;
|
||||
char *component_id = switch_mprintf("%s-input", switch_core_session_get_uuid(session));
|
||||
iks *input = iks_find(iq, "input");
|
||||
char *component_id = create_input_component_id(session, input);
|
||||
switch_memory_pool_t *pool = NULL;
|
||||
struct input_component *input_component = NULL;
|
||||
iks *input = iks_find(iq, "input");
|
||||
const char *error = NULL;
|
||||
|
||||
if (!validate_call_input(input, &error)) {
|
||||
@@ -484,7 +543,6 @@ static iks *start_call_input_component(struct rayo_actor *call, struct rayo_mess
|
||||
switch_core_new_memory_pool(&pool);
|
||||
input_component = switch_core_alloc(pool, sizeof(*input_component));
|
||||
rayo_component_init(RAYO_COMPONENT(input_component), pool, RAT_CALL_COMPONENT, "input", component_id, call, iks_find_attrib(iq, "from"));
|
||||
switch_safe_free(component_id);
|
||||
|
||||
/* start input */
|
||||
return start_call_input(input_component, session, iks_find(iq, "input"), iq, NULL, 0);
|
||||
@@ -530,7 +588,6 @@ static iks *start_timers_call_input_component(struct rayo_actor *component, stru
|
||||
switch_mutex_lock(input_component->handler->mutex);
|
||||
if (input_component->speech_mode) {
|
||||
switch_ivr_detect_speech_start_input_timers(session);
|
||||
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_STOP);
|
||||
} else {
|
||||
input_component->last_digit_time = switch_micro_time_now();
|
||||
input_component->start_timers = 1;
|
||||
@@ -549,53 +606,63 @@ static void on_detected_speech_event(switch_event_t *event)
|
||||
{
|
||||
const char *speech_type = switch_event_get_header(event, "Speech-Type");
|
||||
char *event_str = NULL;
|
||||
const char *uuid = switch_event_get_header(event, "Unique-ID");
|
||||
switch_event_serialize(event, &event_str, SWITCH_FALSE);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s\n", event_str);
|
||||
if (!speech_type) {
|
||||
if (!speech_type || !uuid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp("detected-speech", speech_type)) {
|
||||
const char *uuid = switch_event_get_header(event, "Unique-ID");
|
||||
char *component_id = switch_mprintf("%s-input", uuid);
|
||||
char *component_id = switch_mprintf("%s-input-voice", uuid);
|
||||
struct rayo_component *component = RAYO_COMPONENT_LOCATE(component_id);
|
||||
|
||||
switch_safe_free(component_id);
|
||||
if (component) {
|
||||
const char *result = switch_event_get_body(event);
|
||||
switch_mutex_lock(INPUT_COMPONENT(component)->handler->mutex);
|
||||
INPUT_COMPONENT(component)->handler->component = NULL;
|
||||
INPUT_COMPONENT(component)->handler->voice_component = NULL;
|
||||
switch_mutex_unlock(INPUT_COMPONENT(component)->handler->mutex);
|
||||
if (zstr(result)) {
|
||||
rayo_component_send_complete(component, INPUT_NOMATCH);
|
||||
} else {
|
||||
enum nlsml_match_type match_type = nlsml_parse(result, uuid);
|
||||
switch (match_type) {
|
||||
case NMT_NOINPUT:
|
||||
if (strchr(result, '<')) {
|
||||
/* got an XML result */
|
||||
enum nlsml_match_type match_type = nlsml_parse(result, uuid);
|
||||
switch (match_type) {
|
||||
case NMT_NOINPUT:
|
||||
rayo_component_send_complete(component, INPUT_NOINPUT);
|
||||
break;
|
||||
case NMT_MATCH: {
|
||||
iks *result_xml = nlsml_normalize(result);
|
||||
send_match_event(RAYO_COMPONENT(component), result_xml);
|
||||
iks_delete(result_xml);
|
||||
break;
|
||||
}
|
||||
case NMT_BAD_XML:
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_WARNING, "Failed to parse NLSML result: %s!\n", result);
|
||||
rayo_component_send_complete(component, INPUT_NOMATCH);
|
||||
break;
|
||||
case NMT_NOMATCH:
|
||||
rayo_component_send_complete(component, INPUT_NOMATCH);
|
||||
break;
|
||||
default:
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_CRIT, "Unknown NLSML match type: %i, %s!\n", match_type, result);
|
||||
rayo_component_send_complete(component, INPUT_NOMATCH);
|
||||
break;
|
||||
}
|
||||
} else if (strstr(result, "002")) {
|
||||
/* Completion-Cause: 002 no-input-timeout */
|
||||
rayo_component_send_complete(component, INPUT_NOINPUT);
|
||||
break;
|
||||
case NMT_MATCH: {
|
||||
iks *result_xml = nlsml_normalize(result);
|
||||
send_match_event(RAYO_COMPONENT(component), result_xml);
|
||||
iks_delete(result_xml);
|
||||
break;
|
||||
}
|
||||
case NMT_BAD_XML:
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_WARNING, "Failed to parse NLSML result: %s!\n", result);
|
||||
} else {
|
||||
/* assume no match */
|
||||
rayo_component_send_complete(component, INPUT_NOMATCH);
|
||||
break;
|
||||
case NMT_NOMATCH:
|
||||
rayo_component_send_complete(component, INPUT_NOMATCH);
|
||||
break;
|
||||
default:
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_CRIT, "Unknown NLSML match type: %i, %s!\n", match_type, result);
|
||||
rayo_component_send_complete(component, INPUT_NOMATCH);
|
||||
break;
|
||||
}
|
||||
}
|
||||
RAYO_UNLOCK(component);
|
||||
}
|
||||
} else if (!strcasecmp("begin-speaking", speech_type)) {
|
||||
const char *uuid = switch_event_get_header(event, "Unique-ID");
|
||||
char *component_id = switch_mprintf("%s-input", uuid);
|
||||
char *component_id = switch_mprintf("%s-input-voice", uuid);
|
||||
struct rayo_component *component = RAYO_COMPONENT_LOCATE(component_id);
|
||||
switch_safe_free(component_id);
|
||||
if (component && INPUT_COMPONENT(component)->barge_event) {
|
||||
@@ -603,14 +670,13 @@ static void on_detected_speech_event(switch_event_t *event)
|
||||
}
|
||||
RAYO_UNLOCK(component);
|
||||
} else if (!strcasecmp("closed", speech_type)) {
|
||||
const char *uuid = switch_event_get_header(event, "Unique-ID");
|
||||
char *component_id = switch_mprintf("%s-input", uuid);
|
||||
char *component_id = switch_mprintf("%s-input-voice", uuid);
|
||||
struct rayo_component *component = RAYO_COMPONENT_LOCATE(component_id);
|
||||
switch_safe_free(component_id);
|
||||
if (component) {
|
||||
char *channel_state = switch_event_get_header(event, "Channel-State");
|
||||
switch_mutex_lock(INPUT_COMPONENT(component)->handler->mutex);
|
||||
INPUT_COMPONENT(component)->handler->component = NULL;
|
||||
INPUT_COMPONENT(component)->handler->voice_component = NULL;
|
||||
switch_mutex_unlock(INPUT_COMPONENT(component)->handler->mutex);
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Recognizer closed\n");
|
||||
if (channel_state && !strcmp("CS_HANGUP", channel_state)) {
|
||||
@@ -625,12 +691,63 @@ static void on_detected_speech_event(switch_event_t *event)
|
||||
switch_safe_free(event_str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.default_recognizer = "pocketsphinx";
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Configuring module\n");
|
||||
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, "input");
|
||||
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, "default-recognizer")) {
|
||||
if (!zstr(val)) {
|
||||
globals.default_recognizer = switch_core_strdup(pool, val);
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported param: %s\n", var);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch_xml_free(xml);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize input component
|
||||
* @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_input_component_load(void)
|
||||
switch_status_t rayo_input_component_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;
|
||||
}
|
||||
|
||||
srgs_init();
|
||||
nlsml_init();
|
||||
|
||||
|
||||
@@ -1092,9 +1092,12 @@ static char *fileman_supported_formats[] = { "fileman", NULL };
|
||||
|
||||
/**
|
||||
* Initialize output component
|
||||
* @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_output_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool)
|
||||
switch_status_t rayo_output_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file)
|
||||
{
|
||||
switch_api_interface_t *api_interface;
|
||||
switch_file_interface_t *file_interface;
|
||||
|
||||
@@ -620,9 +620,12 @@ static iks *forward_output_component_request(struct rayo_actor *prompt, struct r
|
||||
|
||||
/**
|
||||
* Initialize prompt component
|
||||
* @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_prompt_component_load(void)
|
||||
switch_status_t rayo_prompt_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file)
|
||||
{
|
||||
/* Prompt is a convenience component that wraps <input> and <output> */
|
||||
rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_PROMPT_NS":prompt", start_call_prompt_component);
|
||||
|
||||
@@ -479,11 +479,12 @@ static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_
|
||||
|
||||
/**
|
||||
* Initialize record component
|
||||
* @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_record_component_load(switch_memory_pool_t *pool, const char *config_file)
|
||||
switch_status_t rayo_record_component_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;
|
||||
|
||||
@@ -145,6 +145,27 @@ static void test_dialback_key(void)
|
||||
ASSERT_NULL(iks_server_dialback_key("s3cr3tf0rd14lb4ck", "xmpp.example.com", "example.org", NULL));
|
||||
}
|
||||
|
||||
static void test_validate_dtmf(void)
|
||||
{
|
||||
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("1"));
|
||||
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("A"));
|
||||
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("a"));
|
||||
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("D"));
|
||||
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("d"));
|
||||
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("*"));
|
||||
ASSERT_EQUALS(SWITCH_TRUE, iks_attrib_is_dtmf_digit("#"));
|
||||
ASSERT_EQUALS(SWITCH_FALSE, iks_attrib_is_dtmf_digit("E"));
|
||||
ASSERT_EQUALS(SWITCH_FALSE, iks_attrib_is_dtmf_digit(NULL));
|
||||
ASSERT_EQUALS(SWITCH_FALSE, iks_attrib_is_dtmf_digit(""));
|
||||
ASSERT_EQUALS(SWITCH_FALSE, iks_attrib_is_dtmf_digit("11"));
|
||||
ASSERT_EQUALS(SWITCH_TRUE, validate_optional_attrib(iks_attrib_is_dtmf_digit, "A"));
|
||||
ASSERT_EQUALS(SWITCH_TRUE, validate_optional_attrib(iks_attrib_is_dtmf_digit, "1"));
|
||||
ASSERT_EQUALS(SWITCH_FALSE, validate_optional_attrib(iks_attrib_is_dtmf_digit, "Z"));
|
||||
ASSERT_EQUALS(SWITCH_FALSE, validate_optional_attrib(iks_attrib_is_dtmf_digit, "11"));
|
||||
ASSERT_EQUALS(SWITCH_TRUE, validate_optional_attrib(iks_attrib_is_dtmf_digit, NULL));
|
||||
ASSERT_EQUALS(SWITCH_TRUE, validate_optional_attrib(iks_attrib_is_dtmf_digit, ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* main program
|
||||
*/
|
||||
@@ -159,5 +180,6 @@ int main(int argc, char **argv)
|
||||
TEST(test_rayo_test_srgs);
|
||||
TEST(test_iks_helper_value_matches);
|
||||
TEST(test_dialback_key);
|
||||
TEST(test_validate_dtmf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -244,8 +244,8 @@ static void test_parse_nlsml_examples(void)
|
||||
static const char *nlsml_dtmf_result =
|
||||
"<result xmlns='http://www.ietf.org/xml/ns/mrcpv2' "
|
||||
"xmlns:xf='http://www.w3.org/2000/xforms'><interpretation>"
|
||||
"<input><input mode='dtmf' confidence='100'>1 2 3 4</input>"
|
||||
"</input></interpretation></result>";
|
||||
"<input mode='dtmf' confidence='100'>1 2 3 4</input>"
|
||||
"</interpretation></result>";
|
||||
|
||||
/**
|
||||
* Test parsing NLSML example results
|
||||
|
||||
@@ -428,7 +428,7 @@ static abyss_bool http_directory_auth(TSession *r, char *domain_name)
|
||||
if (globals.default_domain) {
|
||||
domain_name = globals.default_domain;
|
||||
} else {
|
||||
if ((dup_domain = switch_core_get_variable_dup("domain"))) {
|
||||
if ((dup_domain = switch_core_get_domain(SWITCH_TRUE))) {
|
||||
domain_name = dup_domain;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
#include <switch.h>
|
||||
#include <switch_console.h>
|
||||
#include <switch_version.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <switch_private.h>
|
||||
#endif
|
||||
#define CMD_BUFLEN 1024
|
||||
|
||||
#ifdef SWITCH_HAVE_LIBEDIT
|
||||
@@ -619,6 +622,36 @@ SWITCH_DECLARE_NONSTD(switch_status_t) switch_console_list_loaded_modules(const
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GETIFADDRS
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
SWITCH_DECLARE_NONSTD(switch_status_t) switch_console_list_interfaces(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
{
|
||||
struct match_helper h = { 0 };
|
||||
struct ifaddrs *addrs, *addr;
|
||||
|
||||
getifaddrs(&addrs);
|
||||
for(addr = addrs; addr; addr = addr->ifa_next) {
|
||||
if (addr->ifa_flags & IFF_UP) {
|
||||
switch_console_push_match_unique(&h.my_matches, addr->ifa_name);
|
||||
}
|
||||
}
|
||||
freeifaddrs(addrs);
|
||||
|
||||
if (h.my_matches) {
|
||||
*matches = h.my_matches;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
#else
|
||||
SWITCH_DECLARE_NONSTD(switch_status_t) switch_console_list_interfaces(const char *line, const char *cursor, switch_console_callback_match_t **matches)
|
||||
{
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int uuid_callback(void *pArg, int argc, char **argv, char **columnNames)
|
||||
{
|
||||
struct match_helper *h = (struct match_helper *) pArg;
|
||||
@@ -1631,6 +1664,7 @@ SWITCH_DECLARE(switch_status_t) switch_console_init(switch_memory_pool_t *pool)
|
||||
switch_core_hash_init(&globals.func_hash, pool);
|
||||
switch_console_add_complete_func("::console::list_available_modules", (switch_console_complete_callback_t) switch_console_list_available_modules);
|
||||
switch_console_add_complete_func("::console::list_loaded_modules", (switch_console_complete_callback_t) switch_console_list_loaded_modules);
|
||||
switch_console_add_complete_func("::console::list_interfaces", (switch_console_complete_callback_t) switch_console_list_interfaces);
|
||||
switch_console_add_complete_func("::console::list_uuid", (switch_console_complete_callback_t) switch_console_list_uuid);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -1741,6 +1775,20 @@ SWITCH_DECLARE(void) switch_console_sort_matches(switch_console_callback_match_t
|
||||
}
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_console_push_match_unique(switch_console_callback_match_t **matches, const char *new_val)
|
||||
{
|
||||
/* Ignore the entry if it is already in the list */
|
||||
if (*matches) {
|
||||
switch_console_callback_match_node_t *node;
|
||||
|
||||
for(node = (*matches)->head; node; node = node->next) {
|
||||
if (!strcasecmp(node->val, new_val)) return;
|
||||
}
|
||||
}
|
||||
|
||||
switch_console_push_match(matches, new_val);
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_console_push_match(switch_console_callback_match_t **matches, const char *new_val)
|
||||
{
|
||||
switch_console_callback_match_node_t *match;
|
||||
|
||||
@@ -311,6 +311,24 @@ SWITCH_DECLARE(const char *) switch_core_get_switchname(void)
|
||||
return runtime.hostname;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(char *) switch_core_get_domain(switch_bool_t dup)
|
||||
{
|
||||
char *domain;
|
||||
const char *var;
|
||||
|
||||
switch_thread_rwlock_rdlock(runtime.global_var_rwlock);
|
||||
if (!(var = switch_core_get_variable("domain"))) {
|
||||
var = "freeswitch.local";
|
||||
}
|
||||
if (dup) {
|
||||
domain = strdup(var);
|
||||
} else {
|
||||
domain = (char *) var;
|
||||
}
|
||||
switch_thread_rwlock_unlock(runtime.global_var_rwlock);
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_get_variables(switch_event_t **event)
|
||||
{
|
||||
|
||||
+36
-8
@@ -156,6 +156,7 @@ typedef struct switch_rtp_engine_s {
|
||||
|
||||
struct media_helper mh;
|
||||
switch_thread_t *media_thread;
|
||||
switch_mutex_t *read_mutex;
|
||||
|
||||
} switch_rtp_engine_t;
|
||||
|
||||
@@ -1224,6 +1225,22 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session
|
||||
switch_assert(engine->rtp_session != NULL);
|
||||
engine->read_frame.datalen = 0;
|
||||
|
||||
if (!switch_channel_up_nosig(session->channel) || !switch_rtp_ready(engine->rtp_session) || switch_channel_test_flag(session->channel, CF_NOT_READY)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (switch_mutex_trylock(engine->read_mutex) != SWITCH_STATUS_SUCCESS) {
|
||||
/* return CNG, another thread is already reading */
|
||||
*frame = &engine->read_frame;
|
||||
switch_set_flag((*frame), SFF_CNG);
|
||||
(*frame)->datalen = engine->read_impl.encoded_bytes_per_packet;
|
||||
memset((*frame)->data, 0, (*frame)->datalen);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s is already being read for %s\n",
|
||||
switch_channel_get_name(session->channel), type2str(type));
|
||||
switch_yield(10000);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
while (smh->media_flags[SCMF_RUNNING] && engine->read_frame.datalen == 0) {
|
||||
engine->read_frame.flags = SFF_NONE;
|
||||
@@ -1239,13 +1256,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session
|
||||
(*frame)->datalen = engine->read_impl.encoded_bytes_per_packet;
|
||||
memset((*frame)->data, 0, (*frame)->datalen);
|
||||
switch_channel_execute_on(session->channel, "execute_on_media_timeout");
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
switch_goto_status(SWITCH_STATUS_SUCCESS, end);
|
||||
}
|
||||
|
||||
|
||||
switch_channel_hangup(session->channel, SWITCH_CAUSE_MEDIA_TIMEOUT);
|
||||
}
|
||||
return status;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Try to read an RTCP frame, if successful raise an event */
|
||||
@@ -1322,7 +1339,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session
|
||||
/* Fast PASS! */
|
||||
if (switch_test_flag((&engine->read_frame), SFF_PROXY_PACKET)) {
|
||||
*frame = &engine->read_frame;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
switch_goto_status(SWITCH_STATUS_SUCCESS, end);
|
||||
}
|
||||
|
||||
if (switch_rtp_has_dtmf(engine->rtp_session)) {
|
||||
@@ -1338,7 +1355,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session
|
||||
if (!switch_test_flag((&engine->read_frame), SFF_CNG)) {
|
||||
if (!engine->read_codec.implementation || !switch_core_codec_ready(&engine->read_codec)) {
|
||||
*frame = NULL;
|
||||
return SWITCH_STATUS_GENERR;
|
||||
switch_goto_status(SWITCH_STATUS_GENERR, end);
|
||||
}
|
||||
|
||||
/* check for timing or codec issues */
|
||||
@@ -1475,7 +1492,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session
|
||||
if (switch_rtp_ready(engine->rtp_session)) {
|
||||
if (switch_core_media_set_codec(session, 2, 0) != SWITCH_STATUS_SUCCESS) {
|
||||
*frame = NULL;
|
||||
return SWITCH_STATUS_GENERR;
|
||||
switch_goto_status(SWITCH_STATUS_GENERR, end);
|
||||
}
|
||||
|
||||
if ((val = switch_channel_get_variable(session->channel, "rtp_timeout_sec"))) {
|
||||
@@ -1516,7 +1533,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session
|
||||
switch_set_flag((*frame), SFF_CNG);
|
||||
(*frame)->datalen = engine->read_impl.encoded_bytes_per_packet;
|
||||
memset((*frame)->data, 0, (*frame)->datalen);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
switch_goto_status(SWITCH_STATUS_SUCCESS, end);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1541,7 +1558,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session
|
||||
|
||||
*frame = &engine->read_frame;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
end:
|
||||
|
||||
switch_mutex_unlock(engine->read_mutex);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//?
|
||||
@@ -3416,6 +3439,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_proxy_remote_addr(switch_core_
|
||||
if (*rvp) {
|
||||
v_engine->codec_params.remote_sdp_ip = switch_core_session_strdup(session, rip);
|
||||
v_engine->codec_params.remote_sdp_port = (switch_port_t) atoi(rvp);
|
||||
switch_channel_set_flag(session->channel, CF_VIDEO_POSSIBLE);
|
||||
switch_channel_set_flag(session->channel, CF_VIDEO);
|
||||
}
|
||||
|
||||
if (v_engine->codec_params.remote_sdp_ip && v_engine->codec_params.remote_sdp_port) {
|
||||
@@ -4162,6 +4187,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
|
||||
uint8_t inb = switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND;
|
||||
const char *ssrc;
|
||||
|
||||
switch_mutex_init(&a_engine->read_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
|
||||
|
||||
//switch_core_media_set_rtp_session(session, SWITCH_MEDIA_TYPE_AUDIO, a_engine->rtp_session);
|
||||
|
||||
if ((ssrc = switch_channel_get_variable(session->channel, "rtp_use_ssrc"))) {
|
||||
@@ -4621,6 +4648,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
|
||||
|
||||
switch_thread_cond_create(&v_engine->mh.cond, pool);
|
||||
switch_mutex_init(&v_engine->mh.cond_mutex, SWITCH_MUTEX_NESTED, pool);
|
||||
switch_mutex_init(&v_engine->read_mutex, SWITCH_MUTEX_NESTED, pool);
|
||||
switch_thread_create(&v_engine->media_thread, thd_attr, video_helper_thread, &v_engine->mh, switch_core_session_get_pool(session));
|
||||
}
|
||||
|
||||
@@ -6175,7 +6203,7 @@ SWITCH_DECLARE(void) switch_core_media_patch_sdp(switch_core_session_t *session)
|
||||
}
|
||||
|
||||
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
|
||||
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
|
||||
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
|
||||
|
||||
if (zstr(smh->mparams->local_sdp_str)) {
|
||||
return;
|
||||
|
||||
@@ -2521,6 +2521,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_async(sw
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_core_session_video_reset(switch_core_session_t *session)
|
||||
{
|
||||
if (switch_channel_test_flag(session->channel, CF_VIDEO)) {
|
||||
switch_channel_set_flag(session->channel, CF_VIDEO_ECHO);
|
||||
switch_channel_clear_flag(session->channel, CF_VIDEO_PASSIVE);
|
||||
switch_core_session_refresh_video(session);
|
||||
}
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_get_flags(switch_core_session_t *session, const char *app,
|
||||
const char *arg, int32_t *flags)
|
||||
@@ -2736,19 +2744,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_exec(switch_core_session_t *
|
||||
msg.string_array_arg[1] = expanded;
|
||||
switch_core_session_receive_message(session, &msg);
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_VIDEO)) {
|
||||
switch_channel_set_flag(channel, CF_VIDEO_ECHO);
|
||||
switch_channel_clear_flag(channel, CF_VIDEO_PASSIVE);
|
||||
switch_core_session_refresh_video(session);
|
||||
}
|
||||
|
||||
application_interface->application_function(session, expanded);
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_VIDEO)) {
|
||||
switch_channel_set_flag(channel, CF_VIDEO_ECHO);
|
||||
switch_channel_clear_flag(channel, CF_VIDEO_PASSIVE);
|
||||
switch_core_session_refresh_video(session);
|
||||
}
|
||||
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE) == SWITCH_STATUS_SUCCESS) {
|
||||
const char *resp = switch_channel_get_variable(session->channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE);
|
||||
switch_channel_event_set_data(session->channel, event);
|
||||
|
||||
@@ -216,6 +216,8 @@ static void switch_core_standard_on_execute(switch_core_session_t *session)
|
||||
|
||||
top:
|
||||
switch_channel_clear_flag(session->channel, CF_RESET);
|
||||
|
||||
switch_core_session_video_reset(session);
|
||||
|
||||
if ((extension = switch_channel_get_caller_extension(session->channel)) == 0) {
|
||||
switch_channel_hangup(session->channel, SWITCH_CAUSE_NORMAL_CLEARING);
|
||||
|
||||
+71
-68
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
@@ -22,11 +22,12 @@
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Michael Jerris <mike@jerris.com>
|
||||
* Paul D. Tinsley <pdt at jackhammer.org>
|
||||
* William King <william.king@quentustech.com>
|
||||
* Raymond Chandler <intralanman@freeswitch.org>
|
||||
*
|
||||
* switch_event.c -- Event System
|
||||
*
|
||||
@@ -153,6 +154,8 @@ static char *EVENT_NAMES[] = {
|
||||
"MESSAGE",
|
||||
"PRESENCE_IN",
|
||||
"NOTIFY_IN",
|
||||
"PHONE_FEATURE",
|
||||
"PHONE_FEATURE_SUBSCRIBE",
|
||||
"PRESENCE_OUT",
|
||||
"PRESENCE_PROBE",
|
||||
"MESSAGE_WAITING",
|
||||
@@ -263,7 +266,7 @@ static void *SWITCH_THREAD_FUNC switch_event_dispatch_thread(switch_thread_t *th
|
||||
|
||||
EVENT_DISPATCH_QUEUE_RUNNING[my_id] = 1;
|
||||
switch_mutex_unlock(EVENT_QUEUE_MUTEX);
|
||||
|
||||
|
||||
|
||||
for (;;) {
|
||||
void *pop = NULL;
|
||||
@@ -308,11 +311,11 @@ static switch_status_t switch_event_queue_dispatch_event(switch_event_t **eventp
|
||||
if (!SYSTEM_RUNNING) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
|
||||
while (event) {
|
||||
int launch = 0;
|
||||
|
||||
switch_mutex_lock(EVENT_QUEUE_MUTEX);
|
||||
|
||||
switch_mutex_lock(EVENT_QUEUE_MUTEX);
|
||||
|
||||
if (!PENDING && switch_queue_size(EVENT_DISPATCH_QUEUE) > (unsigned int)(DISPATCH_QUEUE_LEN * DISPATCH_THREAD_COUNT)) {
|
||||
if (SOFT_MAX_DISPATCH + 1 > MAX_DISPATCH) {
|
||||
@@ -322,7 +325,7 @@ static switch_status_t switch_event_queue_dispatch_event(switch_event_t **eventp
|
||||
}
|
||||
|
||||
switch_mutex_unlock(EVENT_QUEUE_MUTEX);
|
||||
|
||||
|
||||
if (launch) {
|
||||
if (SOFT_MAX_DISPATCH + 1 < MAX_DISPATCH) {
|
||||
switch_event_launch_dispatch_threads(SOFT_MAX_DISPATCH + 1);
|
||||
@@ -336,9 +339,9 @@ static switch_status_t switch_event_queue_dispatch_event(switch_event_t **eventp
|
||||
*eventp = NULL;
|
||||
switch_queue_push(EVENT_DISPATCH_QUEUE, event);
|
||||
event = NULL;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -579,12 +582,12 @@ SWITCH_DECLARE(switch_status_t) switch_event_init(switch_memory_pool_t *pool)
|
||||
{
|
||||
//switch_threadattr_t *thd_attr;
|
||||
|
||||
/*
|
||||
/*
|
||||
This statement doesn't do anything commenting it out for now.
|
||||
|
||||
switch_assert(switch_arraylen(EVENT_NAMES) == SWITCH_EVENT_ALL + 1);
|
||||
*/
|
||||
|
||||
|
||||
/* don't need any more dispatch threads than we have CPU's*/
|
||||
MAX_DISPATCH = (switch_core_cpu_count() / 2) + 1;
|
||||
if (MAX_DISPATCH < 2) {
|
||||
@@ -751,7 +754,7 @@ SWITCH_DECLARE(char *) switch_event_get_header_idx(switch_event_t *event, const
|
||||
}
|
||||
}
|
||||
|
||||
return hp->value;
|
||||
return hp->value;
|
||||
} else if (!strcmp(header_name, "_body")) {
|
||||
return event->body;
|
||||
}
|
||||
@@ -802,7 +805,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_del_header_val(switch_event_t *even
|
||||
}
|
||||
|
||||
FREE(hp->value);
|
||||
|
||||
|
||||
memset(hp, 0, sizeof(*hp));
|
||||
#ifdef SWITCH_EVENT_RECYCLE
|
||||
if (switch_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE, hp) != SWITCH_STATUS_SUCCESS) {
|
||||
@@ -834,7 +837,7 @@ static switch_event_header_t *new_header(const char *header_name)
|
||||
switch_assert(header);
|
||||
#ifdef SWITCH_EVENT_RECYCLE
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
memset(header, 0, sizeof(*header));
|
||||
header->name = DUP(header_name);
|
||||
@@ -870,15 +873,15 @@ SWITCH_DECLARE(int) switch_event_add_array(switch_event_t *event, const char *va
|
||||
}
|
||||
|
||||
data = strdup(val + 7);
|
||||
|
||||
|
||||
len = (sizeof(char *) * max) + 1;
|
||||
switch_assert(len);
|
||||
|
||||
array = malloc(len);
|
||||
memset(array, 0, len);
|
||||
|
||||
|
||||
switch_separate_string_string(data, "|:", array, max);
|
||||
|
||||
|
||||
for(i = 0; i < max; i++) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_PUSH, var, array[i]);
|
||||
}
|
||||
@@ -914,20 +917,20 @@ static switch_status_t switch_event_base_add_header(switch_event_t *event, switc
|
||||
}
|
||||
|
||||
if (index_ptr || (stack & SWITCH_STACK_PUSH) || (stack & SWITCH_STACK_UNSHIFT)) {
|
||||
|
||||
|
||||
if (!(header = switch_event_get_header_ptr(event, header_name)) && index_ptr) {
|
||||
|
||||
|
||||
header = new_header(header_name);
|
||||
|
||||
|
||||
if (switch_test_flag(event, EF_UNIQ_HEADERS)) {
|
||||
switch_event_del_header(event, header_name);
|
||||
}
|
||||
|
||||
fly++;
|
||||
}
|
||||
|
||||
|
||||
if (header || (header = switch_event_get_header_ptr(event, header_name))) {
|
||||
|
||||
|
||||
if (index_ptr) {
|
||||
if (index > -1 && index <= 4000) {
|
||||
if (index < header->idx) {
|
||||
@@ -936,7 +939,7 @@ static switch_status_t switch_event_base_add_header(switch_event_t *event, switc
|
||||
} else {
|
||||
int i;
|
||||
char **m;
|
||||
|
||||
|
||||
m = realloc(header->array, sizeof(char *) * (index + 1));
|
||||
switch_assert(m);
|
||||
header->array = m;
|
||||
@@ -986,7 +989,7 @@ static switch_status_t switch_event_base_add_header(switch_event_t *event, switc
|
||||
|
||||
header = new_header(header_name);
|
||||
}
|
||||
|
||||
|
||||
if ((stack & SWITCH_STACK_PUSH) || (stack & SWITCH_STACK_UNSHIFT)) {
|
||||
char **m = NULL;
|
||||
switch_size_t len = 0;
|
||||
@@ -1004,7 +1007,7 @@ static switch_status_t switch_event_base_add_header(switch_event_t *event, switc
|
||||
}
|
||||
|
||||
i = header->idx + 1;
|
||||
m = realloc(header->array, sizeof(char *) * i);
|
||||
m = realloc(header->array, sizeof(char *) * i);
|
||||
switch_assert(m);
|
||||
|
||||
if ((stack & SWITCH_STACK_PUSH)) {
|
||||
@@ -1016,7 +1019,7 @@ static switch_status_t switch_event_base_add_header(switch_event_t *event, switc
|
||||
m[0] = data;
|
||||
}
|
||||
|
||||
header->idx++;
|
||||
header->idx++;
|
||||
header->array = m;
|
||||
|
||||
redraw:
|
||||
@@ -1118,7 +1121,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_set_body(switch_event_t *event, con
|
||||
if (body) {
|
||||
event->body = DUP(body);
|
||||
}
|
||||
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1170,7 +1173,7 @@ SWITCH_DECLARE(void) switch_event_destroy(switch_event_t **event)
|
||||
|
||||
FREE(this->name);
|
||||
FREE(this->value);
|
||||
|
||||
|
||||
|
||||
#ifdef SWITCH_EVENT_RECYCLE
|
||||
if (switch_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE, this) != SWITCH_STATUS_SUCCESS) {
|
||||
@@ -1200,13 +1203,13 @@ SWITCH_DECLARE(void) switch_event_destroy(switch_event_t **event)
|
||||
SWITCH_DECLARE(void) switch_event_merge(switch_event_t *event, switch_event_t *tomerge)
|
||||
{
|
||||
switch_event_header_t *hp;
|
||||
|
||||
|
||||
switch_assert(tomerge && event);
|
||||
|
||||
for (hp = tomerge->headers; hp; hp = hp->next) {
|
||||
if (hp->idx) {
|
||||
int i;
|
||||
|
||||
|
||||
for(i = 0; i < hp->idx; i++) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_PUSH, hp->name, hp->array[i]);
|
||||
}
|
||||
@@ -1232,7 +1235,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_dup(switch_event_t **event, switch_
|
||||
if (todup->subclass_name && !strcmp(hp->name, "Event-Subclass")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (hp->idx) {
|
||||
int i;
|
||||
for (i = 0; i < hp->idx; i++) {
|
||||
@@ -1270,11 +1273,11 @@ SWITCH_DECLARE(switch_status_t) switch_event_dup_reply(switch_event_t **event, s
|
||||
|
||||
for (hp = todup->headers; hp; hp = hp->next) {
|
||||
char *name = hp->name, *value = hp->value;
|
||||
|
||||
|
||||
if (todup->subclass_name && !strcmp(hp->name, "Event-Subclass")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!strncasecmp(hp->name, "from_", 5)) {
|
||||
p = hp->name + 5;
|
||||
switch_snprintf(hname, sizeof(hname), "to_%s", p);
|
||||
@@ -1288,7 +1291,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_dup_reply(switch_event_t **event, s
|
||||
} else if (!strcasecmp(name, "from")) {
|
||||
name = "to";
|
||||
}
|
||||
|
||||
|
||||
if (hp->idx) {
|
||||
int i;
|
||||
for (i = 0; i < hp->idx; i++) {
|
||||
@@ -1379,13 +1382,13 @@ SWITCH_DECLARE(switch_status_t) switch_event_binary_serialize(switch_event_t *ev
|
||||
tn = tpl_map(SWITCH_SERIALIZED_EVENT_MAP, &e, &sh);
|
||||
|
||||
tpl_pack(tn, 0);
|
||||
|
||||
|
||||
for (eh = event->headers; eh; eh = eh->next) {
|
||||
if (eh->idx) continue; // no arrays yet
|
||||
|
||||
|
||||
sh.name = eh->name;
|
||||
sh.value = eh->value;
|
||||
|
||||
|
||||
tpl_pack(tn, 1);
|
||||
}
|
||||
|
||||
@@ -1427,7 +1430,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_serialize(switch_event_t *event, ch
|
||||
/*
|
||||
* grab enough memory to store 3x the string (url encode takes one char and turns it into %XX)
|
||||
* so we could end up with a string that is 3 times the originals length, unlikely but rather
|
||||
* be safe than destroy the string, also add one for the null. And try to be smart about using
|
||||
* be safe than destroy the string, also add one for the null. And try to be smart about using
|
||||
* the memory, allocate and only reallocate if we need more. This avoids an alloc, free CPU
|
||||
* destroying loop.
|
||||
*/
|
||||
@@ -1522,11 +1525,11 @@ SWITCH_DECLARE(switch_status_t) switch_event_create_array_pair(switch_event_t **
|
||||
char *name, *val;
|
||||
|
||||
switch_event_create(event, SWITCH_EVENT_CLONE);
|
||||
|
||||
|
||||
for (r = 0; r < len; r++) {
|
||||
val = switch_str_nil(vals[r]);
|
||||
name = names[r];
|
||||
|
||||
|
||||
if (zstr(name)) {
|
||||
name = "Unknown";
|
||||
}
|
||||
@@ -1535,7 +1538,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_create_array_pair(switch_event_t **
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_event_create_brackets(char *data, char a, char b, char c, switch_event_t **event, char **new_data, switch_bool_t dup)
|
||||
@@ -1555,17 +1558,17 @@ SWITCH_DECLARE(switch_status_t) switch_event_create_brackets(char *data, char a,
|
||||
}
|
||||
|
||||
end = switch_find_end_paren(vdata, a, b);
|
||||
|
||||
|
||||
check_a = end;
|
||||
|
||||
|
||||
while (check_a && (check_b = switch_strchr_strict(check_a, a, " "))) {
|
||||
if ((check_b = switch_find_end_paren(check_b, a, b))) {
|
||||
check_a = check_b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (check_a) end = check_a;
|
||||
|
||||
|
||||
if (end) {
|
||||
next = end;
|
||||
vdata++;
|
||||
@@ -1576,12 +1579,12 @@ SWITCH_DECLARE(switch_status_t) switch_event_create_brackets(char *data, char a,
|
||||
}
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (!e) {
|
||||
switch_event_create_plain(&e, SWITCH_EVENT_CHANNEL_DATA);
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (;;) {
|
||||
if (next) {
|
||||
char *pnext;
|
||||
@@ -1595,7 +1598,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_create_brackets(char *data, char a,
|
||||
vnext = switch_find_end_paren(next, a, b);
|
||||
next = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (vdata) {
|
||||
if (*vdata == '^' && *(vdata + 1) == '^') {
|
||||
@@ -1603,7 +1606,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_create_brackets(char *data, char a,
|
||||
c = *vdata++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((var_count = switch_separate_string(vdata, c, var_array, (sizeof(var_array) / sizeof(var_array[0]))))) {
|
||||
int x = 0;
|
||||
for (x = 0; x < var_count; x++) {
|
||||
@@ -1635,7 +1638,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_create_brackets(char *data, char a,
|
||||
} else {
|
||||
*new_data = end;
|
||||
}
|
||||
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
}
|
||||
@@ -1687,7 +1690,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_create_json(switch_event_t **event,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cJSON_Delete(cj);
|
||||
*event = new_event;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
@@ -1699,7 +1702,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_serialize_json(switch_event_t *even
|
||||
cJSON *cj;
|
||||
|
||||
*str = NULL;
|
||||
|
||||
|
||||
cj = cJSON_CreateObject();
|
||||
|
||||
for (hp = event->headers; hp; hp = hp->next) {
|
||||
@@ -1710,9 +1713,9 @@ SWITCH_DECLARE(switch_status_t) switch_event_serialize_json(switch_event_t *even
|
||||
for(i = 0; i < hp->idx; i++) {
|
||||
cJSON_AddItemToArray(a, cJSON_CreateString(hp->array[i]));
|
||||
}
|
||||
|
||||
|
||||
cJSON_AddItemToObject(cj, hp->name, a);
|
||||
|
||||
|
||||
} else {
|
||||
cJSON_AddItemToObject(cj, hp->name, cJSON_CreateString(hp->value));
|
||||
}
|
||||
@@ -1730,7 +1733,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_serialize_json(switch_event_t *even
|
||||
|
||||
*str = cJSON_Print(cj);
|
||||
cJSON_Delete(cj);
|
||||
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1901,7 +1904,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_bind_removable(const char *id, swit
|
||||
if (node) {
|
||||
*node = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (subclass_name) {
|
||||
if (!(subclass = switch_core_hash_find(CUSTOM_HASH, subclass_name))) {
|
||||
switch_event_reserve_subclass_detailed(id, subclass_name);
|
||||
@@ -2066,9 +2069,9 @@ char *dp;\
|
||||
olen += (len + l + block);\
|
||||
cpos = c - data;\
|
||||
if ((dp = realloc(data, olen))) {\
|
||||
data = dp;\
|
||||
c = data + cpos;\
|
||||
memset(c, 0, olen - cpos);\
|
||||
data = dp;\
|
||||
c = data + cpos;\
|
||||
memset(c, 0, olen - cpos);\
|
||||
}} \
|
||||
|
||||
SWITCH_DECLARE(char *) switch_event_expand_headers_check(switch_event_t *event, const char *in, switch_event_t *var_list, switch_event_t *api_list, uint32_t recur)
|
||||
@@ -2223,7 +2226,7 @@ SWITCH_DECLARE(char *) switch_event_expand_headers_check(switch_event_t *event,
|
||||
int ooffset = 0;
|
||||
char *ptr;
|
||||
int idx = -1;
|
||||
|
||||
|
||||
if ((expanded = switch_event_expand_headers_check(event, (char *) vname, var_list, api_list, recur+1)) == vname) {
|
||||
expanded = NULL;
|
||||
} else {
|
||||
@@ -2266,7 +2269,7 @@ SWITCH_DECLARE(char *) switch_event_expand_headers_check(switch_event_t *event,
|
||||
switch_assert(cloned_sub_val);
|
||||
sub_val = cloned_sub_val;
|
||||
}
|
||||
|
||||
|
||||
if (offset >= 0) {
|
||||
sub_val += offset;
|
||||
} else if ((size_t) abs(offset) <= strlen(sub_val)) {
|
||||
@@ -2278,7 +2281,7 @@ SWITCH_DECLARE(char *) switch_event_expand_headers_check(switch_event_t *event,
|
||||
*ptr = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
switch_safe_free(expanded);
|
||||
} else {
|
||||
@@ -2477,7 +2480,7 @@ SWITCH_DECLARE(int) switch_event_check_permission_list(switch_event_t *list, con
|
||||
r = default_allow;
|
||||
}
|
||||
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_event_add_presence_data_cols(switch_channel_t *channel, switch_event_t *event, const char *prefix)
|
||||
@@ -2485,7 +2488,7 @@ SWITCH_DECLARE(void) switch_event_add_presence_data_cols(switch_channel_t *chann
|
||||
const char *data;
|
||||
|
||||
if (!prefix) prefix = "";
|
||||
|
||||
|
||||
if ((data = switch_channel_get_variable(channel, "presence_data_cols"))) {
|
||||
char *cols[128] = { 0 };
|
||||
char header_name[128] = "";
|
||||
@@ -2493,17 +2496,17 @@ SWITCH_DECLARE(void) switch_event_add_presence_data_cols(switch_channel_t *chann
|
||||
char *data_copy = NULL;
|
||||
|
||||
data_copy = strdup(data);
|
||||
|
||||
|
||||
col_count = switch_split(data_copy, ':', cols);
|
||||
|
||||
|
||||
for (i = 0; i < col_count; i++) {
|
||||
const char *val = NULL;
|
||||
switch_snprintf(header_name, sizeof(header_name), "%s%s", prefix, cols[i]);
|
||||
|
||||
|
||||
val = switch_channel_get_variable(channel, cols[i]);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header_name, val);
|
||||
}
|
||||
|
||||
|
||||
switch_safe_free(data_copy);
|
||||
}
|
||||
|
||||
|
||||
@@ -2907,6 +2907,12 @@ SWITCH_DECLARE(void) switch_ivr_delay_echo(switch_core_session_t *session, uint3
|
||||
interval = read_impl.microseconds_per_packet / 1000;
|
||||
//samples = switch_samples_per_packet(read_impl.samples_per_second, interval);
|
||||
|
||||
if (delay_ms < interval * 2) {
|
||||
delay_ms = interval * 2;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Minimum possible delay for this codec (%d) has been chosen\n", delay_ms);
|
||||
}
|
||||
|
||||
|
||||
qlen = delay_ms / (interval) / 2;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting delay to %dms (%d frames)\n", delay_ms, qlen);
|
||||
jb = stfu_n_init(qlen, qlen, read_impl.samples_per_packet, read_impl.samples_per_second, 0);
|
||||
|
||||
@@ -63,7 +63,7 @@ static void *SWITCH_THREAD_FUNC video_bridge_thread(switch_thread_t *thread, voi
|
||||
|
||||
if (!switch_stristr("loopback", source) && !switch_stristr("loopback", b_source)) {
|
||||
switch_channel_set_flag(channel, CF_VIDEO_PASSIVE);
|
||||
switch_channel_set_flag(b_channel, CF_VIDEO_PASSIVE);
|
||||
//switch_channel_set_flag(b_channel, CF_VIDEO_PASSIVE);
|
||||
}
|
||||
|
||||
switch_core_session_refresh_video(vh->session_a);
|
||||
@@ -94,7 +94,7 @@ static void *SWITCH_THREAD_FUNC video_bridge_thread(switch_thread_t *thread, voi
|
||||
}
|
||||
|
||||
switch_channel_clear_flag(channel, CF_VIDEO_PASSIVE);
|
||||
switch_channel_clear_flag(b_channel, CF_VIDEO_PASSIVE);
|
||||
//switch_channel_clear_flag(b_channel, CF_VIDEO_PASSIVE);
|
||||
|
||||
switch_core_session_kill_channel(vh->session_b, SWITCH_SIG_BREAK);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(vh->session_a), SWITCH_LOG_DEBUG, "%s video thread ended.\n", switch_channel_get_name(channel));
|
||||
@@ -624,7 +624,8 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
|
||||
if (vid_thread) {
|
||||
switch_status_t st;
|
||||
|
||||
if (vh.up) {
|
||||
if (vh.up == 1) {
|
||||
vh.up = -1;
|
||||
switch_core_session_kill_channel(session_a, SWITCH_SIG_BREAK);
|
||||
switch_core_session_kill_channel(session_b, SWITCH_SIG_BREAK);
|
||||
}
|
||||
|
||||
+13
-4
@@ -3126,9 +3126,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_deactivate_jitter_buffer(switch_rtp_t
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
READ_INC(rtp_session);
|
||||
stfu_n_destroy(&rtp_session->jb);
|
||||
READ_DEC(rtp_session);
|
||||
rtp_session->flags[SWITCH_RTP_FLAG_KILL_JB]++;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -3638,6 +3636,9 @@ SWITCH_DECLARE(void) switch_rtp_set_flag(switch_rtp_t *rtp_session, switch_rtp_f
|
||||
rtp_session->autoadj_window = 20;
|
||||
rtp_session->autoadj_tally = 0;
|
||||
rtp_flush_read_buffer(rtp_session, SWITCH_RTP_FLUSH_ONCE);
|
||||
if (rtp_session->jb) {
|
||||
stfu_n_reset(rtp_session->jb);
|
||||
}
|
||||
} else if (flag == SWITCH_RTP_FLAG_NOBLOCK && rtp_session->sock_input) {
|
||||
switch_socket_opt_set(rtp_session->sock_input, SWITCH_SO_NONBLOCK, TRUE);
|
||||
}
|
||||
@@ -4255,6 +4256,14 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
|
||||
switch_swap_linear((int16_t *)RTP_BODY(rtp_session), (int) *bytes - rtp_header_len);
|
||||
}
|
||||
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_KILL_JB]) {
|
||||
rtp_session->flags[SWITCH_RTP_FLAG_KILL_JB] = 0;
|
||||
if (rtp_session->jb) {
|
||||
stfu_n_destroy(&rtp_session->jb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (rtp_session->jb && !rtp_session->pause_jb && rtp_session->recv_msg.header.version == 2 && *bytes) {
|
||||
if (rtp_session->recv_msg.header.m && rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
|
||||
!rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && !(rtp_session->rtp_bugs & RTP_BUG_IGNORE_MARK_BIT)) {
|
||||
@@ -4604,7 +4613,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
||||
pt = 0;
|
||||
}
|
||||
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) {
|
||||
if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && !rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA]) {
|
||||
pt = 100000;
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ SWITCH_DECLARE(uint32_t) switch_scheduler_add_task(time_t task_runtime,
|
||||
switch_assert(func);
|
||||
|
||||
if (task_runtime < now) {
|
||||
container->task.repeat = task_runtime;
|
||||
container->task.repeat = (uint32_t)task_runtime;
|
||||
task_runtime += now;
|
||||
}
|
||||
|
||||
|
||||
+56
-1
@@ -1273,7 +1273,7 @@ static int get_netmask(struct sockaddr_in *me, int *mask)
|
||||
struct sockaddr_in *s = (struct sockaddr_in *) i->ifa_addr;
|
||||
struct sockaddr_in *m = (struct sockaddr_in *) i->ifa_netmask;
|
||||
|
||||
if (s && m && s->sin_addr.s_addr == me->sin_addr.s_addr) {
|
||||
if (s && m && s->sin_family == AF_INET && s->sin_addr.s_addr == me->sin_addr.s_addr) {
|
||||
*mask = m->sin_addr.s_addr;
|
||||
freeifaddrs(ifaddrs);
|
||||
return 0;
|
||||
@@ -1580,6 +1580,61 @@ SWITCH_DECLARE(switch_status_t) switch_find_local_ip(char *buf, int len, int *ma
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GETIFADDRS
|
||||
# include <ifaddrs.h>
|
||||
# include <net/if.h>
|
||||
#endif
|
||||
SWITCH_DECLARE(switch_status_t) switch_find_interface_ip(char *buf, int len, int *mask, const char *ifname, int family)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
#ifdef HAVE_GETIFADDRS
|
||||
|
||||
struct ifaddrs *addrs, *addr;
|
||||
|
||||
getifaddrs(&addrs);
|
||||
for(addr = addrs; addr; addr = addr->ifa_next)
|
||||
{
|
||||
if (!(addr->ifa_flags & IFF_UP)) continue; // Address is not UP
|
||||
if (!addr->ifa_addr) continue; // No address set
|
||||
if (!addr->ifa_netmask) continue; // No netmask set
|
||||
if (family != AF_UNSPEC && addr->ifa_addr->sa_family != family) continue; // Not the address family we're looking for
|
||||
if (strcmp(addr->ifa_name, ifname)) continue; // Not the interface we're looking for
|
||||
|
||||
switch(addr->ifa_addr->sa_family) {
|
||||
case AF_INET:
|
||||
inet_ntop(AF_INET, &( ((struct sockaddr_in*)(addr->ifa_addr))->sin_addr ), buf, len - 1);
|
||||
break;
|
||||
case AF_INET6:
|
||||
inet_ntop(AF_INET6, &( ((struct sockaddr_in6*)(addr->ifa_addr))->sin6_addr ), buf, len - 1);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mask && addr->ifa_netmask->sa_family == AF_INET) {
|
||||
*mask = ((struct sockaddr_in*)(addr->ifa_addr))->sin_addr.s_addr;
|
||||
}
|
||||
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
break;
|
||||
}
|
||||
freeifaddrs(addrs);
|
||||
|
||||
#elif defined(__linux__)
|
||||
|
||||
// TODO Not implemented, contributions welcome.
|
||||
|
||||
#elif defined(WIN32)
|
||||
|
||||
// TODO Not implemented, contributions welcome.
|
||||
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_time_t) switch_str_time(const char *in)
|
||||
{
|
||||
switch_time_exp_t tm = { 0 };
|
||||
|
||||
Reference in New Issue
Block a user