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
}
});
}
Related
I am using Alamofire to make an API request to insert user data to my database, if the user email is exist, the response will return
[Response]:
[Status Code]: 200
[Headers]:
Connection: Keep-Alive
Content-Length: 27
Content-Type: text/html; charset=UTF-8
Date: Thu, 22 Apr 2021 06:39:05 GMT
Keep-Alive: timeout=5, max=99
Server: Apache/2.4.25 (Debian)
[Body]:
Email address already exist
[Network Duration]: 0.013917088508605957s
[Serialization Duration]: 0.0s
[Result]: success(Optional(27 bytes))
and if user email is not exist, it will insert data to the database, and return nothing like this
(literally nothing, there's no character or whatsoever, just a blank page if I open the api in the web browser)
And here is the response
[Response]:
[Status Code]: 200
[Headers]:
Connection: Keep-Alive
Content-Length: 0
Content-Type: text/html; charset=UTF-8
Date: Thu, 22 Apr 2021 06:54:43 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.25 (Debian)
[Body]: None
[Network Duration]: 0.8882529735565186s
[Serialization Duration]: 0.0s
[Result]: success(nil)
Now I want to make a validation to check if user email is exist or not by checking the response body. if the response body is Email address already exist, it will display an error alert. and if response body is None, it will display a successful alert. My question is, how do I check if the response body is None? here is validation code
let parameters = ["USERNAME": "\(USERNAME)", "EMAIL": "\(EMAIL)", "FULL_NAME": "\(FULL_NAME)", "NO_TELEPON": "\(NO_TELEPON)", "PASSWORD": "\(PASSWORD)", "USER_TOKEN": "\(USER_TOKEN)"]
AF.request("http://172.16.5.56:8081/User/InsertNewUser", parameters: parameters).response{ response in
debugPrint(response)
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8){
print(utf8Text)
postResponse = utf8Text
if postResponse == "Email address already exist" {
self.haptics.notificationOccurred(.error)
self.activeAlert = .first
self.showAlert = true
}else if postResponse == "None"{ // This is not working
self.haptics.notificationOccurred(.success)
self.activeAlert = .second
self.showAlert = true
}
}
}
The response (as you shared) in fail-type case is:
[Response]:
[Status Code]: 200
[Headers]:
Connection: Keep-Alive
Content-Length: 0
Content-Type: text/html; charset=UTF-8
Date: Thu, 22 Apr 2021 06:54:43 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.25 (Debian)
[Body]: None
[Network Duration]: 0.8882529735565186s
[Serialization Duration]: 0.0s
[Result]: success(nil)
Shows [Result]: success(nil) which means the response.data is literally nil.
I propose the following solution:
Alamofire
.request("http://172.16.5.56:8081/User/InsertNewUser")
.response { (response) in
if let data = response.data,
let string = String(data: data, encoding: .utf8) {
if string == "Email address already exist" {
self.haptics.notificationOccurred(.error)
self.activeAlert = .first
self.showAlert = true
}
//else if ... {
//handle other cases
//}
} else {
self.haptics.notificationOccurred(.success)
self.activeAlert = .second
self.showAlert = true
}
}
NOTE: I would advise against direct string comparisons unless unavoidable.
Atleast agree on a common response template and ensure the responses are not prone to typos or silly mistakes.
#staticVoidMan has already provided a solution for your current backend setup. However, if you update your backend to return more appropriate responses, Alamofire can do a lot more for you automatically.
In short, you need to make your backend behave in a standard fashion following JSON API best practices. These include:
In the failure case, return a failure status code (probably 403), and a JSON payload describing the error.
In the success case, you could return a 201, which indicates the new user has been created, in which case you should include the new user object JSON in the response, or a 204, which is the proper status code for an empty response.
In these cases you can define proper Decodable payloads which Alamofire can parse for you, as well as a proper value for the empty responses, and Alamofire will ensure it's returned in the 204 case.
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.
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);
});
}
I'm currently working on my own IMAP server.
When i get a FETCH request for 3 mails and i send a response with 3 mails, the client does not seem to recognise my response. (my client reports that there is no mail)
This is the request and response (C is client, S is server):
C: 405 UID FETCH 4,3,1 (INTERNALDATE RFC822.SIZE FLAGS BODY.PEEK[HEADER.FIELDS (subject from date content-type to cc message-id references importance reply-to)])
S: * 3 FETCH (UID 4 RFC822.SIZE 332 INTERNALDATE "<date>" FLAGS (\Recent) BODY[HEADER.FIELDS (SUBJECT FROM DATE CONTENT-TYPE TO CC MESSAGE-ID REFERENCES IMPORTANCE REPLY-TO)] {317}
Subject: <subject>
From: <email>
Date: <date>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
To: <email>
CC: <email>
Message-ID: <messid>
Reply-To: <email>
)
S: * 2 FETCH (UID 3 RFC822.SIZE 731 INTERNALDATE "<date>" FLAGS (\Recent) BODY[HEADER.FIELDS (SUBJECT FROM DATE CONTENT-TYPE TO CC MESSAGE-ID REFERENCES IMPORTANCE REPLY-TO)] {231}
Subject: <subject>
From: <email>
Date: <date>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Message-ID: <messid>
Reply-To: <email>
)
S: * 1 FETCH (UID 1 RFC822.SIZE 400 INTERNALDATE "<date>" FLAGS (\Answered \Recent) BODY[HEADER.FIELDS (SUBJECT FROM DATE CONTENT-TYPE TO CC MESSAGE-ID REFERENCES IMPORTANCE REPLY-TO)] {252}
Subject: <subject>
From: <email>
Date: <date>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
To: <email>
Message-ID: <messid>
Reply-To: <email>
)
S: 405 OK UID FETCH completed
where (subject) is the actual subject, (email) are valid emailadresses, (date) is the date and (messid) is a unique message-id.
Does somebody see what i am doing wrong here. maybe i am sending the wrong response, or am i doing something else wrong?
can someone help me with this?
so far, anything else (login, list, search) works fine. if it is needed, i could send those requests/responses as well
thanx i advance.
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!