Sip Servlet Creates Faulty Responses (Contact Field) - sip

I'm trying to send a 200 OK response using a Sip Servlet after an Invite request by using request.createResponse(200).
Problem is that the Contact header comes out without the "username" part.
Why is this happening?
Relevant Code:
protected void doInvite(SipServletRequest arg0) throws ServletException, IOException {
SipServletResponse respRinging = arg0.createResponse(180);
respRinging.send();
SipServletResponse respOk = arg0.createResponse(200);
String sdpData = "v=0\r\n" +
"o=- 2 2 IN IP4 192.168.50.18\r\n" +
"s=Testing V1.0\r\n" +
"c=IN IP4 192.168.50.18\r\n" +
"t=0 0\r\n" +
"m=audio 63364 RTP/AVP 18 101\r\n" +
"a=fmtp:18 annexb=yes\r\n" +
"a=fmtp:101 0-15\r\n" +
"a=rtpmap:18 G729/8000\r\n" +
"a=rtpmap:101 telephone-event/8000\r\n" +
"a=sendrecv\r\n";
byte[] contents = sdpData.getBytes();
respOk.setContent(contents, arg0.getContentType());
respOk.send();
}
Created 200 Message:
%dMES%22=SIP/2.0 200 OK
Call-ID: ZDE4MzY3NzAzNjRlN2UwZDBmMGZlNDA1MTNlZWJiOWE.
CSeq: 1 INVITE
From: 6000 <sip:6000#192.168.50.18>;tag=d765eb39
To: 2451 <sip:2451#192.168.50.18>;tag=9020141091761795_local.1330939329531_17_16
Via: SIP/2.0/UDP 192.168.50.201:57332;branch=z9hG4bK-d8754z-cc352300a144627e-1---d8754z-;rport=57332;received=192.168.50.201
Content-Type: application/sdp
Content-Length: 221
Contact: sip:IP-HOST:5060;transport=udp
I expected the Contact URI to be sip:2451#IP-HOST:5060;transport=udp

I imagine that jain-sip is automatically populating the Contact URI. It's a perfectly valid Contact URI - the username is not required.
If you need to specify a particular URI, have you tried respOk.addHeader("Contact", "My sip:special#uri:5060")?

Related

Wrong Content-Type in response in IErrorHandler

I would like to send response to my service in JSON format. I catch my custom errors in my custom behavior:
void IErrorHandler.ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
XDocument errorMsg = XDocument.Parse("<errorMessage>" + error.Message + "</errorMessage>");
var jsonWriter = new JsonErrorBodyWriter(errorMsg);
fault = Message.CreateMessage(version, null, jsonWriter);
fault.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Json));
HttpResponseMessageProperty prop = new HttpResponseMessageProperty();
prop.StatusCode = HttpStatusCode.Unauthorized;
prop.Headers.Add("Content-Type", "application/json; charset=utf-8");
prop.Headers[HttpRequestHeader.ContentType] = "application/json; charset=utf-8";
--Tried different ways to achieve this
fault.Properties.Add(HttpResponseMessageProperty.Name, prop);
}
But I get wrong content-type in response. And also I couldn't manage to write any custom header like :
prop.Headers.Add("Test", "Value");
Reponse:
HTTP/1.1 401 Unauthorized
Content-Type: application/xml; charset=utf-8
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Wed, 30 Sep 2020 08:41:15 GMT
Content-Length: 37
{"description":"Autorization Failed"}
What is wrong in my code?

Docker API returns 200 OK then 400 BAD REQUEST

