- move things here and there
git-svn-id: http://bigbluebutton.googlecode.com/svn/trunk@3015 af16638f-c34d-0410-8cfa-b39d5352b314
This commit is contained in:
parent
64089ef8f3
commit
2b01d06621
@ -5,7 +5,7 @@ import org.red5.server.api.IScope;
|
||||
import org.red5.server.api.service.IServiceCapableConnection;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public class RtmpConnection implements ScopeProvider {
|
||||
public class RtmpConnection implements ScopeProvider, SipUserAgentListener, SipRegisterAgentListener {
|
||||
private static Logger log = Red5LoggerFactory.getLogger( RtmpConnection.class, "sip" );
|
||||
|
||||
private final IServiceCapableConnection connection;
|
||||
@ -20,57 +20,56 @@ public class RtmpConnection implements ScopeProvider {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public void onCallIncoming(String source, String sourceName, String destination, String destinationName) {
|
||||
connection.invoke( "incoming",
|
||||
new Object[] { source, sourceName, destination, destinationName } );
|
||||
public void onNewIncomingCall(String source, String sourceName, String destination, String destinationName) {
|
||||
connection.invoke("incoming", new Object[] {source, sourceName, destination, destinationName});
|
||||
}
|
||||
|
||||
public void onUaCallRinging() {
|
||||
log.debug( "onUaCallRinging" );
|
||||
public void onOutgoingCallRemoteRinging() {
|
||||
log.debug("onOutgoingCallRemoteRinging");
|
||||
connection.invoke("callState", new Object[] {"onUaCallRinging"});
|
||||
}
|
||||
|
||||
public void onUaCallAccepted() {
|
||||
log.debug( "onUaCallAccepted" );
|
||||
public void onOutgoingCallAccepted() {
|
||||
log.debug("onOutgoingCallAccepted");
|
||||
connection.invoke("callState", new Object[] {"onUaCallAccepted"});
|
||||
}
|
||||
|
||||
public void onUaCallConnected(String playName, String publishName) {
|
||||
public void onCallConnected(String playName, String publishName) {
|
||||
log.debug( "SIP Call Connected" );
|
||||
connection.invoke("connected", new Object[] {playName, publishName});
|
||||
}
|
||||
|
||||
public void onUaCallTrasferred() {
|
||||
log.debug( "onUaCallTrasferred");
|
||||
public void onCallTrasferred() {
|
||||
log.debug("onCallTrasferred");
|
||||
connection.invoke("callState", new Object[] {"onUaCallTrasferred"});
|
||||
}
|
||||
|
||||
public void onUaCallCancelled() {
|
||||
log.debug( "onUaCallCancelled");
|
||||
public void onIncomingCallCancelled() {
|
||||
log.debug("onIncomingCallCancelled");
|
||||
connection.invoke("callState", new Object[] {"onUaCallCancelled"});
|
||||
}
|
||||
|
||||
public void onUaCallFailed() {
|
||||
log.debug( "onUaCallFailed");
|
||||
connection.invoke("callState", new Object[] {"onUaCallFailed" });
|
||||
public void onOutgoingCallFailed() {
|
||||
log.debug("onOutgoingCallFailed");
|
||||
connection.invoke("callState", new Object[] {"onUaCallFailed"});
|
||||
}
|
||||
|
||||
public void onUaCallClosed() {
|
||||
log.debug( "onUaCallClosed");
|
||||
public void onCallClosed() {
|
||||
log.debug("onCallClosed");
|
||||
connection.invoke("callState", new Object[] {"onUaCallClosed"});
|
||||
}
|
||||
|
||||
public void onUaRegistrationSuccess(String result) {
|
||||
public void onRegistrationSuccess(String result) {
|
||||
log.debug( "SIP Registration success " + result );
|
||||
connection.invoke("registrationSucess", new Object[] {result});
|
||||
}
|
||||
|
||||
public void onUaRegistrationFailure(String result) {
|
||||
public void onRegistrationFailure(String result) {
|
||||
log.debug( "SIP Registration failure " + result );
|
||||
connection.invoke("registrationFailure", new Object[] {result});
|
||||
}
|
||||
|
||||
public void onUaUnregistedSuccess() {
|
||||
public void onUnregistedSuccess() {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
}
|
||||
|
420
bbb-voice/src/main/java/org/red5/app/sip/SipRegisterAgent.java
Normal file
420
bbb-voice/src/main/java/org/red5/app/sip/SipRegisterAgent.java
Normal file
@ -0,0 +1,420 @@
|
||||
package org.red5.app.sip;
|
||||
|
||||
import local.net.KeepAliveSip;
|
||||
import org.zoolu.net.SocketAddress;
|
||||
import org.zoolu.sip.address.*;
|
||||
import org.zoolu.sip.provider.SipStack;
|
||||
import org.zoolu.sip.provider.SipProvider;
|
||||
import org.zoolu.sip.header.*;
|
||||
import org.zoolu.sip.message.*;
|
||||
import org.zoolu.sip.transaction.TransactionClient;
|
||||
import org.zoolu.sip.transaction.TransactionClientListener;
|
||||
import org.zoolu.sip.authentication.DigestAuthentication;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.red5.logging.Red5LoggerFactory;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* Register User Agent. It registers (one time or periodically) a contact
|
||||
* address with a registrar server.
|
||||
*/
|
||||
public class SipRegisterAgent implements TransactionClientListener {
|
||||
private static Logger log = Red5LoggerFactory.getLogger(SipRegisterAgent.class, "sip");
|
||||
|
||||
private final Executor exec = Executors.newSingleThreadExecutor();
|
||||
private Runnable registerProcess;
|
||||
private volatile boolean continueRegistering = false;
|
||||
|
||||
/** The CallerID and CSeq that should be used during REGISTER method */
|
||||
private CallIdHeader registerCallID;
|
||||
private int registerCSeq;
|
||||
|
||||
private static final int MAX_ATTEMPTS = 3;
|
||||
|
||||
private Set<SipRegisterAgentListener> listeners = new HashSet<SipRegisterAgentListener>();
|
||||
|
||||
private SipProvider sipProvider;
|
||||
private NameAddress target; /** User's URI with the fully qualified domain name of the registrar server. */
|
||||
private String username;
|
||||
private String realm;
|
||||
private String passwd;
|
||||
private String nextNonce; /** Nonce for the next authentication. */
|
||||
private String qop; /** Qop for the next authentication. */
|
||||
private NameAddress contact; /** User's contact address. */
|
||||
private int expireTime; /** Expiration time. */
|
||||
private int renewTime;
|
||||
private int origRenewTime; // Change by lior.
|
||||
private int minRenewTime = 20;
|
||||
private int regFailRetryTime = 15;
|
||||
private boolean lastRegFailed = false; // Changed by Lior.
|
||||
private boolean regInprocess = false;
|
||||
private int attempts; /** Number of registration attempts. */
|
||||
private KeepAliveSip keepAlive; /** KeepAliveSip daemon. */
|
||||
|
||||
public SipRegisterAgent(SipProvider sipProvider, String targetUrl, String contactUrl) {
|
||||
init(sipProvider, targetUrl, contactUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new RegisterAgent with authentication credentials (i.e.
|
||||
* username, realm, and passwd).
|
||||
*/
|
||||
public SipRegisterAgent(SipProvider sipProvider, String targetUrl,
|
||||
String contactUrl, String username, String realm, String passwd) {
|
||||
|
||||
init(sipProvider, targetUrl, contactUrl);
|
||||
|
||||
// Authentication.
|
||||
this.username = username;
|
||||
this.realm = realm;
|
||||
this.passwd = passwd;
|
||||
}
|
||||
|
||||
private void init(SipProvider sipProvider, String targetUrl, String contactUrl) {
|
||||
this.sipProvider = sipProvider;
|
||||
this.target = new NameAddress(targetUrl);
|
||||
this.contact = new NameAddress(contactUrl);
|
||||
// this.expire_time=SipStack.default_expires;
|
||||
this.expireTime = 600;
|
||||
// Changed by Lior.
|
||||
this.renewTime = 600;
|
||||
this.origRenewTime = this.renewTime;
|
||||
this.keepAlive = null;
|
||||
// Authentication.
|
||||
this.username = null;
|
||||
this.realm = null;
|
||||
this.passwd = null;
|
||||
this.nextNonce = null;
|
||||
this.qop = null;
|
||||
this.attempts = 0;
|
||||
this.minRenewTime = 20;
|
||||
this.regFailRetryTime = 5;
|
||||
|
||||
this.registerCallID = null;
|
||||
this.registerCSeq = 0;
|
||||
}
|
||||
|
||||
public void addListener(SipRegisterAgentListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeListener(SipRegisterAgentListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
private boolean isPeriodicallyRegistering() {
|
||||
return continueRegistering;
|
||||
}
|
||||
|
||||
/** Registers with the registrar server. */
|
||||
public void register() {
|
||||
register(expireTime);
|
||||
}
|
||||
|
||||
/** Registers with the registrar server for <i>expire_time</i> seconds. */
|
||||
public void register(int expireTime) {
|
||||
attempts = 0;
|
||||
lastRegFailed = false;
|
||||
regInprocess = true;
|
||||
|
||||
if (expireTime > 0) this.expireTime = expireTime;
|
||||
|
||||
Message req = MessageFactory.createRegisterRequest(sipProvider, target, target, contact);
|
||||
|
||||
/*
|
||||
* MY_FIX: registerCallID contains the CallerID randomly generated in
|
||||
* the first REGISTER method. It will be reused for all successive
|
||||
* REGISTER invocations
|
||||
*/
|
||||
if (this.registerCallID == null)
|
||||
this.registerCallID = req.getCallIdHeader();
|
||||
else
|
||||
req.setCallIdHeader(this.registerCallID);
|
||||
|
||||
/*
|
||||
* MY_FIX: the registerCSeq must be unique for a given CallerID
|
||||
*/
|
||||
this.registerCSeq++;
|
||||
req.setCSeqHeader(new CSeqHeader(this.registerCSeq, SipMethods.REGISTER));
|
||||
|
||||
req.setExpiresHeader(new ExpiresHeader(String.valueOf(expireTime)));
|
||||
|
||||
if (nextNonce != null) {
|
||||
AuthorizationHeader authHeader = new AuthorizationHeader("Digest");
|
||||
authHeader.addUsernameParam(username);
|
||||
authHeader.addRealmParam(realm);
|
||||
authHeader.addNonceParam(nextNonce);
|
||||
authHeader.addUriParam(req.getRequestLine().getAddress().toString());
|
||||
authHeader.addQopParam(qop);
|
||||
|
||||
String response = (new DigestAuthentication(SipMethods.REGISTER,
|
||||
authHeader, null, passwd)).getResponse();
|
||||
authHeader.addResponseParam(response);
|
||||
|
||||
req.setAuthorizationHeader(authHeader);
|
||||
}
|
||||
|
||||
if (expireTime > 0)
|
||||
printLog("Registering contact " + contact + " (it expires in " + expireTime + " secs)");
|
||||
else
|
||||
printLog("Unregistering contact " + contact);
|
||||
|
||||
TransactionClient t = new TransactionClient(sipProvider, req, this);
|
||||
t.request();
|
||||
}
|
||||
|
||||
public void unregister() {
|
||||
if (isPeriodicallyRegistering()) {
|
||||
stopRegistering();
|
||||
}
|
||||
|
||||
register(0);
|
||||
sipProvider = null;
|
||||
}
|
||||
|
||||
public void unregisterall() {
|
||||
attempts = 0;
|
||||
Message req = MessageFactory.createRegisterRequest(sipProvider, target, target, null);
|
||||
req.setExpiresHeader(new ExpiresHeader(String.valueOf(0)));
|
||||
printLog("Unregistering all contacts");
|
||||
TransactionClient t = new TransactionClient(sipProvider, req, this);
|
||||
t.request();
|
||||
}
|
||||
|
||||
/**
|
||||
* Periodically registers with the registrar server.
|
||||
*
|
||||
* @param expireTime
|
||||
* expiration time in seconds
|
||||
* @param renewTime
|
||||
* renew time in seconds
|
||||
*/
|
||||
public void loopRegister(int expireTime, int renewTime) {
|
||||
this.expireTime = expireTime;
|
||||
this.renewTime = renewTime;
|
||||
|
||||
if (!isPeriodicallyRegistering()) {
|
||||
registerProcess = new Runnable() {
|
||||
public void run() {
|
||||
registerWithServer();
|
||||
}
|
||||
};
|
||||
exec.execute(registerProcess);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Periodically registers with the registrar server.
|
||||
*
|
||||
* @param expireTime
|
||||
* expiration time in seconds
|
||||
* @param renewTime
|
||||
* renew time in seconds
|
||||
* @param keepaliveTime
|
||||
* keep-alive packet rate (inter-arrival time) in milliseconds
|
||||
*/
|
||||
public void loopRegister(int expireTime, int renewTime, long keepaliveTime) {
|
||||
if (isPeriodicallyRegistering()) {
|
||||
stopRegistering();
|
||||
}
|
||||
|
||||
loopRegister(expireTime, renewTime);
|
||||
// Keep-alive.
|
||||
if (keepaliveTime > 0) {
|
||||
SipURL targetUrl = target.getAddress();
|
||||
String targetHost = targetUrl.getHost();
|
||||
int targePort = targetUrl.getPort();
|
||||
if (targePort < 0) targePort = SipStack.default_port;
|
||||
|
||||
SocketAddress socket = new SocketAddress(targetHost, targePort);
|
||||
keepAlive = new KeepAliveSip(sipProvider, socket, null, keepaliveTime);
|
||||
}
|
||||
}
|
||||
|
||||
public void stopRegistering() {
|
||||
continueRegistering = false;
|
||||
if (keepAlive != null)
|
||||
keepAlive.halt();
|
||||
}
|
||||
|
||||
// ***************************** run() *****************************
|
||||
|
||||
/** Run method */
|
||||
private void registerWithServer() {
|
||||
continueRegistering = true;
|
||||
try {
|
||||
while (continueRegistering) {
|
||||
register();
|
||||
// Changed by Lior.
|
||||
long waitCnt = 0;
|
||||
while (regInprocess) {
|
||||
Thread.sleep(1000);
|
||||
waitCnt += 1000;
|
||||
}
|
||||
|
||||
if (lastRegFailed) {
|
||||
printLog("Failed Registration stop try.");
|
||||
stopRegistering();
|
||||
} else
|
||||
Thread.sleep(renewTime * 1000 - waitCnt);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
printException(e);
|
||||
}
|
||||
continueRegistering = false;
|
||||
}
|
||||
|
||||
// **************** Transaction callback functions *****************
|
||||
|
||||
/** Callback function called when client sends back a failure response. */
|
||||
|
||||
/** Callback function called when client sends back a provisional response. */
|
||||
public void onTransProvisionalResponse(TransactionClient transaction, Message resp) {
|
||||
// do nothing...
|
||||
}
|
||||
|
||||
/** Callback function called when client sends back a success response. */
|
||||
public void onTransSuccessResponse(TransactionClient transaction, Message resp) {
|
||||
if (transaction.getTransactionMethod().equals(SipMethods.REGISTER)) {
|
||||
if (resp.hasAuthenticationInfoHeader()) {
|
||||
nextNonce = resp.getAuthenticationInfoHeader().getNextnonceParam();
|
||||
}
|
||||
StatusLine status = resp.getStatusLine();
|
||||
String result = status.getCode() + " " + status.getReason();
|
||||
|
||||
// Update the renew_time.
|
||||
// Changed by Lior.
|
||||
int expires = 0;
|
||||
|
||||
if (resp.hasExpiresHeader()) {
|
||||
expires = resp.getExpiresHeader().getDeltaSeconds();
|
||||
} else if (resp.hasContactHeader()) {
|
||||
// Look for the max expires - should be the latest.
|
||||
Vector contacts = resp.getContacts().getHeaders();
|
||||
for (int i = 0; i < contacts.size(); i++) {
|
||||
int exp_i = (new ContactHeader((Header) contacts.elementAt(i))).getExpires();
|
||||
if (exp_i / 2 > expires)
|
||||
expires = exp_i / 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (expires > 0 && expires < renewTime) {
|
||||
renewTime = expires;
|
||||
if (renewTime < minRenewTime) {
|
||||
printLog("Attempt to set renew time below min renew. Attempted="
|
||||
+ renewTime + " min=" + minRenewTime + "\r\nResponse=" + resp.toString());
|
||||
renewTime = minRenewTime;
|
||||
}
|
||||
} else if (expires > origRenewTime) {
|
||||
printLog("Attempt to set renew time above original renew. Attempted="
|
||||
+ expires + " origrenew=" + origRenewTime + "\r\nResponse=" + resp.toString());
|
||||
}
|
||||
|
||||
printLog("Registration success: ");
|
||||
regInprocess = false;
|
||||
|
||||
notifyListenersOfRegistrationSuccess(result);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListenersOfRegistrationSuccess(String result) {
|
||||
for (SipRegisterAgentListener listener : listeners) {
|
||||
listener.onRegistrationSuccess(result);
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback function called when client sends back a failure response. */
|
||||
public void onTransFailureResponse(TransactionClient transaction, Message resp) {
|
||||
printLog("onTransFailureResponse start: ");
|
||||
|
||||
if (transaction.getTransactionMethod().equals(SipMethods.REGISTER)) {
|
||||
StatusLine status = resp.getStatusLine();
|
||||
int code = status.getCode();
|
||||
if ((code == 401 && attempts < MAX_ATTEMPTS && resp.hasWwwAuthenticateHeader()
|
||||
&& resp.getWwwAuthenticateHeader().getRealmParam().equalsIgnoreCase(realm))
|
||||
|| (code == 407 && attempts < MAX_ATTEMPTS && resp.hasProxyAuthenticateHeader()
|
||||
&& resp.getProxyAuthenticateHeader().getRealmParam().equalsIgnoreCase(realm)))
|
||||
{
|
||||
printLog("onTransFailureResponse 401 or 407: ");
|
||||
|
||||
attempts++;
|
||||
Message req = transaction.getRequestMessage();
|
||||
req.setCSeqHeader(req.getCSeqHeader().incSequenceNumber());
|
||||
// * MY_FIX: registerCSeq counter must incremented.
|
||||
this.registerCSeq++;
|
||||
|
||||
WwwAuthenticateHeader wah;
|
||||
if (code == 401)
|
||||
wah = resp.getWwwAuthenticateHeader();
|
||||
else
|
||||
wah = resp.getProxyAuthenticateHeader();
|
||||
|
||||
String qopOptions = wah.getQopOptionsParam();
|
||||
// qop=(qopOptions!=null)? "auth" : null;
|
||||
|
||||
// Select a new branch - rfc3261 says should be new on each
|
||||
// request.
|
||||
ViaHeader via = req.getViaHeader();
|
||||
req.removeViaHeader();
|
||||
via.setBranch(SipProvider.pickBranch());
|
||||
req.addViaHeader(via);
|
||||
qop = (qopOptions != null) ? "auth" : null;
|
||||
|
||||
DigestAuthentication digest = new DigestAuthentication(SipMethods.REGISTER,
|
||||
req.getRequestLine().getAddress().toString(), wah, qop, null, username, passwd);
|
||||
|
||||
AuthorizationHeader ah;
|
||||
if (code == 401)
|
||||
ah = digest.getAuthorizationHeader();
|
||||
else
|
||||
ah = digest.getProxyAuthorizationHeader();
|
||||
|
||||
req.setAuthorizationHeader(ah);
|
||||
TransactionClient t = new TransactionClient(sipProvider, req, this);
|
||||
t.request();
|
||||
|
||||
} else {
|
||||
String result = code + " " + status.getReason();
|
||||
lastRegFailed = true;
|
||||
regInprocess = false;
|
||||
|
||||
printLog("Registration failure: " + result);
|
||||
notifyListenersOfRegistrationFailure(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListenersOfRegistrationFailure(String result) {
|
||||
for (SipRegisterAgentListener listener : listeners) {
|
||||
listener.onRegistrationFailure(result);
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback function called when client expires timeout. */
|
||||
public void onTransTimeout(TransactionClient transaction) {
|
||||
if (transaction.getTransactionMethod().equals(SipMethods.REGISTER)) {
|
||||
lastRegFailed = true;
|
||||
regInprocess = false;
|
||||
|
||||
printLog("Registration failure: No response from server.");
|
||||
notifyListenersOfRegistrationFailure( "Timeout");
|
||||
}
|
||||
}
|
||||
|
||||
// ****************************** Logs *****************************
|
||||
|
||||
void printLog(String str) {
|
||||
System.out.println("RegisterAgent: " + str);
|
||||
}
|
||||
|
||||
void printException(Exception e) {
|
||||
System.out.println("RegisterAgent Exception: " + e);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.red5.app.sip;
|
||||
|
||||
public interface SipRegisterAgentListener {
|
||||
/** When a UA has been successfully (un)registered. */
|
||||
public void onRegistrationSuccess(String result);
|
||||
/** When a UA failed on (un)registering. */
|
||||
public void onRegistrationFailure(String result);
|
||||
public void onUnregistedSuccess();
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
package org.red5.app.sip;
|
||||
|
||||
import org.zoolu.sip.address.*;
|
||||
import org.zoolu.sip.provider.*;
|
||||
import org.zoolu.net.SocketAddress;
|
||||
import org.slf4j.Logger;
|
||||
import org.red5.logging.Red5LoggerFactory;
|
||||
|
||||
public class SipUser implements SipUserAgentListener, RegisterAgentListener {
|
||||
public class SipUser {
|
||||
private static Logger log = Red5LoggerFactory.getLogger(SipUser.class, "sip");
|
||||
|
||||
private RtmpConnection rtmpConnection;
|
||||
@ -16,58 +15,33 @@ public class SipUser implements SipUserAgentListener, RegisterAgentListener {
|
||||
private SipProvider sipProvider;
|
||||
private String optOutboundProxy = null;
|
||||
private SipUserAgent userAgent;
|
||||
private RegisterAgent registerAgent;
|
||||
private RTMPUser rtmpUser;
|
||||
private String username;
|
||||
private String password;
|
||||
private String publishName;
|
||||
private String playName;
|
||||
private int sipPort;
|
||||
private int rtpPort;
|
||||
private SipRegisterAgent registerAgent;
|
||||
private String proxy;
|
||||
private String realm;
|
||||
|
||||
public SipUser(String userid, RtmpConnection connection, int sipPort, int rtpPort) {
|
||||
log.debug( "SIPUser Constructor: sip port " + sipPort + " rtp port:" + rtpPort );
|
||||
this.userid = userid;
|
||||
this.rtmpConnection = connection;
|
||||
this.sipPort = sipPort;
|
||||
this.rtpPort = rtpPort;
|
||||
|
||||
initializeSipStack();
|
||||
initializeSipProvider(sipPort);
|
||||
initializeUserProfile(rtpPort);
|
||||
}
|
||||
/*
|
||||
public boolean isRunning() {
|
||||
boolean resp = false;
|
||||
|
||||
try {
|
||||
resp = userAgent.isReceiverRunning();
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
resp = false;
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
*/
|
||||
public void login(String obproxy, String phone, String username, String password, String realm, String proxy) {
|
||||
log.debug( "SIPUser login" );
|
||||
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.proxy = proxy;
|
||||
this.optOutboundProxy = obproxy;
|
||||
this.realm = realm;
|
||||
|
||||
rtmpUser = new RTMPUser();
|
||||
|
||||
initializeSipStack();
|
||||
initializeSipProvider();
|
||||
initializeUserProfile(phone);
|
||||
sipProvider.setOutboundProxy(new SocketAddress(optOutboundProxy));
|
||||
setupUserProfile(username, password, realm, phone);
|
||||
initializeUserAgent();
|
||||
}
|
||||
|
||||
private void initializeUserAgent() {
|
||||
userAgent = new SipUserAgent(sipProvider, userProfile, this, rtmpConnection);
|
||||
userAgent.waitForIncomingCalls();
|
||||
userAgent = new SipUserAgent(sipProvider, userProfile, rtmpConnection);
|
||||
userAgent.addListener(rtmpConnection);
|
||||
userAgent.initialize();
|
||||
}
|
||||
|
||||
private void initializeSipStack() {
|
||||
@ -76,23 +50,24 @@ public class SipUser implements SipUserAgentListener, RegisterAgentListener {
|
||||
SipStack.log_path = "log";
|
||||
}
|
||||
|
||||
private void initializeSipProvider() {
|
||||
sipProvider = new SipProvider( null, sipPort );
|
||||
sipProvider.setOutboundProxy(new SocketAddress(optOutboundProxy));
|
||||
private void initializeSipProvider(int sipPort) {
|
||||
sipProvider = new SipProvider(null, sipPort);
|
||||
sipProvider.addSipProviderListener(new OptionMethodListener());
|
||||
}
|
||||
|
||||
private void initializeUserProfile(String phone) {
|
||||
private void setupUserProfile(String username, String password, String realm, String phone) {
|
||||
String fromURL = "\"" + phone + "\" <sip:" + phone + "@" + proxy + ">";
|
||||
|
||||
userProfile = new SipUserAgentProfile();
|
||||
userProfile.audioPort = rtpPort;
|
||||
userProfile.username = username;
|
||||
userProfile.username = username;
|
||||
userProfile.passwd = password;
|
||||
userProfile.realm = realm;
|
||||
userProfile.fromUrl = fromURL;
|
||||
userProfile.contactUrl = "sip:" + phone + "@" + sipProvider.getViaAddress();
|
||||
|
||||
}
|
||||
|
||||
private void initializeUserProfile(int rtpPort) {
|
||||
userProfile = new SipUserAgentProfile();
|
||||
userProfile.audioPort = rtpPort;
|
||||
|
||||
if ( sipProvider.getPort() != SipStack.default_port ) {
|
||||
userProfile.contactUrl += ":" + sipProvider.getPort();
|
||||
}
|
||||
@ -105,9 +80,10 @@ public class SipUser implements SipUserAgentListener, RegisterAgentListener {
|
||||
public void register() {
|
||||
log.debug( "SIPUser register" );
|
||||
if (sipProvider != null) {
|
||||
registerAgent = new RegisterAgent( sipProvider, userProfile.fromUrl, userProfile.contactUrl, username,
|
||||
userProfile.realm, password, this );
|
||||
loopRegister(userProfile.expires, userProfile.expires / 2, userProfile.keepaliveTime);
|
||||
registerAgent = new SipRegisterAgent(sipProvider, userProfile.fromUrl, userProfile.contactUrl,
|
||||
userProfile.username, userProfile.realm, userProfile.passwd);
|
||||
registerAgent.addListener(rtmpConnection);
|
||||
loopRegister(userProfile.expires, userProfile.expires/2, userProfile.keepaliveTime);
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,7 +124,7 @@ public class SipUser implements SipUserAgentListener, RegisterAgentListener {
|
||||
|
||||
public void close() {
|
||||
log.debug("SIPUser close1");
|
||||
try {
|
||||
try {
|
||||
hangup();
|
||||
unregister();
|
||||
new Thread().sleep(3000);
|
||||
@ -156,41 +132,26 @@ public class SipUser implements SipUserAgentListener, RegisterAgentListener {
|
||||
log.error("close: Exception:>\n" + e);
|
||||
}
|
||||
|
||||
try {
|
||||
log.debug("SIPUser provider.halt");
|
||||
sipProvider.halt();
|
||||
|
||||
} catch(Exception e) {
|
||||
log.error("close: Exception:>\n" + e);
|
||||
}
|
||||
rtmpConnection = null;
|
||||
log.debug("Stopping SipProvider");
|
||||
sipProvider.halt();
|
||||
}
|
||||
|
||||
public void accept() {
|
||||
log.debug( "SIPUser accept" );
|
||||
|
||||
if (userAgent != null) {
|
||||
try {
|
||||
userAgent.accept();
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
log.error( "SIPUser: accept - Exception:>\n" + e );
|
||||
}
|
||||
userAgent.accept();
|
||||
}
|
||||
}
|
||||
|
||||
public void hangup() {
|
||||
log.debug( "SIPUser hangup" );
|
||||
|
||||
if ( userAgent != null ) {
|
||||
if ( userAgent.call_state != UserAgent.UA_IDLE ) {
|
||||
userAgent.hangup();
|
||||
userAgent.waitForIncomingCalls();
|
||||
}
|
||||
if (userAgent != null) {
|
||||
userAgent.hangup();
|
||||
}
|
||||
|
||||
closeStreams();
|
||||
rtmpUser.stopStream();
|
||||
}
|
||||
|
||||
public void streamStatus( String status ) {
|
||||
@ -204,15 +165,12 @@ public class SipUser implements SipUserAgentListener, RegisterAgentListener {
|
||||
public void unregister() {
|
||||
log.debug( "SIPUser unregister" );
|
||||
|
||||
if ( registerAgent != null ) {
|
||||
if ( registerAgent.isRegistering() ) {
|
||||
registerAgent.halt();
|
||||
}
|
||||
if (registerAgent != null) {
|
||||
registerAgent.unregister();
|
||||
registerAgent = null;
|
||||
}
|
||||
|
||||
if ( userAgent != null ) {
|
||||
if (userAgent != null) {
|
||||
userAgent.hangup();
|
||||
}
|
||||
userAgent = null;
|
||||
@ -247,77 +205,6 @@ public class SipUser implements SipUserAgentListener, RegisterAgentListener {
|
||||
}
|
||||
|
||||
private void loopRegister( int expire_time, int renew_time, long keepalive_time ) {
|
||||
if ( registerAgent.isRegistering() ) {
|
||||
registerAgent.halt();
|
||||
}
|
||||
registerAgent.loopRegister( expire_time, renew_time, keepalive_time );
|
||||
}
|
||||
|
||||
public void onUaCallIncoming( SipUserAgent ua, NameAddress callee, NameAddress caller ) {
|
||||
String source = caller.getAddress().toString();
|
||||
String sourceName = caller.hasDisplayName() ? caller.getDisplayName() : "";
|
||||
String destination = callee.getAddress().toString();
|
||||
String destinationName = callee.hasDisplayName() ? callee.getDisplayName() : "";
|
||||
|
||||
log.debug( "onUaCallIncoming " + source + " " + destination);
|
||||
rtmpConnection.onCallIncoming(source, sourceName, destination, destinationName);
|
||||
}
|
||||
|
||||
public void onUaCallRinging( SipUserAgent ua ) {
|
||||
log.debug( "onUaCallRinging" );
|
||||
rtmpConnection.onUaCallRinging();
|
||||
}
|
||||
|
||||
public void onUaCallAccepted( SipUserAgent ua ) {
|
||||
log.debug( "onUaCallAccepted" );
|
||||
rtmpConnection.onUaCallAccepted();
|
||||
}
|
||||
|
||||
public void onUaCallConnected(SipUserAgent ua, String playName, String publishName) {
|
||||
log.debug( "SIP Call Connected" );
|
||||
rtmpConnection.onUaCallConnected(playName, publishName);
|
||||
}
|
||||
|
||||
public void onUaCallTrasferred( SipUserAgent ua ) {
|
||||
log.debug( "onUaCallTrasferred");
|
||||
rtmpConnection.onUaCallTrasferred();
|
||||
}
|
||||
|
||||
public void onUaCallCancelled( SipUserAgent ua ) {
|
||||
log.debug( "onUaCallCancelled");
|
||||
closeStreams();
|
||||
rtmpConnection.onUaCallCancelled();
|
||||
ua.waitForIncomingCalls();
|
||||
}
|
||||
|
||||
public void onUaCallFailed( SipUserAgent ua ) {
|
||||
log.debug( "onUaCallFailed");
|
||||
closeStreams();
|
||||
rtmpConnection.onUaCallFailed();
|
||||
ua.waitForIncomingCalls();
|
||||
}
|
||||
|
||||
|
||||
public void onUaCallClosed( SipUserAgent ua ) {
|
||||
log.debug( "onUaCallClosed");
|
||||
closeStreams();
|
||||
rtmpConnection.onUaCallClosed();
|
||||
ua.waitForIncomingCalls();
|
||||
}
|
||||
|
||||
public void onUaRegistrationSuccess( RegisterAgent ra, NameAddress target, NameAddress contact, String result ) {
|
||||
log.debug( "SIP Registration success " + result );
|
||||
rtmpConnection.onUaRegistrationSuccess(result);
|
||||
}
|
||||
|
||||
|
||||
public void onUaRegistrationFailure( RegisterAgent ra, NameAddress target, NameAddress contact, String result ) {
|
||||
log.debug( "SIP Registration failure " + result );
|
||||
rtmpConnection.onUaRegistrationFailure(result);
|
||||
}
|
||||
|
||||
|
||||
public void onUaUnregistedSuccess() {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ import org.slf4j.Logger;
|
||||
import org.red5.logging.Red5LoggerFactory;
|
||||
import org.zoolu.tools.Parser;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
public class SipUserAgent extends CallListenerAdapter {
|
||||
@ -23,136 +25,66 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
private ExtendedCall callTransfer;
|
||||
private CallStream callStream;
|
||||
private String localSession = null;
|
||||
private SipUserAgentListener listener = null;
|
||||
private Codec sipCodec = null;
|
||||
private final ScopeProvider scopeProvider;
|
||||
private Set<SipUserAgentListener> listeners = new HashSet<SipUserAgentListener>();
|
||||
|
||||
private static final String UA_IDLE = "IDLE"; /** UA_IDLE=0 */
|
||||
private static final String UA_INCOMING_CALL = "INCOMING_CALL"; /** UA_INCOMING_CALL=1 */
|
||||
private static final String UA_OUTGOING_CALL = "OUTGOING_CALL"; /** UA_OUTGOING_CALL=2 */
|
||||
private static final String UA_ONCALL = "ONCALL"; /** UA_ONCALL=3 */
|
||||
|
||||
/**
|
||||
* Call state
|
||||
* <P>
|
||||
* UA_IDLE=0, <BR>
|
||||
* UA_INCOMING_CALL=1, <BR>
|
||||
* UA_OUTGOING_CALL=2, <BR>
|
||||
* UA_ONCALL=3
|
||||
*/
|
||||
String call_state = UA_IDLE;
|
||||
|
||||
protected void changeStatus(String state) {
|
||||
call_state = state;
|
||||
private enum CallState {
|
||||
UA_IDLE(0), UA_INCOMING_CALL(1), UA_OUTGOING_CALL(2), UA_ONCALL(3);
|
||||
private final int state;
|
||||
CallState(int state) {this.state = state;}
|
||||
private int getState() {return state;}
|
||||
}
|
||||
|
||||
protected boolean statusIs(String state) {
|
||||
return call_state.equals(state);
|
||||
private CallState callState;
|
||||
|
||||
public SipUserAgent(SipProvider sipProvider, SipUserAgentProfile userProfile, ScopeProvider scopeProvider) {
|
||||
this.scopeProvider = scopeProvider;
|
||||
this.sipProvider = sipProvider;
|
||||
this.userProfile = userProfile;
|
||||
|
||||
// If no contact_url and/or from_url has been set, create it now.
|
||||
userProfile.initContactAddress(sipProvider);
|
||||
// Set local sdp.
|
||||
initSessionDescriptor();
|
||||
}
|
||||
|
||||
protected String getStatus() {
|
||||
return call_state;
|
||||
|
||||
public void addListener(SipUserAgentListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeListener(SipUserAgentListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
private void changeStatus(CallState state) {
|
||||
callState = state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the automatic answer time (default is -1 that means no auto accept
|
||||
* mode)
|
||||
*/
|
||||
public void setAcceptTime(int accept_time) {
|
||||
userProfile.acceptTime = accept_time;
|
||||
|
||||
public boolean isIdle() {
|
||||
return callState == CallState.UA_IDLE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the automatic hangup time (default is 0, that corresponds to manual
|
||||
* hangup mode)
|
||||
*/
|
||||
public void setHangupTime(int time) {
|
||||
userProfile.hangupTime = time;
|
||||
}
|
||||
|
||||
|
||||
/** Sets the redirection url (default is null, that is no redircetion) */
|
||||
public void setRedirection(String url) {
|
||||
userProfile.redirectTo = url;
|
||||
}
|
||||
|
||||
/** Sets the no offer mode for the invite (default is false) */
|
||||
public void setNoOfferMode(boolean nooffer) {
|
||||
userProfile.noOffer = nooffer;
|
||||
}
|
||||
|
||||
public void setAudio(boolean enable) {
|
||||
userProfile.audio = enable;
|
||||
}
|
||||
|
||||
public void setVideo(boolean enable) {
|
||||
userProfile.video = enable;
|
||||
}
|
||||
|
||||
public void setReceiveOnlyMode(boolean r_only) {
|
||||
userProfile.recvOnly = r_only;
|
||||
}
|
||||
|
||||
public void setSendOnlyMode(boolean s_only) {
|
||||
userProfile.sendOnly = s_only;
|
||||
}
|
||||
|
||||
public void setSendToneMode(boolean s_tone) {
|
||||
userProfile.sendTone = s_tone;
|
||||
}
|
||||
|
||||
public void setSendFile(String file_name) {
|
||||
userProfile.sendFile = file_name;
|
||||
}
|
||||
|
||||
public void setRecvFile(String file_name) {
|
||||
userProfile.recvFile = file_name;
|
||||
}
|
||||
|
||||
public String getSessionDescriptor() {
|
||||
return localSession;
|
||||
}
|
||||
|
||||
public void setSessionDescriptor(String sdp) {
|
||||
localSession = sdp;
|
||||
}
|
||||
|
||||
// public boolean isReceiverRunning() {
|
||||
// return callStream.isReceiverRunning();
|
||||
// }
|
||||
|
||||
public void queueSipDtmfDigits(String digits) {
|
||||
callStream.queueSipDtmfDigits(digits);
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
waitForIncomingCalls();
|
||||
}
|
||||
|
||||
public void initSessionDescriptor() {
|
||||
log.debug("initSessionDescriptor");
|
||||
SessionDescriptor newSdp = SdpUtils.createInitialSdp(
|
||||
userProfile.username, sipProvider.getViaAddress(),
|
||||
userProfile.audioPort, userProfile.videoPort,
|
||||
userProfile.audioCodecsPrecedence );
|
||||
SessionDescriptor newSdp = SdpUtils.createInitialSdp(userProfile.username,
|
||||
sipProvider.getViaAddress(), userProfile.audioPort,
|
||||
userProfile.videoPort, userProfile.audioCodecsPrecedence );
|
||||
localSession = newSdp.toString();
|
||||
log.debug("localSession Descriptor = " + localSession );
|
||||
}
|
||||
|
||||
public SipUserAgent(SipProvider sipProvider, SipUserAgentProfile userProfile,
|
||||
SipUserAgentListener listener, ScopeProvider scopeProvider) {
|
||||
this.scopeProvider = scopeProvider;
|
||||
this.sipProvider = sipProvider;
|
||||
this.listener = listener;
|
||||
this.userProfile = userProfile;
|
||||
|
||||
// If no contact_url and/or from_url has been set, create it now.
|
||||
userProfile.initContactAddress( sipProvider );
|
||||
// Set local sdp.
|
||||
initSessionDescriptor();
|
||||
}
|
||||
|
||||
public void call(String targetUrl) {
|
||||
log.debug( "call", "Init..." );
|
||||
changeStatus( UA_OUTGOING_CALL );
|
||||
log.debug( "call", "Init..." );
|
||||
changeStatus(CallState.UA_OUTGOING_CALL);
|
||||
|
||||
call = new ExtendedCall(sipProvider, userProfile.fromUrl,
|
||||
userProfile.contactUrl, userProfile.username,
|
||||
@ -165,7 +97,7 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
if (userProfile.noOffer) {
|
||||
call.call(targetUrl);
|
||||
} else {
|
||||
call.call( targetUrl, localSession );
|
||||
call.call(targetUrl, localSession);
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,9 +112,9 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
|
||||
|
||||
/** Waits for an incoming call (acting as UAS). */
|
||||
public void waitForIncomingCalls() {
|
||||
log.debug("waitForIncomingCalls..." );
|
||||
changeStatus( UA_IDLE );
|
||||
private void waitForIncomingCalls() {
|
||||
log.debug("waitForIncomingCalls..." );
|
||||
changeStatus(CallState.UA_IDLE);
|
||||
|
||||
call = new ExtendedCall(sipProvider, userProfile.fromUrl,
|
||||
userProfile.contactUrl, userProfile.username,
|
||||
@ -194,12 +126,13 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
/** Closes an ongoing, incoming, or pending call */
|
||||
public void hangup() {
|
||||
log.debug("hangup");
|
||||
|
||||
closeMediaApplication();
|
||||
if (call != null) {
|
||||
call.hangup();
|
||||
}
|
||||
changeStatus(UA_IDLE);
|
||||
|
||||
if (isIdle()) return;
|
||||
|
||||
closeMediaApplication();
|
||||
if (call != null) call.hangup();
|
||||
changeStatus(CallState.UA_IDLE);
|
||||
waitForIncomingCalls();
|
||||
}
|
||||
|
||||
|
||||
@ -212,8 +145,6 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Redirects an incoming call */
|
||||
public void redirect(String redirection) {
|
||||
log.debug( "redirect", "Init..." );
|
||||
|
||||
@ -243,9 +174,7 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
|
||||
try {
|
||||
callStream = new CallStream(sipCodec, connInfo, scopeProvider);
|
||||
if (listener != null) {
|
||||
listener.onUaCallConnected(this, callStream.getListenStreamName(), callStream.getTalkStreamName());
|
||||
}
|
||||
notifyListenersOnCallConnected(callStream.getListenStreamName(), callStream.getTalkStreamName());
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to create Call Stream.");
|
||||
}
|
||||
@ -253,9 +182,15 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListenersOnCallConnected(String listenStream, String talkStream) {
|
||||
for (SipUserAgentListener listener : listeners) {
|
||||
listener.onCallConnected(listenStream, talkStream);
|
||||
}
|
||||
}
|
||||
|
||||
private int getLocalAudioPort(SessionDescriptor localSdp) {
|
||||
int localAudioPort = 0;
|
||||
int localVideoPort = 0;
|
||||
//int localVideoPort = 0;
|
||||
|
||||
// parse local sdp
|
||||
for ( Enumeration e = localSdp.getMediaDescriptors().elements(); e.hasMoreElements(); ) {
|
||||
@ -263,9 +198,9 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
if ( media.getMedia().equals( "audio" ) ) {
|
||||
localAudioPort = media.getPort();
|
||||
}
|
||||
if ( media.getMedia().equals( "video" ) ) {
|
||||
localVideoPort = media.getPort();
|
||||
}
|
||||
//if ( media.getMedia().equals( "video" ) ) {
|
||||
// localVideoPort = media.getPort();
|
||||
//}
|
||||
}
|
||||
|
||||
return localAudioPort;
|
||||
@ -273,9 +208,9 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
|
||||
private int getRemoteAudioPort(SessionDescriptor remoteSdp) {
|
||||
int remoteAudioPort = 0;
|
||||
int remoteVideoPort = 0;
|
||||
//int remoteVideoPort = 0;
|
||||
|
||||
for ( Enumeration e = remoteSdp.getMediaDescriptors().elements(); e.hasMoreElements(); ) {
|
||||
for (Enumeration e = remoteSdp.getMediaDescriptors().elements(); e.hasMoreElements();) {
|
||||
MediaDescriptor descriptor = (MediaDescriptor) e.nextElement();
|
||||
MediaField media = descriptor.getMedia();
|
||||
|
||||
@ -283,9 +218,9 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
remoteAudioPort = media.getPort();
|
||||
}
|
||||
|
||||
if ( media.getMedia().equals( "video" ) ) {
|
||||
remoteVideoPort = media.getPort();
|
||||
}
|
||||
// if ( media.getMedia().equals( "video" ) ) {
|
||||
// remoteVideoPort = media.getPort();
|
||||
// }
|
||||
}
|
||||
|
||||
return remoteAudioPort;
|
||||
@ -296,7 +231,7 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
}
|
||||
|
||||
protected void closeMediaApplication() {
|
||||
log.debug( "closeMediaApplication", "Init..." );
|
||||
log.debug("closeMediaApplication" );
|
||||
|
||||
if (callStream != null) {
|
||||
callStream.stopMedia();
|
||||
@ -307,125 +242,41 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
|
||||
// ********************** Call callback functions **********************
|
||||
|
||||
private void createAudioCodec(SessionDescriptor newSdp) {
|
||||
sipCodec = SdpUtils.getNegotiatedAudioCodec(newSdp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function called when arriving a new INVITE method (incoming call)
|
||||
*/
|
||||
public void onCallIncoming(Call call, NameAddress callee, NameAddress caller, String sdp, Message invite) {
|
||||
log.debug("onCallIncoming");
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("NOT the current call.");
|
||||
return;
|
||||
}
|
||||
if (!isCurrentCall(call)) return;
|
||||
|
||||
log.debug("Inside SIPUserAgent.onCallIncoming(): sdp=\n" + sdp);
|
||||
log.debug("IncomingCallIncoming()");
|
||||
|
||||
changeStatus(UA_INCOMING_CALL);
|
||||
changeStatus(CallState.UA_INCOMING_CALL);
|
||||
call.ring();
|
||||
|
||||
if (sdp != null) {
|
||||
SessionDescriptor remoteSdp = new SessionDescriptor(sdp);
|
||||
SessionDescriptor localSdp = new SessionDescriptor(localSession);
|
||||
|
||||
log.debug("localSdp = " + localSdp.toString() + ".");
|
||||
log.debug("remoteSdp = " + remoteSdp.toString() + ".");
|
||||
|
||||
// First we need to make payloads negotiation so the related
|
||||
// attributes can be then matched.
|
||||
SessionDescriptor newSdp = SdpUtils.makeMediaPayloadsNegotiation(localSdp, remoteSdp);
|
||||
|
||||
// After we can create the correct audio codec considering
|
||||
// audio negotiation made above.
|
||||
sipCodec = SdpUtils.getNegotiatedAudioCodec(newSdp);
|
||||
|
||||
// Now we complete the SDP negotiation informing the selected
|
||||
// codec, so it can be internally updated during the process.
|
||||
SdpUtils.completeSdpNegotiation(newSdp, localSdp, remoteSdp);
|
||||
|
||||
localSession = newSdp.toString();
|
||||
|
||||
log.debug("newSdp = " + localSession + "." );
|
||||
|
||||
// Finally, we use the "newSdp" and "remoteSdp" to initialize
|
||||
// the lasting codec informations.
|
||||
CodecUtils.initSipAudioCodec(sipCodec, userProfile.audioDefaultPacketization,
|
||||
userProfile.audioDefaultPacketization, newSdp, remoteSdp);
|
||||
setupSdpAndCodec(sdp);
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onUaCallIncoming(this, callee, caller);
|
||||
}
|
||||
notifyListenersOfNewIncomingCall(callee, caller);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback function called when arriving a new Re-INVITE method
|
||||
* (re-inviting/call modify)
|
||||
*/
|
||||
public void onCallModifying(Call call, String sdp, Message invite) {
|
||||
log.debug("onCallModifying");
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("NOT the current call.");
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("RE-INVITE/MODIFY.");
|
||||
|
||||
// to be implemented.
|
||||
// currently it simply accepts the session changes (see method
|
||||
// onCallModifying() in CallListenerAdapter)
|
||||
super.onCallModifying( call, sdp, invite );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback function that may be overloaded (extended). Called when arriving
|
||||
* a 180 Ringing
|
||||
*/
|
||||
public void onCallRinging(Call call, Message resp) {
|
||||
log.debug("onCallRinging");
|
||||
|
||||
if (call != this.call && call != callTransfer) {
|
||||
log.debug("NOT the current call.");
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("RINGING." );
|
||||
|
||||
// Play "on" sound.
|
||||
if (listener != null) {
|
||||
listener.onUaCallRinging(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Callback function called when arriving a 2xx (call accepted) */
|
||||
public void onCallAccepted(Call call, String sdp, Message resp) {
|
||||
log.debug( "onCallAccepted");
|
||||
|
||||
if (call != this.call && call != callTransfer) {
|
||||
log.debug("NOT the current call." );
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("ACCEPTED/CALL.");
|
||||
|
||||
changeStatus(UA_ONCALL);
|
||||
|
||||
SessionDescriptor remoteSdp = new SessionDescriptor(sdp);
|
||||
|
||||
private void setupSdpAndCodec(String sdp) {
|
||||
SessionDescriptor remoteSdp = new SessionDescriptor(sdp);
|
||||
SessionDescriptor localSdp = new SessionDescriptor(localSession);
|
||||
|
||||
log.debug("localSdp = " + localSdp.toString() + ".");
|
||||
log.debug("remoteSdp = " + remoteSdp.toString() + ".");
|
||||
|
||||
// First we need to make payloads negotiation so the related
|
||||
// attributes can be then matched.
|
||||
// First we need to make payloads negotiation so the related attributes can be then matched.
|
||||
SessionDescriptor newSdp = SdpUtils.makeMediaPayloadsNegotiation(localSdp, remoteSdp);
|
||||
|
||||
// After we can create the correct audio codec considering
|
||||
// audio negotiation made above.
|
||||
sipCodec = SdpUtils.getNegotiatedAudioCodec(newSdp);
|
||||
createAudioCodec(newSdp);
|
||||
|
||||
// Now we complete the SDP negotiation informing the selected
|
||||
// codec, so it can be internally updated during the process.
|
||||
@ -433,12 +284,71 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
|
||||
localSession = newSdp.toString();
|
||||
|
||||
log.debug("newSdp = " + localSession + ".");
|
||||
log.debug("newSdp = " + localSession + "." );
|
||||
|
||||
// Finally, we use the "newSdp" and "remoteSdp" to initialize
|
||||
// the lasting codec informations.
|
||||
// Finally, we use the "newSdp" and "remoteSdp" to initialize the lasting codec informations.
|
||||
CodecUtils.initSipAudioCodec(sipCodec, userProfile.audioDefaultPacketization,
|
||||
userProfile.audioDefaultPacketization, newSdp, remoteSdp);
|
||||
}
|
||||
|
||||
private void notifyListenersOfNewIncomingCall(NameAddress callee, NameAddress caller) {
|
||||
String source = caller.getAddress().toString();
|
||||
String sourceName = caller.hasDisplayName() ? caller.getDisplayName() : "";
|
||||
String destination = callee.getAddress().toString();
|
||||
String destinationName = callee.hasDisplayName() ? callee.getDisplayName() : "";
|
||||
|
||||
for (SipUserAgentListener listener : listeners) {
|
||||
listener.onNewIncomingCall(source, sourceName, destination, destinationName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function called when arriving a new Re-INVITE method (re-inviting/call modify)
|
||||
*/
|
||||
public void onCallModifying(Call call, String sdp, Message invite) {
|
||||
log.debug("onCallModifying");
|
||||
|
||||
if (!isCurrentCall(call)) return;
|
||||
|
||||
log.debug("RE-INVITE/MODIFY.");
|
||||
|
||||
// to be implemented.
|
||||
// currently it simply accepts the session changes (see method
|
||||
// onCallModifying() in CallListenerAdapter)
|
||||
super.onCallModifying(call, sdp, invite);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback function that may be overloaded (extended). Called when arriving a 180 Ringing
|
||||
*/
|
||||
public void onCallRinging(Call call, Message resp) {
|
||||
log.debug("onCallRinging");
|
||||
|
||||
if (!isCurrentCallOrCallTransfer(call)) return;
|
||||
|
||||
log.debug("RINGING." );
|
||||
|
||||
notifyListenersOfOnOutgoingCallRemoteRinging();
|
||||
}
|
||||
|
||||
private void notifyListenersOfOnOutgoingCallRemoteRinging() {
|
||||
for (SipUserAgentListener listener : listeners) {
|
||||
listener.onOutgoingCallRemoteRinging();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Callback function called when arriving a 2xx (call accepted) */
|
||||
public void onCallAccepted(Call call, String sdp, Message resp) {
|
||||
log.debug( "onCallAccepted");
|
||||
|
||||
if (!isCurrentCallOrCallTransfer(call)) return;
|
||||
|
||||
log.debug("ACCEPTED/CALL.");
|
||||
changeStatus(CallState.UA_ONCALL);
|
||||
|
||||
setupSdpAndCodec(sdp);
|
||||
|
||||
if (userProfile.noOffer) {
|
||||
// Answer with the local sdp.
|
||||
@ -454,24 +364,24 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
this.call.notify(code, reason);
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onUaCallAccepted(this);
|
||||
}
|
||||
notifyListenersOfOnOutgoingCallAccepted();
|
||||
}
|
||||
|
||||
public void notifyListenersOfOnOutgoingCallAccepted() {
|
||||
for (SipUserAgentListener listener : listeners) {
|
||||
listener.onOutgoingCallAccepted();
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback function called when arriving an ACK method (call confirmed) */
|
||||
public void onCallConfirmed(Call call, String sdp, Message ack) {
|
||||
log.debug("onCallConfirmed");
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("NOT the current call.");
|
||||
return;
|
||||
}
|
||||
if (!isCurrentCall(call)) return;
|
||||
|
||||
log.debug("CONFIRMED/CALL.");
|
||||
|
||||
changeStatus(UA_ONCALL);
|
||||
changeStatus(CallState.UA_ONCALL);
|
||||
|
||||
launchMediaApplication();
|
||||
}
|
||||
|
||||
@ -480,10 +390,7 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
public void onCallReInviteAccepted(Call call, String sdp, Message resp) {
|
||||
log.debug( "onCallReInviteAccepted");
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("NOT the current call." );
|
||||
return;
|
||||
}
|
||||
if (!isCurrentCall(call)) return;
|
||||
|
||||
log.debug("RE-INVITE-ACCEPTED/CALL." );
|
||||
}
|
||||
@ -493,30 +400,22 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
public void onCallReInviteRefused(Call call, String reason, Message resp) {
|
||||
log.debug("onCallReInviteRefused");
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("NOT the current call");
|
||||
return;
|
||||
}
|
||||
if (!isCurrentCall(call)) return;
|
||||
|
||||
log.debug("RE-INVITE-REFUSED (" + reason + ")/CALL.");
|
||||
|
||||
if (listener != null) {
|
||||
listener.onUaCallFailed(this);
|
||||
}
|
||||
notifyListenersOnOutgoingCallFailed();
|
||||
waitForIncomingCalls();
|
||||
}
|
||||
|
||||
/** Callback function called when arriving a 4xx (call failure) */
|
||||
public void onCallRefused(Call call, String reason, Message resp) {
|
||||
log.debug("onCallRefused");
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("NOT the current call.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCurrentCall(call)) return;
|
||||
|
||||
log.debug("REFUSED (" + reason + ").");
|
||||
|
||||
changeStatus(UA_IDLE);
|
||||
changeStatus(CallState.UA_IDLE);
|
||||
|
||||
if (call == callTransfer) {
|
||||
StatusLine status_line = resp.getStatusLine();
|
||||
@ -526,9 +425,14 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
callTransfer = null;
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onUaCallFailed(this);
|
||||
}
|
||||
notifyListenersOnOutgoingCallFailed();
|
||||
waitForIncomingCalls();
|
||||
}
|
||||
|
||||
private void notifyListenersOnOutgoingCallFailed() {
|
||||
for (SipUserAgentListener listener : listeners) {
|
||||
listener.onOutgoingCallFailed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -536,11 +440,7 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
public void onCallRedirection(Call call, String reason, Vector contact_list, Message resp) {
|
||||
log.debug("onCallRedirection");
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("NOT the current call.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCurrentCall(call)) return;
|
||||
log.debug("REDIRECTION (" + reason + ")." );
|
||||
|
||||
call.call(((String) contact_list.elementAt(0)));
|
||||
@ -548,24 +448,23 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
|
||||
|
||||
/**
|
||||
* Callback function that may be overloaded (extended). Called when arriving
|
||||
* a CANCEL request
|
||||
* Callback function that may be overloaded (extended). Called when arriving a CANCEL request
|
||||
*/
|
||||
public void onCallCanceling(Call call, Message cancel) {
|
||||
log.debug("onCallCanceling");
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("NOT the current call.");
|
||||
return;
|
||||
}
|
||||
if (!isCurrentCall(call)) return;
|
||||
|
||||
log.debug("CANCEL.");
|
||||
|
||||
changeStatus(UA_IDLE);
|
||||
|
||||
if (listener != null) {
|
||||
listener.onUaCallCancelled(this);
|
||||
}
|
||||
changeStatus(CallState.UA_IDLE);
|
||||
notifyListenersOfOnIncomingCallCancelled();
|
||||
waitForIncomingCalls();
|
||||
}
|
||||
|
||||
private void notifyListenersOfOnIncomingCallCancelled() {
|
||||
for (SipUserAgentListener listener : listeners) {
|
||||
listener.onIncomingCallCancelled();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -573,10 +472,7 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
public void onCallClosing(Call call, Message bye) {
|
||||
log.debug("onCallClosing");
|
||||
|
||||
if (call != this.call && call != callTransfer) {
|
||||
log.debug("NOT the current call.");
|
||||
return;
|
||||
}
|
||||
if (!isCurrentCallOrCallTransfer(call)) return;
|
||||
|
||||
if (call != callTransfer && callTransfer != null) {
|
||||
log.debug("CLOSE PREVIOUS CALL.");
|
||||
@ -589,16 +485,19 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
|
||||
closeMediaApplication();
|
||||
|
||||
if (listener != null) {
|
||||
listener.onUaCallClosed(this);
|
||||
}
|
||||
|
||||
changeStatus(UA_IDLE);
|
||||
notifyListenersOfOnCallClosed();
|
||||
changeStatus(CallState.UA_IDLE);
|
||||
|
||||
// Reset local sdp for next call.
|
||||
initSessionDescriptor();
|
||||
waitForIncomingCalls();
|
||||
}
|
||||
|
||||
private void notifyListenersOfOnCallClosed() {
|
||||
for (SipUserAgentListener listener : listeners) {
|
||||
listener.onCallClosed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function called when arriving a response after a BYE request
|
||||
@ -607,18 +506,13 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
public void onCallClosed(Call call, Message resp) {
|
||||
log.debug("onCallClosed");
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("NOT the current call." );
|
||||
return;
|
||||
}
|
||||
if (!isCurrentCall(call)) return;
|
||||
|
||||
log.debug("CLOSE/OK.");
|
||||
|
||||
if (listener != null) {
|
||||
listener.onUaCallClosed(this);
|
||||
}
|
||||
|
||||
changeStatus(UA_IDLE);
|
||||
notifyListenersOfOnCallClosed();
|
||||
changeStatus(CallState.UA_IDLE);
|
||||
waitForIncomingCalls();
|
||||
}
|
||||
|
||||
|
||||
@ -626,40 +520,31 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
public void onCallTimeout(Call call) {
|
||||
log.debug("onCallTimeout");
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("NOT the current call.");
|
||||
return;
|
||||
}
|
||||
if (!isCurrentCall(call)) return;
|
||||
|
||||
log.debug("NOT FOUND/TIMEOUT.");
|
||||
|
||||
changeStatus(UA_IDLE);
|
||||
changeStatus(CallState.UA_IDLE);
|
||||
|
||||
if (call == callTransfer) {
|
||||
int code = 408;
|
||||
String reason = "Request Timeout";
|
||||
this.call.notify( code, reason );
|
||||
this.call.notify(code, reason);
|
||||
callTransfer = null;
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onUaCallFailed(this);
|
||||
}
|
||||
notifyListenersOnOutgoingCallFailed();
|
||||
waitForIncomingCalls();
|
||||
}
|
||||
|
||||
|
||||
// ****************** ExtendedCall callback functions ******************
|
||||
|
||||
/**
|
||||
* Callback function called when arriving a new REFER method (transfer request)
|
||||
*/
|
||||
public void onCallTransfer(ExtendedCall call, NameAddress refer_to, NameAddress refered_by, Message refer) {
|
||||
log.debug("onCallTransfer");
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("NOT the current call.");
|
||||
return;
|
||||
}
|
||||
if (!isCurrentCall(call)) return;
|
||||
|
||||
log.debug("Transfer to " + refer_to.toString() + ".");
|
||||
|
||||
@ -674,10 +559,7 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
public void onCallTransferAccepted(ExtendedCall call, Message resp) {
|
||||
log.debug("onCallTransferAccepted");
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("NOT the current call.");
|
||||
return;
|
||||
}
|
||||
if (!isCurrentCall(call)) return;
|
||||
|
||||
log.debug("Transfer accepted.");
|
||||
}
|
||||
@ -685,48 +567,45 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
|
||||
/** Callback function called when a call transfer is refused. */
|
||||
public void onCallTransferRefused(ExtendedCall call, String reason, Message resp) {
|
||||
log.debug("onCallTransferRefused");
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("NOT the current call.");
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug( "onCallTransferRefused", "Transfer refused." );
|
||||
log.debug("onCallTransferRefused");
|
||||
if (!isCurrentCall(call)) return;
|
||||
log.debug("Transfer refused.");
|
||||
}
|
||||
|
||||
|
||||
/** Callback function called when a call transfer is successfully completed */
|
||||
public void onCallTransferSuccess(ExtendedCall call, Message notify) {
|
||||
log.debug( "onCallTransferSuccess", "Init..." );
|
||||
log.debug("onCallTransferSuccess");
|
||||
if (!isCurrentCall(call)) return;
|
||||
|
||||
if (call != this.call) {
|
||||
log.debug("onCallTransferSuccess", "NOT the current call.");
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug( "onCallTransferSuccess", "Transfer successed." );
|
||||
log.debug("Transfer succeeded.");
|
||||
|
||||
call.hangup();
|
||||
|
||||
if ( listener != null ) {
|
||||
listener.onUaCallTrasferred( this );
|
||||
}
|
||||
notifyListenersOfOnCallTransferred();
|
||||
}
|
||||
|
||||
private void notifyListenersOfOnCallTransferred() {
|
||||
for (SipUserAgentListener listener : listeners) {
|
||||
listener.onCallTrasferred();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function called when a call transfer is NOT sucessfully
|
||||
* completed
|
||||
* Callback function called when a call transfer is NOT successfully completed
|
||||
*/
|
||||
public void onCallTransferFailure(ExtendedCall call, String reason, Message notify) {
|
||||
log.debug( "onCallTransferFailure", "Init..." );
|
||||
log.debug("onCallTransferFailure");
|
||||
if (!isCurrentCall(call)) return;
|
||||
|
||||
if ( call != this.call ) {
|
||||
log.debug( "onCallTransferFailure", "NOT the current call." );
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug( "onCallTransferFailure", "Transfer failed." );
|
||||
log.info("Transfer failed.");
|
||||
}
|
||||
|
||||
private boolean isCurrentCallOrCallTransfer(Call call) {
|
||||
return (call == this.call) || (call != callTransfer);
|
||||
}
|
||||
|
||||
private boolean isCurrentCall(Call call) {
|
||||
return this.call == call;
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,12 @@
|
||||
package org.red5.app.sip;
|
||||
|
||||
import org.zoolu.sip.address.NameAddress;
|
||||
|
||||
/** Listener of SIPUserAgent */
|
||||
public interface SipUserAgentListener {
|
||||
/** When a new call is incoming */
|
||||
public void onUaCallIncoming( SipUserAgent ua, NameAddress callee, NameAddress caller );
|
||||
|
||||
/** When an incoming call is cancelled */
|
||||
public void onUaCallCancelled( SipUserAgent ua );
|
||||
|
||||
/** When an ougoing call is remotly ringing */
|
||||
public void onUaCallRinging( SipUserAgent ua );
|
||||
|
||||
/** When an ougoing call has been accepted */
|
||||
public void onUaCallAccepted( SipUserAgent ua );
|
||||
|
||||
/** When a call has been trasferred */
|
||||
public void onUaCallTrasferred( SipUserAgent ua );
|
||||
|
||||
/** When an ougoing call has been refused or timeout */
|
||||
public void onUaCallFailed( SipUserAgent ua );
|
||||
|
||||
|
||||
/** When a call has been locally or remotely closed */
|
||||
public void onUaCallClosed(SipUserAgent ua);
|
||||
|
||||
|
||||
/** When a call has media connected */
|
||||
public void onUaCallConnected(SipUserAgent ua, String talkStreamName, String listenStreamName);
|
||||
|
||||
public void onCallConnected(String talkStreamName, String listenStreamName);
|
||||
public void onNewIncomingCall(String source, String sourceName, String destination, String destinationName);
|
||||
public void onOutgoingCallRemoteRinging();
|
||||
public void onOutgoingCallAccepted();
|
||||
public void onCallTrasferred();
|
||||
public void onIncomingCallCancelled();
|
||||
public void onOutgoingCallFailed();
|
||||
public void onCallClosed();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user