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

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);
});
}

Related

How to get Status code for Trying and Ringing in JsSip

How to get Status code like 100 and 180 from response when i call with any number from below response in my console.console output for my call response as below so how to get status code for trying and ringing when i call with nay number.
[1]: https://i.stack.imgur.com/YOTL8.png
also display resonse as below :
browser.js:183 JsSIP:WebSocketInterface received WebSocket message +13s
browser.js:183 JsSIP:Transport received text message:INVITE sip:rpj7...#127.0.0.1:55702;transport=WS SIP/2.0
Via: SIP/2.0/WS 127.0.0.1:8088;rport;branch=z9hG4bKPjacdc2b28-994d-49de-b3af-f3f7740afb93;alias
From: "F200" <sip:2...#XXXXX.com>;tag=95bffc6b-992b-48dd-83e1-23a2473e271e
To: <sip:rpj7...#127.0.0.1>
Contact: <sip:aste...#XXXXX.com:5060;transport=ws>
Call-ID: 3290aa94-d410-4bb5-ad10-b72e9a05ce04
CSeq: 3467 INVITE
Allow: OPTIONS, INVITE, ACK, BYE, CANCEL, UPDATE, PRACK, REGISTER, SUBSCRIBE, NOTIFY, PUBLISH, MESSAGE, REFER
Supported: 100rel, replaces, norefersub
P-Asserted-Identity: "F200" <sip:2...#XXXXX.com>
Max-Forwards: 70
User-Agent: Asterisk PBX 16.8.0-7.5.1.rl.101706.4465cf5
Content-Type: application/sdp
Content-Length: 935
v=0
...trimmed ordinary-looking incoming SDP
a=mid:audio-0
+13s
browser.js:183 JsSIP:Transport send() +1ms
browser.js:183 JsSIP:Transport sending message:SIP/2.0 100 Trying
... trimmed 100 trying body....
+0ms
browser.js:183 JsSIP:WebSocketInterface send() +6ms
browser.js:183 JsSIP:RTCSession new +3m
browser.js:183 JsSIP:RTCSession init_incoming() +1ms
browser.js:183 JsSIP:Dialog new UAS dialog created with status EARLY +3m
browser.js:183 JsSIP:RTCSession newRTCSession() +0ms
App.js:348 {id: 0.5232762505149955, remoteExt: "800", time: 1591730563324, state: "incoming", session: RTCSession}
browser.js:183 JsSIP:Transport send() +3ms
browser.js:183 JsSIP:Transport sending message:SIP/2.0 180 Ringing
... TRIMMED 180 Ringing body ....
Content-Length: 0
+0ms
browser.js:183 JsSIP:WebSocketInterface send() +3ms
browser.js:183 JsSIP:RTCSession session progress +2ms
browser.js:183 JsSIP:RTCSession emit "progress" +0ms
.... session.answer called here ...
browser.js:183 JsSIP:RTCSession answer() +501ms
browser.js:183 JsSIP:Dialog dialog 3290aa94-d410-4bb5-ad10-b72e9a05ce04sgb1kgc5mc95bffc6b-992b-48dd-83e1-23a2473e271e changed to CONFIRMED state +503ms
browser.js:183 JsSIP:RTCSession emit "peerconnection" +1ms
browser.js:183 JsSIP:WebSocketInterface received WebSocket message +2s
browser.js:183 JsSIP:Transport received text message:
+2s
common.js:114 JsSIP:ERROR:Parser parseMessage() | error parsing first line of SIP message: "" +15s
debug # common.js:114
./node_modules/jssip/lib-es5/Parser.js.exports.parseMessage # Parser.js:29
onTransportData # UA.js:950
_onData # Transport.js:303
_onMessage # WebSocketInterface.js:151
Try this:
this.coolPhone = new JsSIP.UA(configuration);
this.setUAEvent();
this.coolPhone.start();
setUAEvent(ua) {
this.coolPhone.on("newRTCSession", (e) => {
console.log("new rtc session", e);
const session = e.session;
session.on("progress", (message) => {
console.log("progress session ", message.response.status_code);
if (message.response.status_code === 180) //RINGING EXAMPLE
{
//put your code 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.

using curllib to send data to server

I am very new to all this http thing and I am trying to make communication with a server.
I need to write the client that post to server - I know what server returns but I am not sure how to send it the data:
I (the client) Post XML (binary format) to server at url: 192.168.2.111/senddata (i.e post /senddata) using HTTP.
Server response is:
TCP: [ACK] Seq=1274 Ack=504 Win=525088 Len=0
I.E here is the problem - the server does not reply with HTTP reply.
The protocol server uses after I send it the XML is TCP and this makes curl_easy_perform
to not return.
After server TCP reply in step 2, I-the client should send binary data in a loop to server using HTTP Continuation or non-HTTP traffic.
Server asynchronicity answers with
TCP: [ACK] Seq=1274 Ack=3424 Win=522176 Len=0
for each binary data sending .
So to send the XML in step 1, I use
curl_easy_setopt(mCurlHndl, CURLOPT_URL, "192.168.2.111");
curl_easy_setopt(mCurlHndl, CURLOPT_CUSTOMREQUEST, "POST /senddata");
curl_easy_setopt(mCurlHndl, CURLOPT_POST, 1L);
curl_easy_setopt(mCurlHndl, CURLOPT_POSTFIELDS, sXML.c_str());
curl_easy_setopt(mCurlHndl, CURLOPT_POSTFIELDSIZE, sXML.length());
headers = curl_slist_append(headers, "Content-Type: application/octet-stream");
headers = curl_slist_append(headers, "Accept:");
headers = curl_slist_append(headers, (string("Content-Length: ") + string(to_string(sXML.length()))).c_str());
curl_easy_setopt(mCurlHndl, CURLOPT_HTTPHEADER, headers);
res = curl_easy_perform(mCurlHndl);
Server does send in reply the:
TCP: [ACK] Seq=1274 Ack=504 Win=525088 Len=0
(just with other seq/ack/win numbers of course).
OK, here starts the problems.
a. curl_easy_perform does not return since (I think) server reply was not HTTP, but TCP.
b. OK, lets say that i can bypass it giving Timeout
curl_easy_setopt(mCurlHndl, CURLOPT_TIMEOUT_MS, 1000);
But i just know that i am doing something wrong.
c. Lets say I gave the timeout, now in step 3 I need to send in a loop stream of data using HTTP Continuation or non-HTTP traffic.
I do not know how to do that since it should not be regular post again like in step 1.
It should be HTTP Continuation or non-HTTP traffic.
Sorry for my bad explanation but again it is from my very little experience in HTTP.
Seems that after step 1, server breaks that normal http connection rules and what I need to send it is the binary data in a loop but again, i do not know how to do step 2 and 3. I.E how to get the TCP ACK from server using curllib that I will know to move to step 3 and how to (step 3) send to server over the same connection (I think) the binary data in loop.
I want to add that servers returns what is supposed to return. in step 2 server should return the TCP: [ACK] Seq=1274 Ack=504 Win=525088 Len=0 since this is what server should do - this is that server protocol. It is not that i do not send it right (in step 1) and that is why it send TCP reply and not http.
Here is Wireshark log:
192.168.2.7 is the client (that works).
192.168.2.111 is the server.
in the first line (seq 9) the clinet post the binary xml (POST /senddata) and then the loop of binary data stream sending starts as you can see:
9 0.173574000 192.168.2.7 192.168.2.111 HTTP 380 POST /senddata HTTP/1.1 (application/octet-stream)
10 0.176611000 192.168.2.111 192.168.2.7 TCP 60 4089 > 53419 [ACK] Seq=1274 Ack=504 Win=525088 Len=0
11 0.182581000 192.168.2.111 192.168.2.7 UDP 90 Source port: 4020 Destination port: 4005
12 0.553367000 192.168.2.7 192.168.2.111 HTTP 1354 Continuation or non-HTTP traffic
13 0.553403000 192.168.2.7 192.168.2.111 HTTP 1354 Continuation or non-HTTP traffic
14 0.555539000 192.168.2.111 192.168.2.7 TCP 60 4089 > 53419 [ACK] Seq=1274 Ack=3424 Win=522176 Len=0
15 0.555698000 192.168.2.7 192.168.2.111 HTTP 1354 Continuation or non-HTTP traffic
16 0.555724000 192.168.2.7 192.168.2.111 HTTP 1354 Continuation or non-HTTP traffic
17 0.555724000 192.168.2.7 192.168.2.111 HTTP 1354 Continuation or non-HTTP traffic
18 0.555724000 192.168.2.7 192.168.2.111 HTTP 1354 Continuation or non-HTTP traffic
19 0.558870000 192.168.2.111 192.168.2.7 TCP 60 4089 > 53419 [ACK] Seq=1274 Ack=6344 Win=519248 Len=0
20 0.559033000 192.168.2.7 192.168.2.111 HTTP 1354 Continuation or non-HTTP traffic
..... and many other sends like seq 12 - seq 20 ........
How do i do something like this with curllib - this is my question.
Thanks again
You are not using curl correctly for sending an HTTP POST request. Try this instead:
curl_easy_setopt(mCurlHndl, CURLOPT_URL, "http://192.168.2.111/senddata");
curl_easy_setopt(mCurlHndl, CURLOPT_POST, 1L);
curl_easy_setopt(mCurlHndl, CURLOPT_POSTFIELDS, sXML.c_str());
curl_easy_setopt(mCurlHndl, CURLOPT_POSTFIELDSIZE, sXML.length());
struct curl_slist *headers = curl_slist_append(NULL, "Content-Type: application/octet-stream");
headers = curl_slist_append(headers, "Accept:");
curl_easy_setopt(mCurlHndl, CURLOPT_HTTPHEADER, headers);
res = curl_easy_perform(mCurlHndl);
curl_slist_free_all(headers);
// process reply using curl_easy_getinfo() and curl_easy_recv() as needed...
With that said, are you sure that you should be sending the Content-Type as application/octet-stream? Typically XML is posted using text/xml, application/xml, or other XML-related Content-Type so the server knows it is dealing with XML data. application/octet-stream refers to arbitrary binary data when its actual type is not known.
Also, setting the Accept header to a blank value basically means you do not accept any data in reply. Unless you want to accept only specific Content-Type reply types, or want to accept any data the server wants to send, then you should omit the Accept header.
Read RFC 2616 for the formal definition of the HTTTP protocol and how it works.
Update: since you are obviously dealing with a custom protocol and not standard HTTP, you cannot use curl_easy_perform() to send the HTTP request. You will have to enable the CURLOPT_CONNECT_ONLY option so curl_easy_perform() will only open the socket connection, and then use curl_easy_send() to send the actual request and subsequent binary data, eg:
CURLcode curl_send(CURL *curl, const void * buffer, size_t buflen)
{
size_t sent;
uint8_t *pbuf = (uint8_t*) buffer;
while (buflen > 0)
{
do
{
res = curl_easy_send(curl, pbuf, buflen, &sent);
}
while (res == CURLE_AGAIN);
if (res != CURLE_OK)
return res;
pbuf += sent;
buflen -= sent;
}
while (buflen > 0);
return CURLE_OK;
}
mCurlHndl = curl_easy_init();
...
curl_easy_setopt(mCurlHndl, CURLOPT_URL, "http://192.168.2.111");
curl_easy_setopt(mCurlHndl, CURLOPT_CONNECT_ONLY, 1);
res = curl_easy_perform(mCurlHndl);
if (res == CURLE_OK)
{
string req =
"POST /senddata HTTP/1.1\r\n"
"Content-Type: application/octet-stream\r\n"
"Content-Length: " + to_string(sXML.length()) + "\r\n"
"\r\n"
+ sXML;
res = curl_send(mCurlHndl, req.c_str(), req.length());
if (res !- CURLE_OK) ...
res = curl_send(mCurlHndl, ...binary data...);
if (res !- CURLE_OK) ...
res = curl_send(mCurlHndl, ...binary data...);
if (res !- CURLE_OK) ...
res = curl_send(mCurlHndl, ...binary data...);
if (res !- CURLE_OK) ...
...
}
...
curl_easy_cleanup(mCurlHndl);

Sip Servlet Creates Faulty Responses (Contact Field)

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")?

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!