I am writing an API client for Docker. I understood from the documentation that the API is Restful/HTTP, yet if you connect to the local daemon you have to do it over the exposed unix socket.
It all seems to work, I open a socket, send an HTTP request (which respects the specification), I receive the expected response, but also a 400 BAD REQUEST response follows immediately.
Here is the request:
GET /info HTTP/1.1
Host: localhost
Accept: application/json
And here is what I get:
HTTP/1.1 200 OK
Api-Version: 1.30
Content-Type: application/json
Docker-Experimental: false
Ostype: linux
Server: Docker/17.06.1-ce (linux)
Date: Thu, 01 Feb 2018 18:53:18 GMT
Transfer-Encoding: chunked
892
{"ID":"6MGE:35TO:BI..." ...}
0
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
Connection: close
400 Bad Request
First, I figured that there is a bug on my side and I am somehow sending 2 requests, but I enabled debugging and followed the logs with sudo journalctl -fu docker.service and there is exactly one request received... at least one is logged, the GET /info. I've also debugged the code and 1 single request is sent.
Any hint is greatly appreciated!
Edit: here is the client's code:
final StringBuilder hdrs = new StringBuilder();
for(final Map.Entry<String, String> header : headers) {
hdrs.append(header.getKey() + ": " + header.getValue())
.append("\r\n");
}
final String request = String.format(
this.template(), method, home, hdrs, this.readContent(content)
);
final UnixSocketChannel channel = UnixSocketChannel.open(
new UnixSocketAddress(this.path)
);
final PrintWriter writer = new PrintWriter(
Channels.newOutputStream(channel)
);
writer.print(request);
writer.flush();
final InputStreamReader reader = new InputStreamReader(
Channels.newInputStream(channel)
);
CharBuffer result = CharBuffer.allocate(1024);
reader.read(result);
result.flip();
System.out.println("read from server: " + result.toString());
It seems like you have an extra CRLF between headers and body.
private String template() {
final StringBuilder message = new StringBuilder();
message
.append("%s %s HTTP/1.1\r\n")
.append("Host: localhost").append("\r\n")
.append("%s")
.append("\r\n").append("\r\n") //one of these is superfluous, as each header line ends with "\r\n" itself
.append("%s");
return message.toString();
}
Remove one append("\r\n") after headers and see what happens.
Fixed. Initially, I thought the problem was with the line endings (that they should have been \n instead of \r\n). Turns out, the 400 BAD REQUEST occured because the Connection: close header was missing, while the Request made was being closed right after receiving the response.
More details here.

SipJS and Freeswtch : Not able to receive phone call

