Skip to content

Commit

Permalink
Merge branch 'master' into issue-1657
Browse files Browse the repository at this point in the history
* master:
  Updated RMS build to #43
  Patch to support nullable FinishOnKey for Recordings  This refer to #1886
  Patch for UserAgentManager to store all Contact header parameters in the Registration location This close #1887
  Patch for sequential dialing using Dial Action Url more than once. This close #1885
  • Loading branch information
Maria Farooq committed Feb 24, 2017
2 parents 3a57c52 + 552600b commit 6f5ca42
Show file tree
Hide file tree
Showing 12 changed files with 413 additions and 82 deletions.
2 changes: 1 addition & 1 deletion release/build.xml
Expand Up @@ -17,7 +17,7 @@
<property name="restcomm-sipservlets-as7.version" value="3.1.${sipservlets-build}"/>
<!--<property name="jain-sip-ri.version" value="7.0.3.190" />-->
<property name="restcomm-media.version" value="5.1.0"/>
<property name="restcomm-media.build" value="42"/>
<property name="restcomm-media.build" value="43"/>
<!--property name="mobicents-diameter.version" value="6.1.2.GA" /-->

<!-- mobicents SIP Servlets 7.x on JBoss AS7-->
Expand Down
Expand Up @@ -12,7 +12,7 @@ The *<Record>* verb records the caller's voice and returns to you the URL of a f
|action |relative or absolute URL |current document URL
|method |GET, POST |POST
|timeout |positive integer |5
|finishOnKey |any digit, #, * |1234567890*#
|finishOnKey |any digit, #, * or -1 to disable|1234567890*#
|maxLength |integer greater than 1 with the number of seconds to wait |3600 (1 hour)
|transcribe |true, false |false
|transcribeCallback |relative or absolute URL |none
Expand All @@ -33,7 +33,7 @@ The *<Record>* verb records the caller's voice and returns to you the URL of a f

* *method.* The 'method' attribute takes the value 'GET' or 'POST'. This tells RestComm whether to request the URL via HTTP GET or POST.
* *timeout.* The 'timeout' attribute tells RestComm to end the recording after a number of seconds of silence has passed.
* *finishOnKey.* The 'finishOnKey' attribute lets you choose a set of digits that end the recording when entered. For example, if you set 'finishOnKey' to '\#' and the caller presses '#', RestComm will immediately stop recording and submit 'RecordingUrl', 'RecordingDuration', and the '\#' as parameters in a request to the 'action' URL. The allowed values are the digits 0-9, '#' and '*'. Unlike <Gather>, you may specify more than one character as a 'finishOnKey' value.
* *finishOnKey.* The 'finishOnKey' attribute lets you choose a set of digits that end the recording when entered. For example, if you set 'finishOnKey' to '\#' and the caller presses '#', RestComm will immediately stop recording and submit 'RecordingUrl', 'RecordingDuration', and the '\#' as parameters in a request to the 'action' URL. The allowed values are the digits 0-9, '#', '\*' and '-1'. The default value is '1234567890*#' which means that any key will end the recording. The value '-1' is a special value that can be used to disable finishOnKey and never stop recording on a DTMF. Unlike <Gather>, you may specify more than one character as a 'finishOnKey' value but '-1' must be used alone.
* *maxLength.* The 'maxLength' attribute lets you set the maximum length for the recording in seconds.
* *transcribe.* The 'transcribe' attribute tells RestComm that you would like a text representation of the audio of the recording.
* *transcribeCallback.* The 'transcribeCallback' attribute is used in conjunction with the 'transcribe' attribute. It allows you to specify a URL to which RestComm will make an asynchronous POST request when the transcription is complete. This is not a request for RCML and the response will not change call flow, but the request will contain the standard RCML request parameters as well as 'TranscriptionStatus', 'TranscriptionText', 'TranscriptionUrl' and 'RecordingUrl'. If 'transcribeCallback' is specified, then there is no need to specify 'transcribe=true'. It is implied. If you specify 'transcribe=true' without a 'transcribeCallback', the completed transcription will be stored for you to retrieve later (see the REST API Transcriptions section), but RestComm will not asynchronously notify your application.
Expand All @@ -52,11 +52,11 @@ The *<Record>* verb records the caller's voice and returns to you the URL of a f
* *playBeep.* The 'playBeep' attribute allows you to toggle between playing a sound before the start of a recording.
* *Nesting.* The <Record> verb can not have any other verbs or nouns nested.

