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?
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:
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
RTPManagerclass, I spotted some sample code in the documentation for setting up a unicast session and adapted it for my scenario. Here is the updatedstartMedia()method that works: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!