Trying to call using Freeswitch and sipJS based SipPhone
I am using linphone at one end and sipjs at another , lin phone is able to call browser bases sipJs phone as its ringing but I am not able to receive call
Here Are My Logs, Unauthorized UA Seems to be a problem
Logs :
SIP/2.0 401 Unauthorized
Via: SIP/2.0/WS hntgukqjg2hc.invalid;branch=z9hG4bK8046067;received=100.74.156.116;rport=49654
From: "1000" <sip:1000#100.74.156.116>;tag=ab7a6dqv0k
To: "1000" <sip:1000#100.74.156.116>;tag=rS92SD9Zt6yDg
Call-ID: 52aucsstdsah4mf5499e6m
CSeq: 81 REGISTER
**User-Agent: FreeSWITCH-mod_sofia/1.5.15b~64bit**
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE
Supported: timer, path, replaces
WWW-Authenticate: Digest realm="100.74.156.116", nonce="f92c8e20-1906-4a61-b341-f6fd43e1be87", algorithm=MD5, qop="auth"
Content-Length: 0
sip.transport | sending WebSocket message:
REGISTER sip:100.74.156.116 SIP/2.0
Via: SIP/2.0/WS hntgukqjg2hc.invalid;branch=z9hG4bK521909
Max-Forwards: 70
To: "1000" <sip:1000#100.74.156.116>
From: "1000" <sip:1000#100.74.156.116>;tag=ab7a6dqv0k
Call-ID: 52aucsstdsah4mf5499e6m
CSeq: 82 REGISTER
Authorization: Digest algorithm=MD5, username="1000", realm="100.74.156.116", nonce="f92c8e20-1906-4a61-b341-f6fd43e1be87", uri="sip:100.74.156.116", response="357518a5593937845bf92f2e961f3b4c", qop=auth, cnonce="otm5sa1unt17", nc=00000001
Contact: <sip:c0e2i9qn#hntgukqjg2hc.invalid;transport=ws>;reg-id=1;+sip.instance="<urn:uuid:e7733a3b-3480-48e6-a065-5af261036403>";expires=130
Allow: ACK,CANCEL,INVITE,MESSAGE,BYE,OPTIONS,INFO,NOTIFY
Supported: path, gruu, outbound
User-Agent: SIP.js/0.7.3
Content-Length: 0
sip.js:2884 Fri Apr 15 2016 16:56:42 GMT+0530 (India Standard Time) | sip.transport | received WebSocket text message:
SIP/2.0 200 OK
Via: SIP/2.0/WS hntgukqjg2hc.invalid;branch=z9hG4bK521909;received=100.74.156.116;rport=49654
From: "1000" <sip:1000#100.74.156.116>;tag=ab7a6dqv0k
To: "1000" <sip:1000#100.74.156.116>;tag=S22UU8S3QFN0B
Call-ID: 52aucsstdsah4mf5499e6m
CSeq: 82 REGISTER
Contact: <sip:c0e2i9qn#hntgukqjg2hc.invalid;transport=ws>;expires=130
Date: Fri, 15 Apr 2016 11:26:42 GMT
User-Agent: FreeSWITCH-mod_sofia/1.5.15b~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE
Supported: timer, path, replaces
Content-Length: 0
sip.transport | received WebSocket text message:
NOTIFY sip:c0e2i9qn#hntgukqjg2hc.invalid;transport=ws SIP/2.0
Via: SIP/2.0/WS 100.74.156.116:5066;rport;branch=z9hG4bKmmBevgH597eDF
Route: <sip:c0e2i9qn#100.74.156.116:49654>;transport=ws
Max-Forwards: 70
From: <sip:1000#100.74.156.116>;tag=tBvmX3a7mrBKQ
To: <sip:1000#100.74.156.116>
Call-ID: c51139ce-7d9f-1234-0faa-37dc5feb612c
CSeq: 90023737 NOTIFY
Contact: <sip:mod_sofia#100.74.156.116:5060>
User-Agent: FreeSWITCH-mod_sofia/1.5.15b~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE
Supported: timer, path, replaces
Event: message-summary
Allow-Events: talk, hold, conference, presence, as-feature-event, dialog, line-seize, call-info, sla, include-session-description, presence.winfo, message-summary, refer
Subscription-State: terminated;reason=noresource
Content-Type: application/simple-message-summary
Content-Length: 66
Messages-Waiting: no
Message-Account: sip:1000#100.74.156.116
sip.transport | sending WebSocket message:
SIP/2.0 405 Method Not Allowed
Via: SIP/2.0/WS 100.74.156.116:5066;rport;branch=z9hG4bKmmBevgH597eDF
To: <sip:1000#100.74.156.116>;tag=ao6rh9rc8h
From: <sip:1000#100.74.156.116>;tag=tBvmX3a7mrBKQ
Call-ID: c51139ce-7d9f-1234-0faa-37dc5feb612c
CSeq: 90023737 NOTIFY
Supported: outbound
User-Agent: SIP.js/0.7.3
Content-Length: 0
REGISTER sip:100.74.156.116 SIP/2.0
Via: SIP/2.0/WS hntgukqjg2hc.invalid;branch=z9hG4bK9236948
Max-Forwards: 70
To: "1000" <sip:1000#100.74.156.116>
From: "1000" <sip:1000#100.74.156.116>;tag=ab7a6dqv0k
Call-ID: 52aucsstdsah4mf5499e6m
CSeq: 83 REGISTER
Authorization: Digest algorithm=MD5, username="1000", realm="100.74.156.116", nonce="f92c8e20-1906-4a61-b341-f6fd43e1be87", uri="sip:100.74.156.116", response="357518a5593937845bf92f2e961f3b4c", qop=auth, cnonce="otm5sa1unt17", nc=00000001
Contact: <sip:c0e2i9qn#hntgukqjg2hc.invalid;transport=ws>;reg-id=1;+sip.instance="<urn:uuid:e7733a3b-3480-48e6-a065-5af261036403>";expires=130
Allow: ACK,CANCEL,INVITE,MESSAGE,BYE,OPTIONS,INFO,NOTIFY
Supported: path, gruu, outbound
User-Agent: SIP.js/0.7.3
Content-Length: 0
above is just registration logs and its registered fine with 200 OK.

How to read Call-Info Header from Invite Message using sipml5