=== Examples
=== Examples
For an example of how to use the <Record> verb see below.

----
<Response>
<Record maxLength="30"/>
</Response>
----
----
Expand Up @@ -1654,11 +1654,13 @@ public void execute(final Object message) throws Exception {
if (attribute != null) {
finishOnKey = attribute.value();
if (finishOnKey != null && !finishOnKey.isEmpty()) {
if (!PATTERN.matcher(finishOnKey).matches()) {
final Notification notification = notification(WARNING_NOTIFICATION, 13613, finishOnKey
+ " is not a valid finishOnKey value");
notifications.addNotification(notification);
finishOnKey = "1234567890*#";
if (!finishOnKey.equals("-1")) {
if (!PATTERN.matcher(finishOnKey).matches()) {
final Notification notification = notification(WARNING_NOTIFICATION, 13613, finishOnKey
+ " is not a valid finishOnKey value");
notifications.addNotification(notification);
finishOnKey = "1234567890*#";
}
}
} else {
finishOnKey = "1234567890*#";
Expand Down
Expand Up @@ -857,6 +857,12 @@ private void onTagMessage(Object message) throws TransitionFailedException, Tran
fsm.transition(message, initializingCall);
}
} else if (Verbs.dial.equals(verb.name())) {
Attribute action = verb.attribute("action");
if (action != null && dialActionExecuted) {
//We have a new Dial verb that contains Dial Action URL again.
//We set dialActionExecuted to false in order to execute Dial Action again
dialActionExecuted = false;
}
dialRecordAttribute = verb.attribute("record");
fsm.transition(message, startDialing);
} else if (Verbs.fax.equals(verb.name())) {
Expand Down
Expand Up @@ -376,7 +376,11 @@ protected void record(final Object message) {
builder.setPreSpeechTimer(request.timeout());
builder.setPostSpeechTimer(request.timeout());
builder.setRecordingLength(request.length());
builder.setEndInputKey(request.endInputKey());
if (!request.endInputKey().equals("-1")) {
builder.setEndInputKey(request.endInputKey());
} else {
builder.setEndInputKey("null");
}
builder.setRecordingId(request.destination());
this.lastEvent = AUMgcpEvent.aupr;
stop(lastEvent);
Expand Down
Expand Up @@ -19,34 +19,11 @@
*/
package org.restcomm.connect.telephony.ua;

import static java.lang.Integer.parseInt;
import static javax.servlet.sip.SipServlet.OUTBOUND_INTERFACES;
import static javax.servlet.sip.SipServletResponse.SC_OK;
import static javax.servlet.sip.SipServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED;
import static javax.servlet.sip.SipServletResponse.SC_UNAUTHORIZED;
import static org.restcomm.connect.commons.util.HexadecimalUtils.toHex;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.sip.Address;
import javax.servlet.sip.Parameterable;
import javax.servlet.sip.ServletParseException;
import javax.servlet.sip.SipApplicationSession;
import javax.servlet.sip.SipFactory;
import javax.servlet.sip.SipServletMessage;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.SipSession;
import javax.servlet.sip.SipURI;

import akka.actor.ActorRef;
import akka.actor.ReceiveTimeout;
import akka.actor.UntypedActor;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import org.apache.commons.configuration.Configuration;
import org.joda.time.DateTime;
import org.restcomm.connect.commons.configuration.RestcommConfiguration;
Expand All @@ -62,11 +39,32 @@
import org.restcomm.connect.telephony.api.Hangup;
import org.restcomm.connect.telephony.api.UserRegistration;

import akka.actor.ActorRef;
import akka.actor.ReceiveTimeout;
import akka.actor.UntypedActor;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.sip.Address;
import javax.servlet.sip.Parameterable;
import javax.servlet.sip.ServletParseException;
import javax.servlet.sip.SipApplicationSession;
import javax.servlet.sip.SipFactory;
import javax.servlet.sip.SipServletMessage;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.SipSession;
import javax.servlet.sip.SipURI;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import static java.lang.Integer.parseInt;
import static javax.servlet.sip.SipServlet.OUTBOUND_INTERFACES;
import static javax.servlet.sip.SipServletResponse.SC_OK;
import static javax.servlet.sip.SipServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED;
import static javax.servlet.sip.SipServletResponse.SC_UNAUTHORIZED;
import static org.restcomm.connect.commons.util.HexadecimalUtils.toHex;

/**
* @author quintana.thomas@gmail.com (Thomas Quintana)
Expand Down Expand Up @@ -490,11 +488,13 @@ private void register(final Object message) throws Exception {
final SipURI uri = (SipURI) contact.getURI();
final String ip = request.getInitialRemoteAddr();
final int port = request.getInitialRemotePort();

String transport = (uri.getTransportParam()==null?request.getParameter("transport"):uri.getTransportParam()); //Issue #935, take transport of initial request-uri if contact-uri has no transport parameter
if (transport == null && !request.getInitialTransport().equalsIgnoreCase("udp")) {
//Issue1068, if Contact header or RURI doesn't specify transport, check InitialTransport from
transport = request.getInitialTransport();
}

boolean isLBPresent = false;
//Issue 306: https://telestax.atlassian.net/browse/RESTCOMM-306
final String initialIpBeforeLB = request.getHeader("X-Sip-Balancer-InitialRemoteAddr");
Expand All @@ -518,6 +518,17 @@ private void register(final Object message) throws Exception {
if (transport != null) {
buffer.append(";transport=").append(transport);
}

Iterator<String> extraParameterNames = uri.getParameterNames();
while (extraParameterNames.hasNext()) {
String paramName = extraParameterNames.next();
String paramValue = uri.getParameter(paramName);
buffer.append(";");
buffer.append(paramName);
buffer.append("=");
buffer.append(paramValue);
}

final String address = buffer.toString();
// Prepare the response.
final SipServletResponse response = request.createResponse(SC_OK);
Expand Down
Expand Up @@ -3,6 +3,7 @@
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import gov.nist.javax.sip.address.SipUri;
import org.cafesip.sipunit.Credential;
import org.cafesip.sipunit.SipCall;
import org.cafesip.sipunit.SipPhone;
Expand Down Expand Up @@ -52,7 +53,7 @@

/**
* Test for clients with or without VoiceURL (Bitbucket issue 115). Clients without VoiceURL can dial anything.
*
*
* @author <a href="mailto:gvagenas@gmail.com">gvagenas</a>
*/
@RunWith(Arquillian.class)
Expand Down Expand Up @@ -187,7 +188,7 @@ public class ClientsDialTest {
private String pstnNumber = "+151261006100";

private String clientPassword = "qwerty1234RT";

// Maria is a Restcomm Client **without** VoiceURL. This Restcomm Client can dial anything.
private SipStack mariaSipStack;
private SipPhone mariaPhone;
Expand Down Expand Up @@ -412,7 +413,7 @@ public void testClientsCallEachOther() throws ParseException, InterruptedExcepti
assertTrue(!(mariaCall.getLastReceivedResponse().getStatusCode() >= 400));

assertTrue(dimitriCall.waitForAck(3000));

//Talk time ~ 3sec
Thread.sleep(3000);
dimitriCall.listenForDisconnect();
Expand All @@ -421,11 +422,11 @@ public void testClientsCallEachOther() throws ParseException, InterruptedExcepti
assertTrue(dimitriCall.waitForDisconnect(5 * 1000));
assertTrue(dimitriCall.respondToDisconnect());
long endTime = System.currentTimeMillis();

double totalTime = (endTime - startTime)/1000.0;
assertTrue(3.0 <= totalTime);
assertTrue(totalTime <= 4.0);

Thread.sleep(3000);

//Check CDR
Expand Down Expand Up @@ -711,7 +712,7 @@ public void testClientDialOutPstnWebRTCClientwithSDP() throws ParseException, In
public void testClientDialToInvalidNumber() throws ParseException, InterruptedException, InvalidArgumentException, SipException {
String invalidNumber = "+123456789";
SipPhone outboundProxy = georgeSipStack.createSipPhone("127.0.0.1", SipStack.PROTOCOL_UDP, 5080, "sip:"+invalidNumber+"@127.0.0.1:5070");

assertNotNull(mariaRestcommClientSid);
assertNotNull(dimitriRestcommClientSid);

Expand All @@ -732,7 +733,7 @@ public void testClientDialToInvalidNumber() throws ParseException, InterruptedEx

final SipCall georgeCall = outboundProxy.createSipCall();
georgeCall.listenForIncomingCall();

georgeCall.waitForIncomingCall(5 * 1000);
georgeCall.sendIncomingCallResponse(Response.NOT_FOUND, "Not-Found George", 3600);

Expand All @@ -750,7 +751,7 @@ public void testClientDialToInvalidNumber() throws ParseException, InterruptedEx

outboundProxy.dispose();
}

@Test
public void testClientDialOutPstnCancelBefore200() throws ParseException, InterruptedException {

Expand Down Expand Up @@ -859,6 +860,68 @@ public synchronized void testDialClientAlice() throws InterruptedException, Pars
assertTrue(aliceCall.respondToDisconnect());
}

@Test
public synchronized void testDialClientAliceWithExtraParamsAtContactHeader() throws InterruptedException, ParseException {
stubFor(get(urlPathEqualTo("/1111"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "text/xml")
.withBody(dialClientRcml)));

String extraParamName1 = "rc-id";
String extraParamValue1 = "7616";
String extraParamName2 = "my-param";
String extraParamValue2 = "test";
aliceContact = aliceContact+";"+extraParamName1+"="+extraParamValue1+";"+extraParamName2+"="+extraParamValue2;
// Phone2 register as alice
SipURI uri = aliceSipStack.getAddressFactory().createSipURI(null, "127.0.0.1:5080");
assertTrue(alicePhone.register(uri, "alice", "1234", aliceContact, 3600, 3600));

// Prepare second phone to receive call
SipCall aliceCall = alicePhone.createSipCall();
aliceCall.listenForIncomingCall();

// Create outgoing call with first phone
final SipCall georgeCall = georgePhone.createSipCall();
georgeCall.initiateOutgoingCall(georgeContact, "sip:1111@127.0.0.1:5080", null, body, "application", "sdp", null, null);
assertLastOperationSuccess(georgeCall);
assertTrue(georgeCall.waitOutgoingCallResponse(5 * 1000));
final int response = georgeCall.getLastReceivedResponse().getStatusCode();
assertTrue(response == Response.TRYING || response == Response.RINGING);

if (response == Response.TRYING) {
assertTrue(georgeCall.waitOutgoingCallResponse(5 * 1000));
assertEquals(Response.RINGING, georgeCall.getLastReceivedResponse().getStatusCode());
}

assertTrue(georgeCall.waitOutgoingCallResponse(5 * 1000));
assertEquals(Response.OK, georgeCall.getLastReceivedResponse().getStatusCode());

georgeCall.sendInviteOkAck();
assertTrue(!(georgeCall.getLastReceivedResponse().getStatusCode() >= 400));

assertTrue(aliceCall.waitForIncomingCall(30 * 1000));

SipUri ruri = (SipUri) aliceCall.getLastReceivedRequest().getRequestEvent().getRequest().getRequestURI();

assertEquals(extraParamValue1, ruri.getParameter(extraParamName1));
assertEquals(extraParamValue2, ruri.getParameter(extraParamName2));

assertTrue(aliceCall.sendIncomingCallResponse(Response.RINGING, "Ringing-Alice", 3600));
String receivedBody = new String(aliceCall.getLastReceivedRequest().getRawContent());
assertTrue(aliceCall.sendIncomingCallResponse(Response.OK, "OK-Alice", 3600, receivedBody, "application", "sdp", null,
null));
assertTrue(aliceCall.waitForAck(50 * 1000));

Thread.sleep(3000);

// hangup.
georgeCall.disconnect();

aliceCall.listenForDisconnect();
assertTrue(aliceCall.waitForDisconnect(30 * 1000));
assertTrue(aliceCall.respondToDisconnect());
}

private String dialWebRTCClientRcml = "<Response><Dial timeLimit=\"10\" timeout=\"10\"><Client>bob</Client></Dial></Response>";
@Test
Expand Down

0 comments on commit 6f5ca42

Please sign in to comment.