我正在使用Jain Sip,我的用例是这样的: 一个注册商,一个呼叫者和一个被呼叫者。 Caller和Callee在注册商处注册。然后呼叫者发起呼叫。 Invite到达我的被叫方但是当我尝试发送“RINGING”响应时,它无法到达我的来电者。
注册官:172.18.18.109:5060
来电者:172.18.18.52:5066
Callee:172.18.18.52:5067
这是我的代码:
呼叫者:
import mypackage.voip.model.ClientStatus;
import gov.nist.javax.sip.address.AddressFactoryImpl;
import gov.nist.javax.sip.header.HeaderFactoryImpl;
import gov.nist.javax.sip.message.MessageFactoryImpl;
import javax.sdp.*;
import javax.sip.*;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.*;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.*;
import static mypackage.voip.model.ClientStatus.*;
public class Caller implements SipListener {
private String myIpAddress = "172.18.18.52";
private String registrarIp = "172.18.18.109";
private int myPort = 5066;
private String myTransportProtocol = "UDP";
private String myUserName = "caller";
private String viaHostName = registrarIp;
private int viaHostPort = 5060;
private AddressFactoryImpl addressFactory;
private SipStack sipStack;
private SipProvider sipProvider = null;
private MessageFactoryImpl messageFactory;
private HeaderFactoryImpl headerFactory;
private ClientStatus clientStatus = DISCONNECTED;
private String myDomainName = "172.18.18.52";
private String viaHostBranch = "abcdefghi";
public Caller(String name, String ipAddress, int port, String protocol) {
this.myUserName = name;
this.myTransportProtocol = protocol;
this.myIpAddress = ipAddress;
this.myPort = port;
changeClientStatusTo(DISCONNECTED);
}
public void init() throws PeerUnavailableException, TooManyListenersException {
SipFactory sipFactory = SipFactory.getInstance();
Properties properties = new Properties();
properties.setProperty("javax.sip.STACK_NAME", myIpAddress + ":" + myPort);
sipStack = sipFactory.createSipStack(properties);
addressFactory = new AddressFactoryImpl();
messageFactory = new MessageFactoryImpl();
headerFactory = new HeaderFactoryImpl();
sipProvider = getSipProvider();
}
public void doRegistration(String registrarIp) throws ParseException, InvalidArgumentException {
if (startRegistration(registrarIp)) {
changeClientStatusTo(REGISTERING);
}
}
private SipProvider getSipProvider() {
try {
ListeningPoint listeningPoint = sipStack.createListeningPoint(myIpAddress, myPort, myTransportProtocol);
if (sipProvider != null)
return sipProvider;
sipProvider = sipStack.createSipProvider(listeningPoint);
sipProvider.addSipListener(this);
return sipProvider;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
private void changeClientStatusTo(ClientStatus newClientStatus) {
this.clientStatus = newClientStatus;
}
public Address getMyContactAddress() {
return createAddress(myUserName, myIpAddress, myPort);
}
private Address createAddress(String username, String hostname, int port) {
try {
return addressFactory.createAddress(String.format("%s <sip:%s@%s:%s;transport=%s>",
username,
username,
hostname,
port,
myTransportProtocol));
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
private boolean startRegistration(String registrarIpAddress) throws ParseException, InvalidArgumentException {
SipURI requestURI = addressFactory.createSipURI("sip:" + registrarIpAddress + ":5060");
CallIdHeader callIdHeader = headerFactory.createCallIdHeader("callID");
CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(2L, Request.REGISTER);
ContactHeader contactHeader = headerFactory.createContactHeader(getMyContactAddress());
ExpiresHeader expiresHeader = headerFactory.createExpiresHeader(217);
Address fromAddress = getMyContactAddress();
Address toAddress = fromAddress;
FromHeader fromHeader = headerFactory.createFromHeader(fromAddress, "tag");
ToHeader toHeader = headerFactory.createToHeader(toAddress, "tag");
List viaHeaders = Arrays.asList();
MaxForwardsHeader maxForwards = headerFactory.createMaxForwardsHeader(70);
Request register = messageFactory.createRequest(requestURI,
Request.REGISTER,
callIdHeader,
cSeqHeader,
fromHeader,
toHeader,
viaHeaders,
maxForwards);
register.addHeader(contactHeader);
register.addHeader(expiresHeader);
return sendRequest(register);
}
private boolean sendRequest(Request request) {
sipProvider = getSipProvider();
try {
ClientTransaction clientTransaction = sipProvider.getNewClientTransaction(request);
clientTransaction.sendRequest();
return true;
} catch (SipException e) {
e.printStackTrace();
}
return false;
}
private boolean sendInvite(Address addressToInvite) throws SdpException {
try {
CallIdHeader callIdHeader = headerFactory.createCallIdHeader("callID");
CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(System.currentTimeMillis() / 1000L, Request.INVITE);
Address fromAddress = getMySipAddress();
FromHeader fromHeader = headerFactory.createFromHeader(fromAddress, "meinTag");
ToHeader toHeader = headerFactory.createToHeader(addressToInvite, null);
ViaHeader viaHeader = headerFactory.createViaHeader(viaHostName,
viaHostPort,
myTransportProtocol,
viaHostBranch);
List viaHeaders = Arrays.asList(viaHeader);
Address sipAd = addressFactory.createAddress("sip:" + toHeader.getAddress().getDisplayName() + "@" + registrarIp);
MaxForwardsHeader maxForwards = headerFactory.createMaxForwardsHeader(70);
Request invite = messageFactory.createRequest(sipAd.getURI(),
Request.INVITE,
callIdHeader,
cSeqHeader,
fromHeader,
toHeader,
viaHeaders,
maxForwards);
AllowHeader allowHeader = headerFactory.createAllowHeader("PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS");
invite.addHeader(allowHeader);
ContactHeader contactHeader = headerFactory.createContactHeader(toHeader.getAddress());
invite.addHeader(contactHeader);
SessionDescription sessionDescription = SdpFactory.getInstance().createSessionDescription();
String sdpData =
"v=0\n" +
"o=Lautsprecher 13760799956958020 13760799956958020 IN IP4 172.18.18.52\n" +
"s=-\n" +
"c=IN IP4 172.18.18.52\n" +
"m=audio 49172 RTP/AVP 11\n" +
"a=rtpmap:11 L16/44100";
byte[] contents = sdpData.getBytes();
ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("application", "sdp");
invite.setContent(contents, contentTypeHeader);
return sendRequest(invite);
} catch (ParseException | InvalidArgumentException e) {
return false;
}
}
public Address getMySipAddress() {
return createSipUserAddress(myUserName, myDomainName);
}
private Address createSipUserAddress(String name, String domain) {
try {
return addressFactory.createAddress(String.format("%s <sip:%s@%s;transport=%s>",
name, name, domain, myTransportProtocol));
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
@Override
public void processRequest(RequestEvent requestEvent) {
}
@Override
public void processResponse(ResponseEvent responseEvent) {
Response response = responseEvent.getResponse();
String method = responseEvent.getClientTransaction().getRequest().getMethod();
int statusCode = responseEvent.getResponse().getStatusCode();
if (statusCode == 200 && method.equalsIgnoreCase("REGISTER")) {
changeClientStatusTo(REGISTERED);
}
if (statusCode == 100 && method.equalsIgnoreCase("INVITE")) {
changeClientStatusTo(TRYING);
}
if (statusCode == 180 && method.equalsIgnoreCase("INVITE")) {
changeClientStatusTo(RINGING);
}
if (statusCode == 200 && method.equalsIgnoreCase("INVITE")) {
// DO SOMETHING
}
}
@Override
public void processTimeout(TimeoutEvent timeoutEvent) { }
@Override
public void processIOException(IOExceptionEvent exceptionEvent) { }
@Override
public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) { }
@Override
public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) { }
}
被叫方:
import mypackage.voip.model.ClientStatus;
import gov.nist.javax.sip.address.AddressFactoryImpl;
import gov.nist.javax.sip.header.HeaderFactoryImpl;
import gov.nist.javax.sip.header.SIPHeaderNames;
import gov.nist.javax.sip.message.MessageFactoryImpl;
import javax.sip.*;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.*;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.TooManyListenersException;
import static mypackage.voip.model.ClientStatus.DISCONNECTED;
import static mypackage.voip.model.ClientStatus.INVITED;
import static mypackage.voip.model.ClientStatus.REGISTERING;
import static javax.sip.message.Response.OK;
import static javax.sip.message.Response.RINGING;
public class Callee implements SipListener {
private int myPort;
private String myIpAddress;
private String myUserName;
private ClientStatus clientStatus = DISCONNECTED;
private SipStack sipStack;
private SipProvider sipProvider = null;
private MessageFactoryImpl messageFactory;
private HeaderFactoryImpl headerFactory;
private AddressFactoryImpl addressFactory;
private String myTransportProtocol = "UDP";
public Callee(String name, String ip, int port, String protocol) {
this.myUserName = name;
this.myTransportProtocol = protocol;
this.myIpAddress = ip;
this.myPort = port;
changeClientStatusTo(DISCONNECTED);
}
void init() throws PeerUnavailableException, TooManyListenersException {
SipFactory sipFactory = SipFactory.getInstance();
Properties properties = new Properties();
properties.setProperty("javax.sip.STACK_NAME", myIpAddress + ":" + myPort);
addressFactory = new AddressFactoryImpl();
messageFactory = new MessageFactoryImpl();
headerFactory = new HeaderFactoryImpl();
sipProvider = getSipProvider();
}
@Override
public void processRequest(RequestEvent requestEvent) {
Request request = requestEvent.getRequest();
Header from = request.getHeader(SIPHeaderNames.FROM);
Header to = request.getHeader(SIPHeaderNames.TO);
Header contact = request.getHeader(SIPHeaderNames.CONTACT);
Header via = request.getHeader(SIPHeaderNames.VIA);
ServerTransaction serverTransactionId = requestEvent.getServerTransaction();
if (request.getMethod().equals(Request.INVITE)) {
processInvite(requestEvent);
} else if (request.getMethod().equals(Request.ACK)) {
// DO SOMETHING
} else if (request.getMethod().equals(Request.CANCEL)) {
// DO SOMETHING
} else if (request.getMethod().equals(Request.BYE)) {
// DO SOMETHING
}
else{
// DO SOMETHING
}
}
@Override
public void processResponse(ResponseEvent responseEvent) {
}
public void doRegistration(String registrarIp) throws ParseException, InvalidArgumentException {
if (startRegistration(registrarIp)) {
changeClientStatusTo(REGISTERING);
}
}
private void changeClientStatusTo(ClientStatus newClientStatus) {
this.clientStatus = newClientStatus;
}
private boolean startRegistration(String registrarIpAddress) throws ParseException, InvalidArgumentException {
CallIdHeader callIdHeader = headerFactory.createCallIdHeader("callID");
CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(System.currentTimeMillis() / 1000L, Request.REGISTER);
ContactHeader contactHeader = headerFactory.createContactHeader(getMyContactAddress());
ExpiresHeader expiresHeader = headerFactory.createExpiresHeader(217);
Address fromAddress = getMyContactAddress();
Address toAddress = fromAddress;
FromHeader fromHeader = headerFactory.createFromHeader(fromAddress, "tag");
ToHeader toHeader = headerFactory.createToHeader(toAddress, "tag");
List viaHeaders = Arrays.asList();
MaxForwardsHeader maxForwards = headerFactory.createMaxForwardsHeader(70);
SipURI requestURI = addressFactory.createSipURI("sip:" + registrarIpAddress + ":5060");
Request register = messageFactory.createRequest(requestURI,
Request.REGISTER,
callIdHeader,
cSeqHeader,
fromHeader,
toHeader,
viaHeaders,
maxForwards);
register.addHeader(contactHeader);
register.addHeader(expiresHeader);
return sendRequest(register);
}
private Address getMyContactAddress() {
return createAddress(myUserName, myIpAddress, myPort);
}
private boolean sendRequest(Request request) {
sipProvider = getSipProvider();
try {
ClientTransaction clientTransaction = sipProvider.getNewClientTransaction(request);
clientTransaction.sendRequest();
return true;
} catch (SipException e) {
e.printStackTrace();
}
return false;
}
private Address createAddress(String username, String hostname, int port) {
try {
return addressFactory.createAddress(String.format("%s <sip:%s@%s:%s;transport=%s>",
username,
username,
hostname,
port,
myTransportProtocol));
} catch (ParseException e) {
return null;
}
}
private void processInvite(RequestEvent requestEvent) {
try {
changeClientStatusTo(INVITED);
SipProvider sipProvider = (SipProvider) requestEvent.getSource();
Request request = requestEvent.getRequest();
ServerTransaction st = requestEvent.getServerTransaction();
if (st == null) {
st = sipProvider.getNewServerTransaction(request);
}
Response ringingResponse = messageFactory.createResponse(RINGING, request);
ToHeader toHeader = (ToHeader) ringingResponse.getHeader(ToHeader.NAME);
toHeader.setTag("foobar");
ringingResponse.removeHeader(ToHeader.NAME);
ringingResponse.addHeader(toHeader);
st.sendResponse(ringingResponse);
} catch (ParseException | InvalidArgumentException | SipException e) {
e.printStackTrace();
}
}
public ClientStatus getClientStatus() {
return clientStatus;
}
private SipProvider getSipProvider() {
try {
ListeningPoint listeningPoint = sipStack.createListeningPoint(myIpAddress, myPort, myTransportProtocol);
if (sipProvider != null)
return sipProvider;
sipProvider = sipStack.createSipProvider(listeningPoint);
sipProvider.addSipListener(this);
return sipProvider;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
@Override
public void processTimeout(TimeoutEvent timeoutEvent) {
}
@Override
public void processIOException(IOExceptionEvent exceptionEvent) {
}
@Override
public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
}
@Override
public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
}
}
修改
我为我的场景写了一个小测试:
import org.junit.Before;
import org.junit.Test;
import javax.sdp.SdpException;
import javax.sip.InvalidArgumentException;
import javax.sip.PeerUnavailableException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.util.TooManyListenersException;
import static mypackage.voip.model.ClientStatus.*;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.CoreMatchers.is;
public class CallerCalleeTest {
private String myIpAddress;
private String registrarIpAddress = "172.18.18.109";
private TestRegistrar testRegistrar;
@Test
public void testTwoClients() throws PeerUnavailableException, UnknownHostException, TooManyListenersException,
SdpException, ParseException, InvalidArgumentException {
Caller caller = createAndInitializeCaller("caller", myIpAddress, 5066);
caller.doRegistration(registrarIpAddress);
await().until(() -> caller.getClientStatus(), is(REGISTERED));
Callee callee = createAndInitializeCallee("callee", myIpAddress, 5067);
callee.doRegistration(registrarIpAddress);
await().until(() -> callee.getClientStatus(), is(REGISTERING));
// Start the call
caller.call("callee", myIpAddress + ":" + 5067);
await().until(() -> caller.getClientStatus(), is(WAIT_AFTER_INVITE));
await().until(() -> callee.getClientStatus(), is(INVITED));
}
@Before
public void setup() throws UnknownHostException, PeerUnavailableException, TooManyListenersException {
myIpAddress = InetAddress.getLocalHost().getHostAddress();
}
private static Caller createAndInitializeCaller(String username, String ipAddress, int port) throws
PeerUnavailableException, TooManyListenersException {
Caller classUnderTestUdp = new Caller(username, ipAddress, port, "UDP");
classUnderTestUdp.init();
return classUnderTestUdp;
}
private static Callee createAndInitializeCallee(String username, String ipAddress, int port) throws
PeerUnavailableException, TooManyListenersException {
Callee callee = new Callee(username, ipAddress, port, "UDP");
callee.init();
return callee;
}
}
注册官是siproxd