I use sipml5 with freeswitch and I need to detect when call should be answered automatically. The only part where I can get it from is SIP Invite message:
recv=INVITE sip:username#IP:50598;transport=ws;intercom=true SIP/2.0
Via: SIP/2.0/WSS IP;branch=z9hG4bKd451.8dc49598935d4ebdf937de014cf1d922.0
From: "Device QuickCall"<sip:NUMBER#DOMAIN>;tag=68rtr6c12v9em
To: <sip:michaltesar2#IP:50598;transport=ws>
Contact: <sip:mod_sofia#IP:11000>
Call-ID: dcd8fb4d69f0850840a743c152f4f7358a21-quickcall
CSeq: 89383073 INVITE
Content-Type: application/sdp
Content-Length: 882
Record-Route: <sip:IP;transport=ws;r2=on;lr=on;ftag=68rtr6c12v9em>
Record-Route: <sip:IP;r2=on;lr=on;ftag=68rtr6c12v9em>
Via: SIP/2.0/UDP 37.157.194.240:11000;rport=11000;received=IP;branch=z9hG4bKSNmDFvya0ceaQ
Max-Forwards: 50
Call-Info: answer-after=0;answer-after=0
User-Agent: 2600hz
Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,MESSAGE,INFO,UPDATE,REGISTER,REFER,NOTIFY,PUBLISH,SUBSCRIBE
Supported: path,replaces
Allow-Events: talk,hold,conference,presence,as-feature-event,dialog,line-seize,call-info,sla,include-session-description,presence.winfo,message-summary,refer
Content-Disposition: session
Remote-Party-ID: privacy=off;party=calling;screen=yes;privacy=off
v=0
o=FreeSWITCH 1459415113 1459415114 IN IP4 37.157.194.240
s=FreeSWITCH
c=IN IP4 37.157.194.240
t=0 0
a=msid-semantic: WMS W2YlkINCSBwtCldHnD3FYpIuFQW9iaH5
m=audio 23162 RTP/SAVPF 0 101 13
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=fingerprint:sha-256 03:8E:7D:14:E6:88:F1:75:55:70:40:E5:7F:07:9F:9F:C5:38:43:59:FB:EF:4D:70:0C:C7:F7:24:FC:7B:54:AB
a=rtcp-mux
a=rtcp:23162 IN IP4 37.157.194.240
a=ssrc:1258116307 cname:2vgd3UFMl25Od8lq
a=ssrc:1258116307 msid:W2YlkINCSBwtCldHnD3FYpIuFQW9iaH5 a0
a=ssrc:1258116307 mslabel:W2YlkINCSBwtCldHnD3FYpIuFQW9iaH5
a=ssrc:1258116307 label:W2YlkINCSBwtCldHnD3FYpIuFQW9iaH5a0
a=ice-ufrag:CfWquvL0by0kyxfq
a=ice-pwd:SmtM6ZoiRjWVi8cKdZ1ykDom
a=candidate:8660741513 1 udp 659136 IP 23162 typ host generation 0
a=candidate:8660741513 2 udp 659136 IP 23162 typ host generation 0
a=ptime:20
My VOIP phone detects it from Call-Info header :
Call-Info: answer-after=0;answer-after=0
Is there any way how to access Call-Info header using sipml5?
I also needed to get a SIP header's value for something similar in a project using SIPml5.
What I did, is a bit of a hack, but it works: all SIP signaling messages are logged to browser console (if the debug level is set to "info").
So I found and changed that debug function in SIPml5 library to receive all the incoming SIP messages (regardless of the debug level). You can find the function, by searching for this: function tsk_utils_log_info.
The new function looks like:
function tsk_utils_log_info(s_msg){
if (s_msg.indexOf('recv=') === 0)
{
CatchWebrtcSignaling(s_msg);
}
common_public.PutToDebugLog(3, 'WRTC, EVENT, ' + s_msg);
if (window.console && (__i_debug_level >= 4)) {
window.console.info(s_msg);
}
}
Now I receive all incoming SIP messages in function CatchWebrtcSignaling(msg) where I can parse the message and get any SIP headers value.
You can either make this change in SIPml5-api.js file or you can download the source code from github, make the change and minify/build SIPml5-api.js, by executing "release.sh" from main directory.
in SIPml.js you have event with 'i_new_call' type
, in this event you have o_message variable, you can iterate over this o_message.ao_headers
var dispatchEvent = function (s_event_type) {
if (s_event_type) {
switch (s_event_type) {
case 'i_new_call':
case 'm_permission_requested':
case 'm_permission_accepted':
case 'm_permission_refused':
{
var oNewEvent = new SIPml.Stack.Event(s_event_type, e);
if (s_event_type == 'i_new_call') {
oNewEvent.o_event.o_message.ao_headers.forEach(function (o_header) {
window.console.error('header name '+ o_header.s_name+ 'value ' + o_header.s_value);
});
}

Asterisk stops transmitting RTP data

I am developing a SIP controller in Java using the NIST implementation of the JAIN SIP API.
I am having trouble making a call from my SIP controller to a softphone via Asterisk.
If I call the softphone directly (not via Asterisk) using its IP address and port number, everything works fine. The call gets established, the softphone hears the audio (RTP data) I send it, and I can receive the audio that it sends me.
However, when I call the same softphone via Asterisk, the call gets established, and I start to receive RTP data from the softphone (via Asterisk). Now, my send stream takes a little while to set up, but while it is being configured I receive the RTP data from the softphone. The problem is that as soon as my send stream is initialized and starts to transmit RTP data, I stop receiving RTP data from the softphone! The result is that after the call is established, I hear the softphone for half a second or a second at most, and then nothing. At this stage the softphone can hear my outgoing RTP-data, but I cannot hear it.
If I don't start transmitting any RTP data, I keep on receiving RTP data from the softphone. But as soon as I start transmitting, it stops coming!
In case it helps, here is the type of SIP-conversation that establishes the call (>> indicates an outgoing message and << indicates indicates an incoming message):
>> INVITE sip:301#asterisk SIP/2.0
Call-ID: 8b92ba1ca9c922bcd266dce086596ce4#10.0.85.3
CSeq: 1 INVITE
From: <sip:null>;tag=JqbJKA
To: <sip:301#asterisk>
Via: SIP/2.0/UDP 10.0.85.3:5060;branch=z9hG4bK34d24b3f748ac08a5ca46f500f110d38353436
Max-Forwards: 70
Contact: <sip:10.0.85.3:5060>
Route: <sip:10.0.84.30;lr>
Content-Type: application/sdp
Content-Length: 106
v=0
o=- 3515232260 3515232260 IN IP4 10.0.85.3
s=-
c=IN IP4 10.0.85.3
t=0 0
m=audio 42138 RTP/AVP 0
a=rtpmap:0 PCMU/8000
<< SIP/2.0 407 Proxy Authentication Required
Via: SIP/2.0/UDP 10.0.85.3:5060;branch=z9hG4bK34d24b3f748ac08a5ca46f500f110d38353436;received=10.0.85.3
From: <sip:null>;tag=JqbJKA
To: <sip:301#asterisk>;tag=as7077f414
Call-ID: 8b92ba1ca9c922bcd266dce086596ce4#10.0.85.3
CSeq: 1 INVITE
User-Agent: Asterisk PBX (switchvox)
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,SUBSCRIBE,NOTIFY
Contact: <sip:301#10.0.84.30>
Proxy-Authenticate: Digest realm="asterisk",nonce="4a1cbda4"
Content-Length: 0
>> INVITE sip:301#asterisk SIP/2.0
CSeq: 2 INVITE
From: <sip:303#asterisk>;tag=JqbJKA
To: <sip:301#asterisk>
Via: SIP/2.0/UDP 10.0.85.3:5060;branch=z9hG4bKd1870f50e9fbf883b3e64fa3ef75dda9353436
Max-Forwards: 70
Contact: <sip:10.0.85.3:5060>
Route: <sip:10.0.84.30;lr>
Proxy-Authorization: Digest username="303",realm="asterisk",nonce="4a1cbda4",response="249b2b7d7c0e7b54499c632ba410365c",algorithm=MD5,uri="sip:301#asterisk",nc=00000001
Call-ID: 8b92ba1ca9c922bcd266dce086596ce4#10.0.85.3
Content-Type: application/sdp
Content-Length: 106
v=0
o=- 3515232260 3515232260 IN IP4 10.0.85.3
s=-
c=IN IP4 10.0.85.3
t=0 0
m=audio 42138 RTP/AVP 0
a=rtpmap:0 PCMU/8000`
`<< SIP/2.0 100 Trying
Via: SIP/2.0/UDP 10.0.85.3:5060;branch=z9hG4bKd1870f50e9fbf883b3e64fa3ef75dda9353436;received=10.0.85.3
From: <sip:303#asterisk>;tag=JqbJKA
To: <sip:301#asterisk>
Call-ID: 8b92ba1ca9c922bcd266dce086596ce4#10.0.85.3
CSeq: 2 INVITE
User-Agent: Asterisk PBX (switchvox)
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,R EFER,SUBSCRIBE,NOTIFY
Contact: <sip:301#10.0.84.30>
Content-Length: 0
`<< SIP/2.0 180 Ringing
Via: SIP/2.0/UDP 10.0.85.3:5060;branch=z9hG4bKd1870f50e9fbf883b3e64fa3ef75dda9353436;received=10.0.85.3
From: <sip:303#asterisk>;tag=JqbJKA
To: <sip:301#asterisk>;tag=as00faa25e
Call-ID: 8b92ba1ca9c922bcd266dce086596ce4#10.0.85.3
CSeq: 2 INVITE
User-Agent: Asterisk PBX (switchvox)
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,SUBSCRIBE,NOTIFY
Contact: <sip:301#10.0.84.30>
Content-Length: 0`
<< SIP/2.0 200 OK
Via: SIP/2.0/UDP 10.0.85.3:5060;branch=z9hG4bKd1870f50e9fbf883b3e64fa3ef75dda9353436;received=10.0.85.3
From: <sip:303#asterisk>;tag=JqbJKA
To: <sip:301#asterisk>;tag=as00faa25e
Call-ID: 8b92ba1ca9c922bcd266dce086596ce4#10.0.85.3
CSeq: 2 INVITE
User-Agent: Asterisk PBX (switchvox)
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,SUBSCRIBE,NOTIFY
Contact: <sip:301#10.0.84.30>
Content-Type: application/sdp
Content-Length: 154
v=0
o=root 2593 2593 IN IP4 10.0.84.30
s=session
c=IN IP4 10.0.84.30
t=0 0
m=audio 10294 RTP/AVP 0
a=rtpmap:0 PCMU/8000
a=silenceSupp:off - - - -
>> ACK sip:301#10.0.84.30 SIP/2.0
Call-ID: 8b92ba1ca9c922bcd266dce086596ce4#10.0.85.3
CSeq: 2 ACK
Via: SIP/2.0/UDP 10.0.85.3:5060;branch=z9hG4bK7e16ebc0de9c6eaf901db0e2e58f495f353436
From: <sip:303#asterisk>;tag=JqbJKA
To: <sip:301#asterisk>;tag=as00faa25e
Max-Forwards: 70
Contact: <sip:10.0.85.3:5060>
Content-Length: 0
Here is the code that sets up the RTP-session. First some declarations:
private RTPManager sessionManager = null;
private Processor processor = null;
private SendStream sendStream;`
The following method is called first:
public void startMedia(String peerIp,int peerPort,int receivePort,String format) throws IOException,MediaException,InvalidSessionAddressException
{
stopMedia();
this.format = format;
RTPSessionMgr rtpSessionMgr = new RTPSessionMgr();
rtpSessionMgr.initSession(new SessionAddress(),null,0.05,0.25);
InetAddress localhost = InetAddress.getLocalHost();
SessionAddress localAddr = new SessionAddress(localhost,receivePort,localhost,receivePort + 1);
InetAddress destAddr = InetAddress.getByName(peerIp);
rtpSessionMgr.startSession(localAddr,localAddr,new SessionAddress(destAddr,peerPort,destAddr,peerPort + 1),null);
sessionManager = rtpSessionMgr;
for (ReceiveStreamListener nextListener : receiveStreamListeners)
sessionManager.addReceiveStreamListener(nextListener);
}
Then, to start playing the sound over RTP, this method is called:
public void transmitSound(DataSource ds) throws NoProcessorException,IOException,UnsupportedFormatException,NotRealizedError
{
stopTransmittingSound();
processor = Manager.createProcessor(ds);
for (ControllerListener nextListener : controllerListeners)
processor.addControllerListener(nextListener);
processor.addControllerListener(myControllerListener);
processor.configure();
}
Here is the controllerUpdate() method of the controller listener:
public void controllerUpdate(ControllerEvent event)
{
if (processor.getState()==Processor.Configured)
{
processor.setContentDescriptor(new ContentDescriptor(ContentDescriptor.RAW_RTP));
processor.getTrackControls()[0].setFormat(new AudioFormat(format,8000,8,1));
processor.realize();
}
else if (processor.getState()==Processor.Realized)
{
try
{
sendStream = sessionManager.createSendStream(processor.getDataOutput(),0);
sendStream.start();
processor.start();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (UnsupportedFormatException e)
{
e.printStackTrace();
}
catch (NotRealizedError e)
{
e.printStackTrace();
}
}
}
This is what basically happens after the ACK is sent:
I create an RTP-session for transmitting and listening.
I start initializing a processor for transmitting RTP.
In the meanwhile I receive lots of RTP-data.
The processor finishes initialization and I start sending RTP-data.
At this stage I stop receiving RTP-data if going through Asterisk. If calling a softphone directly, everything works fine.
Any ideas?
Are you sure your handling for send part of RTP is correct? According to my understanding there should be one socket fd both for sending and receiving. Are you creating new socket fd for send part and closing recv fd? Please check and reply
You can also have two socket fds one for receiving and another for sending. RTP RFC-3550 doesnt say anything about implementation.
you should try to add media attribute in your invite, if you're using ulaw too then you can add:
a=rtpmap:0 PCMU/8000
Also try with a simpler test, instead of calling a softphone call:
301,1,Answer
301,2,Echo
Echo will capture the rtp stream from your client and send it back to you. If everything works fine then you can make a call between 2 working softphones and compare the traces with your client.
Also if possible try to post your dialplan and both users configuration.
(samll tip: if you enable canreinvite=yes or directrtpsetup=yes for both users they will be able to exchange rtp stream directly between each other instead of using asterisk as bridge)
Sounds like Asterisk may be attempting to re-INVITE your call so that it flows directly between your SIP app and the softphone. The advantage of Asterisk doing that is it makes the media path more efficient, the Asterisk server will no longer be bridging the call media only the signalling. The disadvantage is it can cause problems getting the RTP through if there are NATs involved or if a SIP user agent didn't support re-INVITEs, which may be the case with yours.
If it is a re-INVITE issue then firstly you should be able to see the extra INVITE request arrive at your SIP app or on the Asterisk console using a SIP debug. Secondly you can stop Asterisk doing re-INVITEs by setting canreinvite=no on the SIP account you are using.
For the record, I've decided to try a different PBX. I've downloaded and installed the 3CX Phone System and with this PBX everything works perfectly!
Now, the client for the beta version uses Patton at his site, so I just hope that this problem is specific to our Asterisk setup, and that it won't manifest there.
I've finally solved this problem! It turns out that the problem was not with the SIP messages, but with the code that set up the RTP session. I'm still not quite sure what went wrong, but it seems as though this code only works when the softphone is called directly (that is, not through a PBX) or when the softphone is on the same IP-address as the PBX.
This is the erroneous code:
public void startMedia(String peerIp,int peerPort,int receivePort,String format) throws IOException,MediaException,InvalidSessionAddressException
{
stopMedia();
this.format = format;
RTPSessionMgr rtpSessionMgr = new RTPSessionMgr();
rtpSessionMgr.initSession(new SessionAddress(),null,0.05,0.25);
InetAddress localhost = InetAddress.getLocalHost();
SessionAddress localAddr = new SessionAddress(localhost,receivePort,localhost,receivePort + 1);
InetAddress destAddr = InetAddress.getByName(peerIp);
rtpSessionMgr.startSession(localAddr,localAddr,new SessionAddress(destAddr,peerPort,destAddr,peerPort + 1),null);
sessionManager = rtpSessionMgr;
for (ReceiveStreamListener nextListener : receiveStreamListeners)
sessionManager.addReceiveStreamListener(nextListener);
}
This code was adapted from a book on SIP programming in Java (I guess that in order to preserve the author's reputation, I should not share which book that is).
When I went to look at the javadoc of the RTPManager class, I spotted some sample code in the documentation for setting up a unicast session and adapted it for my scenario. Here is the updated startMedia() method that works:
public void startMedia(String peerIp,int peerPort,int receivePort,String format,int sampleRate,int sampleSizeInBits) throws IOException,MediaException,InvalidSessionAddressException
{
stopMedia();
this.format = format;
this.sampleRate = sampleRate;
this.sampleSizeInBits = sampleSizeInBits;
sessionManager = RTPManager.newInstance();
SessionAddress localAddress = new SessionAddress(InetAddress.getLocalHost(),receivePort);
sessionManager.initialize(localAddress);
for (ReceiveStreamListener nextListener : receiveStreamListeners)
sessionManager.addReceiveStreamListener(nextListener);
InetAddress ipAddress = InetAddress.getByName(peerIp);
SessionAddress remoteAddress = new SessionAddress(ipAddress,peerPort);
sessionManager.addTarget(remoteAddress);
}
As you can see this code - although it uses the same classes - is quite different than that which I found in the book (which makes it hard to determine what the problem was), but it works perfectly!