diff options
author | Lyubomir Marinov <lyubomir.marinov@jitsi.org> | 2009-04-27 17:37:20 +0000 |
---|---|---|
committer | Lyubomir Marinov <lyubomir.marinov@jitsi.org> | 2009-04-27 17:37:20 +0000 |
commit | 27194e062ffb11162ac7d7e99f61c79a5e98251f (patch) | |
tree | 60d14d0ac38720f93feb8929c91f32addb4409a2 /src/net/java/sip | |
parent | 39779d7707b2a721ea3dc134b231c616897a358a (diff) | |
download | jitsi-27194e062ffb11162ac7d7e99f61c79a5e98251f.zip jitsi-27194e062ffb11162ac7d7e99f61c79a5e98251f.tar.gz jitsi-27194e062ffb11162ac7d7e99f61c79a5e98251f.tar.bz2 |
Fixes reINVITE-related functionality so that SC can join a 3-way auto-conference (SC doesn't really see that it's a conference) created by X-Lite.
Diffstat (limited to 'src/net/java/sip')
5 files changed, 336 insertions, 218 deletions
diff --git a/src/net/java/sip/communicator/impl/media/CallSessionImpl.java b/src/net/java/sip/communicator/impl/media/CallSessionImpl.java index a7d9bc2..c3a0570 100644 --- a/src/net/java/sip/communicator/impl/media/CallSessionImpl.java +++ b/src/net/java/sip/communicator/impl/media/CallSessionImpl.java @@ -73,14 +73,14 @@ import gnu.java.zrtp.*; */ public class CallSessionImpl extends PropertyChangeNotifier - implements CallSession - , CallParticipantListener - , CallChangeListener - , ReceiveStreamListener - , SendStreamListener - , SessionListener - , ControllerListener -// , SecureEventListener + implements CallSession + , CallParticipantListener + , CallChangeListener + , ReceiveStreamListener + , SendStreamListener + , SessionListener + , ControllerListener +// , SecureEventListener { private static final Logger logger = Logger.getLogger(CallSessionImpl.class); @@ -462,32 +462,71 @@ public class CallSessionImpl applyOnHold(); } + /* Implements CallSession#startStreamingAndProcessingMedia(). */ + public void startStreamingAndProcessingMedia() + throws MediaException + { + startStreaming(); + mediaServCallback.getMediaControl(getCall()).startProcessingMedia(this); + } + /** * Stops and closes all streams that have been initialized for local - * RTP managers. + * RTP managers and disposes of the local RTP managers. */ public boolean stopStreaming() { + return stopStreaming(true); + } + + /** + * Stops and closes all streams that have been initialized for local + * RTP managers and, optionally, disposes of the local RTP managers. + * + * @param dispose <tt>true</tt> to dispose of the local RTP managers once + * their streams have been stopped and closed; <tt>false</tt> to + * only stop and close the initialized streams but not dispose of + * the local RTP managers + * @return <tt>true</tt> if at least one stream has been closed and stopped; + * otherwise, <tt>false</tt> + */ + private boolean stopStreaming(boolean dispose) + { boolean stoppedStreaming = false; RTPManager audioRtpManager = getAudioRtpManager(); if (audioRtpManager != null) { - stoppedStreaming = stopStreaming(audioRtpManager); - this.audioRtpManager = null; + stoppedStreaming = stopStreaming(audioRtpManager, dispose); + if (dispose) + { + transConnectors.remove(this.audioRtpManager); // clean up + this.audioRtpManager = null; + } } RTPManager videoRtpManager = getVideoRtpManager(); if (videoRtpManager != null) { stoppedStreaming = - stopStreaming(videoRtpManager) || stoppedStreaming; - this.videoRtpManager = null; + stopStreaming(videoRtpManager, dispose) || stoppedStreaming; + if (dispose) + { + transConnectors.remove(this.videoRtpManager); // clean up + this.videoRtpManager = null; + } } lastIntendedDestination = null; return stoppedStreaming; } + /** + * Stops and closes the <code>SendStream</code>s initialized for the local + * RTP managers. + * + * @return <tt>true</tt> if at least one stream has been closed and stopped; + * otherwise, <tt>false</tt> + */ private boolean stopSendStreaming() { boolean stoppedAtLeastOneStream = false; @@ -505,9 +544,18 @@ public class CallSessionImpl return stoppedAtLeastOneStream; } + /** + * Stops and closes the <code>SendStream</code>s initialized for a specific + * <code>RTPManager</code>. + * + * @param rtpManager the <code>RTPManager</code> whose + * <code>SendStream</code>s are to be stopped and closed + * @return <tt>true</tt> if at least one stream has been closed and stopped; + * otherwise, <tt>false</tt> + */ private boolean stopSendStreaming(RTPManager rtpManager) { - List<SendStream> sendStreams = rtpManager.getSendStreams(); + Iterable<SendStream> sendStreams = rtpManager.getSendStreams(); boolean stoppedAtLeastOneStream = false; for (SendStream stream : sendStreams) @@ -535,7 +583,7 @@ public class CallSessionImpl * the streaming wasn't already stopped before this request; * <tt>false</tt>, otherwise */ - private boolean stopStreaming(RTPManager rtpManager) + private boolean stopStreaming(RTPManager rtpManager, boolean dispose) { boolean stoppedAtLeastOneStream = stopSendStreaming(rtpManager); @@ -556,7 +604,14 @@ public class CallSessionImpl { try { - stream.getDataSource().stop(); + DataSource streamDataSource = stream.getDataSource(); + + /* + * For an unknown reason, the stream DataSource can be null at + * the end of the Call after re-INVITEs have been handled. + */ + if (streamDataSource != null) + streamDataSource.stop(); } catch (IOException ex) { @@ -575,7 +630,7 @@ public class CallSessionImpl if (transConnector != null) { - if (usingZRTP) + if (dispose && usingZRTP) { ZRTPTransformEngine engine = (ZRTPTransformEngine) transConnector.getEngine(); @@ -593,11 +648,14 @@ public class CallSessionImpl printFlowStatistics(rtpManager); - //stop listening - rtpManager.removeReceiveStreamListener(this); - rtpManager.removeSendStreamListener(this); - rtpManager.removeSessionListener(this); - rtpManager.dispose(); + if (dispose) + { + //stop listening + rtpManager.removeReceiveStreamListener(this); + rtpManager.removeSendStreamListener(this); + rtpManager.removeSessionListener(this); + rtpManager.dispose(); + } return stoppedAtLeastOneStream; } @@ -728,13 +786,40 @@ public class CallSessionImpl * callee to be put on hold or answer an offer from the remote * callee to be put on hold; <tt>false</tt> to work in the * context of a put-off-hold offer - * @return an SDP description <tt>String</tt> which offers the remote + * @return a SDP description <tt>String</tt> which offers the remote * callee to be put her on/off hold or answers an offer from the * remote callee to be put on/off hold * @throws MediaException */ public String createSdpDescriptionForHold(String participantSdpDescription, - boolean on) throws MediaException + boolean on) + throws MediaException + { + return + createSessionDescriptionForHold(participantSdpDescription, on) + .toString(); + } + + /** + * The method is meant for use by protocol service implementations when + * willing to send an in-dialog invitation to a remote callee to put her + * on/off hold or to send an answer to an offer to be put on/off hold. + * + * @param participantSdpDescription the last SDP description of the remote + * callee + * @param on <tt>true</tt> if the SDP description should offer the remote + * callee to be put on hold or answer an offer from the remote + * callee to be put on hold; <tt>false</tt> to work in the + * context of a put-off-hold offer + * @return a <code>SessionDescription</code> which offers the remote + * callee to be put her on/off hold or answers an offer from the + * remote callee to be put on/off hold + * @throws MediaException + */ + private SessionDescription createSessionDescriptionForHold( + String participantSdpDescription, + boolean on) + throws MediaException { SessionDescription participantDescription = null; try @@ -793,7 +878,7 @@ public class CallSessionImpl MediaException.INTERNAL_ERROR, ex); } - return sdpOffer.toString(); + return sdpOffer; } /** @@ -1066,33 +1151,81 @@ public class CallSessionImpl * String. */ public void processSdpAnswer(CallParticipant responder, - String sdpAnswerStr) + String sdpAnswerStr) + throws MediaException, ParseException + { + processSdpStr(responder, sdpAnswerStr, true); + } + + private String processSdpStr(CallParticipant participant, + String sdpStr, + boolean answer) throws MediaException, ParseException { - logger.trace("Parsing sdp answer: " + sdpAnswerStr); + String answerStr = answer ? "answer" : "offer"; + + logger.trace("Parsing SDP " + answerStr + ": " + sdpStr); + //first parse the answer - SessionDescription sdpAnswer = null; + SessionDescription sdp; try { - sdpAnswer = mediaServCallback.getSdpFactory() - .createSessionDescription(sdpAnswerStr); + sdp = mediaServCallback.getSdpFactory() + .createSessionDescription(sdpStr); } catch (SdpParseException ex) { - throw new ParseException("Failed to parse SDPOffer: " - + ex.getMessage() - , ex.getCharOffset()); + throw new ParseException("Failed to parse SDP " + + answerStr + + ": " + + ex.getMessage(), + ex.getCharOffset()); + } + //it appears that in some cases parsing could also fail with + //other exceptions such as a NullPointerException for example so make + //sure we get those too. + catch (Exception ex) + { + throw new ParseException("Failed to parse SDP " + + answerStr + + ": " + + ex.getMessage(), + 0); + } + + SessionDescription sdpAnswer; + + if (answer) + { + /* + * extract URI (rfc4566 says that if present it should be before the + * media description so let's start with it) + */ + setCallURL(sdp.getURI()); + + sdpAnswer = sdp; } + else + { + //create an sdp answer. + CallParticipantState participantState = participant.getState(); - //extract URI (rfc4566 says that if present it should be before the - //media description so let's start with it) - setCallURL(sdpAnswer.getURI()); + if (CallParticipantState.CONNECTED.equals(participantState) + || CallParticipantState.isOnHold(participantState)) + sdpAnswer = + createSessionDescriptionForHold( + sdpStr, + (getSdpOfferMediaFlags(sdpStr) + & CallSession.ON_HOLD_REMOTELY) != 0); + else + sdpAnswer = createSessionDescription(sdp, null); + } //extract media descriptions - Vector<MediaDescription> mediaDescriptions = null; + Vector<MediaDescription> mediaDescriptions; try { - mediaDescriptions = sdpAnswer.getMediaDescriptions(true); + mediaDescriptions = sdp.getMediaDescriptions(true); } catch (SdpException exc) { @@ -1103,20 +1236,22 @@ public class CallSessionImpl } //add the RTP targets - this.initStreamTargets(sdpAnswer.getConnection(), mediaDescriptions); + initStreamTargets(sdp.getConnection(), mediaDescriptions); //create and init the streams (don't start streaming just yet but wait //for the call to enter the connected state). createSendStreams(mediaDescriptions); - CallParticipantState responderState = responder.getState(); - if (CallParticipantState.CONNECTED.equals(responderState) - || CallParticipantState.isOnHold(responderState)) + if (answer) { - mediaServCallback.getMediaControl(getCall()) - .startProcessingMedia(this); - startStreaming(); + CallParticipantState participantState = participant.getState(); + + if (CallParticipantState.CONNECTED.equals(participantState) + || CallParticipantState.isOnHold(participantState)) + startStreamingAndProcessingMedia(); } + + return sdpAnswer.toString(); } /** @@ -1140,55 +1275,7 @@ public class CallSessionImpl public String processSdpOffer(CallParticipant offerer, String sdpOfferStr) throws MediaException, ParseException { - //first parse the offer - SessionDescription sdpOffer = null; - try - { - sdpOffer = mediaServCallback.getSdpFactory() - .createSessionDescription(sdpOfferStr); - } - catch (SdpParseException ex) - { - throw new ParseException("Failed to parse SDPOffer: " - + ex.getMessage() - , ex.getCharOffset()); - } - //it appears that in some cases parsing could also fail with - //other exceptions such as a NullPointerException for example so make - //sure we get those too. - catch(Exception ex) - { - throw new ParseException("Failed to parse SDPOffer: " - + ex.getMessage() - , 0); - } - - //create an sdp answer. - SessionDescription sdpAnswer = createSessionDescription(sdpOffer, null); - - //extract the remote addresses. - Vector<MediaDescription> mediaDescriptions = null; - try - { - mediaDescriptions = sdpOffer.getMediaDescriptions(true); - } - catch (SdpException exc) - { - logger.error("failed to extract media descriptions", exc); - throw new MediaException("failed to extract media descriptions" - , MediaException.INTERNAL_ERROR - , exc); - } - - - //add the RTP targets - this.initStreamTargets(sdpOffer.getConnection(), mediaDescriptions); - - //create and init the streams (don't start streaming just yet but wait - //for the call to enter the connected state). - createSendStreams(mediaDescriptions); - - return sdpAnswer.toString(); + return processSdpStr(offerer, sdpOfferStr, false); } /** @@ -1448,8 +1535,6 @@ public class CallSessionImpl //we don't yet implement ice so just try to choose a local address //that corresponds to the address provided by the offer or as an //intended destination. - NetworkAddressManagerService netAddressManager - = MediaActivator.getNetworkAddressManagerService(); if(offer != null) { @@ -1511,34 +1596,23 @@ public class CallSessionImpl */ boolean allocateMediaPorts = false; - /* - * TODO Should the reinitializing for the purposes of re-INVITE - * start the streaming before ACK? - */ - boolean startStreaming = false; if ((audioSessionAddress == null) || (videoSessionAddress == null)) { allocateMediaPorts = true; } - else - { - if ((intendedDestination != null) + else if ((intendedDestination != null) && !intendedDestination.equals(lastIntendedDestination)) - { - startStreaming = stopStreaming(); - audioRtpManager = RTPManager.newInstance(); - videoRtpManager = RTPManager.newInstance(); + { + stopStreaming(false); + //audioRtpManager = RTPManager.newInstance(); + //videoRtpManager = RTPManager.newInstance(); - allocateMediaPorts = true; - } + //allocateMediaPorts = true; } if (allocateMediaPorts) { allocateMediaPorts(intendedDestination); lastIntendedDestination = intendedDestination; - - if (startStreaming) - startStreaming(); } InetAddress publicIpAddress = audioPublicAddress.getAddress(); @@ -1578,9 +1652,10 @@ public class CallSessionImpl sessDescr.setTimeDescriptions(timeDescs); //media descriptions. - Vector<MediaDescription> offeredMediaDescriptions = null; - if(offer != null) - offeredMediaDescriptions = offer.getMediaDescriptions(false); + Vector<MediaDescription> offeredMediaDescriptions + = (offer == null) + ? null + : offer.getMediaDescriptions(false); logger.debug("Will create media descs with: audio public address=" + audioPublicAddress @@ -1595,9 +1670,7 @@ public class CallSessionImpl sessDescr.setMediaDescriptions(mediaDescs); if (logger.isTraceEnabled()) - { logger.trace("Generated SDP - " + sessDescr.toString()); - } return sessDescr; } @@ -1605,7 +1678,7 @@ public class CallSessionImpl { throw new MediaException( "An SDP exception occurred while generating local " - + "sdp description" + + "SDP description" , MediaException.INTERNAL_ERROR , exc); } @@ -2086,58 +2159,60 @@ public class CallSessionImpl private void allocateMediaPorts(InetAddress intendedDestination) throws MediaException { - NetworkAddressManagerService netAddressManager = MediaActivator - .getNetworkAddressManagerService(); - // Get our local address for the intended destination. // Use this address to bind our local RTP sockets InetAddress inAddrLocal - = netAddressManager.getLocalHost(intendedDestination); + = MediaActivator.getNetworkAddressManagerService() + .getLocalHost(intendedDestination); //check the number of times that we'd have to retry binding to local //ports before giving up. - String bindRetriesStr - = MediaActivator.getConfigurationService().getString( - MediaService.BIND_RETRIES_PROPERTY_NAME); + int bindRetries + = MediaActivator.getConfigurationService() + .getInt( + MediaService.BIND_RETRIES_PROPERTY_NAME, + MediaService.BIND_RETRIES_DEFAULT_VALUE); - int bindRetries = MediaService.BIND_RETRIES_DEFAULT_VALUE; - try - { - if(bindRetriesStr != null && bindRetriesStr.length() > 0) - bindRetries = Integer.parseInt(bindRetriesStr); - } - catch (NumberFormatException ex) + //initialize audio rtp manager. + + /* + * XXX If the ports have to be relocated, keep in mind that when X-Lite + * sends a re-INVITE and our port change is reported as part of the OK + * response to the re-INVITE, X-Lite continues to stream to the old + * ports and not to the new ones. + */ + if (audioSessionAddress == null) { - logger.warn(bindRetriesStr - + " is not a valid value for number of bind retries." - , ex); - } + audioSessionAddress + = new SessionAddress(inAddrLocal, minPortNumber); + audioPublicAddress + = allocatePort( + intendedDestination, audioSessionAddress, bindRetries); - //initialize audio rtp manager. - audioSessionAddress = new SessionAddress(inAddrLocal, minPortNumber); - audioPublicAddress = allocatePort(intendedDestination, - audioSessionAddress, - bindRetries); + //augment min port number so that no one else tries to bind here. + minPortNumber = audioSessionAddress.getDataPort() + 2; + } if (logger.isDebugEnabled()) { logger.debug("AudioSessionAddress=" + audioSessionAddress); logger.debug("AudioPublicAddress=" + audioPublicAddress); } - //augment min port number so that no one else tries to bind here. - minPortNumber = audioSessionAddress.getDataPort() + 2; - //initialize video rtp manager. - videoSessionAddress = new SessionAddress(inAddrLocal, minPortNumber); - videoPublicAddress = allocatePort(intendedDestination, - videoSessionAddress, - bindRetries); + if (videoSessionAddress == null) + { + videoSessionAddress + = new SessionAddress(inAddrLocal, minPortNumber); + videoPublicAddress + = allocatePort( + intendedDestination, videoSessionAddress, bindRetries); - //augment min port number so that no one else tries to bind here. - minPortNumber = videoSessionAddress.getDataPort() + 2; + //augment min port number so that no one else tries to bind here. + minPortNumber = videoSessionAddress.getDataPort() + 2; + } //if we have reached the max port number - reinit. - if(minPortNumber > maxPortNumber -2) + if (minPortNumber > maxPortNumber - 2) initializePortNumbers(); //now init the rtp managers and make them bind @@ -2446,9 +2521,7 @@ public class CallSessionImpl try { logger.debug("call connected. starting streaming"); - startStreaming(); - mediaServCallback.getMediaControl(getCall()) - .startProcessingMedia(this); + startStreamingAndProcessingMedia(); } catch (MediaException ex) { @@ -2591,27 +2664,26 @@ public class CallSessionImpl */ public synchronized void update(SessionEvent event) { - if (event instanceof NewParticipantEvent) + if (logger.isDebugEnabled()) { - Participant participant - = ( (NewParticipantEvent) event).getParticipant(); - if (logger.isDebugEnabled()) + if (event instanceof NewParticipantEvent) { + Participant participant + = ((NewParticipantEvent) event).getParticipant(); + logger.debug("A new participant had just joined: " - + participant.getCNAME()); + + participant.getCNAME()); } - } - else - { - if (logger.isDebugEnabled()) + else { - logger.debug( - "Received the following JMF Session event - " - + event.getClass().getName() + "=" + event); + logger.debug("Received the following JMF Session event - " + + event.getClass().getName() + + "=" + + event); } } - } + /** * Method called back in the RTPSessionListener to notify * listener of all SendStream Events. diff --git a/src/net/java/sip/communicator/impl/media/MediaControl.java b/src/net/java/sip/communicator/impl/media/MediaControl.java index fc1fd17..a7bd547 100644 --- a/src/net/java/sip/communicator/impl/media/MediaControl.java +++ b/src/net/java/sip/communicator/impl/media/MediaControl.java @@ -655,8 +655,8 @@ public class MediaControl logger.debug( "sourceProcessor is in state " + sourceProcessor.getState() - + "which is > Processor.Configured" - + "and then TrackControl.setFormat(Format) may not work."); + + " which is > Processor.Configured" + + " and then TrackControl.setFormat(Format) may not work."); boolean atLeastOneTrack = false; // Program the tracks. for (int i = 0; i < tracks.length; i++) diff --git a/src/net/java/sip/communicator/impl/media/transform/TransformConnector.java b/src/net/java/sip/communicator/impl/media/transform/TransformConnector.java index 6344ec2..8dcf15c 100755 --- a/src/net/java/sip/communicator/impl/media/transform/TransformConnector.java +++ b/src/net/java/sip/communicator/impl/media/transform/TransformConnector.java @@ -12,6 +12,8 @@ import java.net.*; import javax.media.protocol.*;
import javax.media.rtp.*;
+import net.java.sip.communicator.util.*;
+
/**
* TransformConnector implements the RTPConnector interface. RTPConnector
* is originally designed for programmers to abstract the underlying transport
@@ -37,6 +39,9 @@ import javax.media.rtp.*; public class TransformConnector
implements RTPConnector
{
+ private static final Logger logger
+ = Logger.getLogger(TransformConnector.class);
+
/**
* The customized TransformEngine object, which contains the concrete
* transform logic.
@@ -102,9 +107,18 @@ public class TransformConnector this.localAddr.getControlPort(),
this.localAddr.getControlAddress());
}
- catch (SocketException e)
+ catch (SocketException se)
{
- throw new InvalidSessionAddressException();
+ /*
+ * TODO Could anyone please provide a meaningful message for the
+ * Logger here because I don't have an idea?
+ */
+ logger.error(null, se);
+
+ InvalidSessionAddressException isae
+ = new InvalidSessionAddressException();
+ isae.initCause(se);
+ throw isae;
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java index 7a0eca0..7e740f3 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java @@ -6,7 +6,7 @@ */ package net.java.sip.communicator.impl.protocol.sip; -import gov.nist.javax.sip.header.HeaderFactoryImpl; +import gov.nist.javax.sip.header.HeaderFactoryImpl; // disambiguates Contact import gov.nist.javax.sip.header.extensions.*; import java.net.*; @@ -696,10 +696,7 @@ public class OperationSetBasicTelephonySipImpl processInviteOK(clientTransaction, response); processed = true; } - else if (method.equals(Request.BYE)) - { - // ignore - } + // Ignore the case of method.equals(Request.BYE) break; // Ringing @@ -1074,8 +1071,8 @@ public class OperationSetBasicTelephonySipImpl // !!! set sdp content before setting call state as that is where // listeners get alerted and they need the sdp // ignore sdp if we have already received one in early media - if(!CallParticipantState.CONNECTING_WITH_EARLY_MEDIA. - equals(callParticipant.getState())) + if(!CallParticipantState.CONNECTING_WITH_EARLY_MEDIA + .equals(callParticipant.getState())) callParticipant.setSdpDescription(new String(ok.getRawContent())); // notify the media manager of the sdp content @@ -1098,9 +1095,10 @@ public class OperationSetBasicTelephonySipImpl callSession .setSessionCreatorCallback(callParticipant); - String sdp = - callSession.processSdpOffer(callParticipant, - callParticipant.getSdpDescription()); + String sdp + = callSession.processSdpOffer( + callParticipant, + callParticipant.getSdpDescription()); ack.setContent(sdp, contentTypeHeader); // set the call url in case there was one @@ -1141,9 +1139,11 @@ public class OperationSetBasicTelephonySipImpl if (!CallParticipantState.CONNECTING_WITH_EARLY_MEDIA .equals(callParticipantState)) { - callSession.processSdpAnswer(callParticipant, callParticipant - .getSdpDescription()); + callSession.processSdpAnswer( + callParticipant, + callParticipant.getSdpDescription()); } + // set the call url in case there was one /** * @todo this should be done in CallSession, once we move it here. @@ -1155,20 +1155,23 @@ public class OperationSetBasicTelephonySipImpl catch (Exception exc)//Media or parse exception. { logger.error("There was an error parsing the SDP description of " - + callParticipant.getDisplayName() + "(" - + callParticipant.getAddress() + ")", exc); - try{ + + callParticipant.getDisplayName() + + "(" + callParticipant.getAddress() + ")", + exc); + try + { //we are connected from a SIP point of view (cause we sent our - //ack) sp make sure we set the state accordingly or the hangup + //ack) so make sure we set the state accordingly or the hangup //method won't know how to end the call. callParticipant.setState(CallParticipantState.CONNECTED); hangupCallParticipant(callParticipant); } - catch (Exception e){ + catch (Exception e) + { //I don't see what more we could do. logger.error(e); callParticipant.setState(CallParticipantState.FAILED, - e.getMessage()); + e.getMessage()); } return; } @@ -1788,18 +1791,15 @@ public class OperationSetBasicTelephonySipImpl CallSession callSession = ((CallSipImpl) participant.getCall()).getMediaCallSession(); - CallParticipantSipImpl sipParticipant = - (CallParticipantSipImpl) participant; - String sdpOffer = sipParticipant.getSdpDescription(); String sdpAnswer = null; try { - sdpAnswer = - callSession.createSdpDescriptionForHold( - sdpOffer, - (callSession.getSdpOfferMediaFlags(sdpOffer) - & CallSession.ON_HOLD_REMOTELY) != 0); + sdpAnswer + = callSession.processSdpOffer( + participant, + ((CallParticipantSipImpl) participant) + .getSdpDescription()); } catch (MediaException ex) { @@ -1808,8 +1808,10 @@ public class OperationSetBasicTelephonySipImpl OperationFailedException.INTERNAL_ERROR, ex); } - response.setContent(sdpAnswer, protocolProvider.getHeaderFactory() - .createContentTypeHeader("application", "sdp")); + response.setContent( + sdpAnswer, + protocolProvider.getHeaderFactory() + .createContentTypeHeader("application", "sdp")); } /** @@ -1974,26 +1976,47 @@ public class OperationSetBasicTelephonySipImpl Request ackRequest) { // find the call - CallParticipantSipImpl callParticipant = - activeCallsRepository.findCallParticipant(serverTransaction - .getDialog()); + CallParticipantSipImpl participant + = activeCallsRepository.findCallParticipant( + serverTransaction.getDialog()); - if (callParticipant == null) + if (participant == null) { // this is most probably the ack for a killed call - don't signal it logger.debug("didn't find an ack's call, returning"); return; } - ContentLengthHeader cl = ackRequest.getContentLength(); - if (cl != null && cl.getContentLength() > 0) + ContentLengthHeader contentLength = ackRequest.getContentLength(); + if ((contentLength != null) && (contentLength.getContentLength() > 0)) { - callParticipant.setSdpDescription(new String(ackRequest - .getRawContent())); + participant.setSdpDescription( + new String(ackRequest.getRawContent())); } + // change status - if (!CallParticipantState.isOnHold(callParticipant.getState())) - callParticipant.setState(CallParticipantState.CONNECTED); + CallParticipantState participantState = participant.getState(); + if (!CallParticipantState.isOnHold(participantState)) + { + if (CallParticipantState.CONNECTED.equals(participantState)) + { + try + { + ((CallSipImpl) participant.getCall()) + .getMediaCallSession() + .startStreamingAndProcessingMedia(); + } + catch (MediaException ex) + { + logger.error( + "Failed to start the streaming" + + " and the processing of the media", + ex); + } + } + else + participant.setState(CallParticipantState.CONNECTED); + } } /** @@ -2002,8 +2025,8 @@ public class OperationSetBasicTelephonySipImpl * @param serverTransaction the transaction that the cancel was received in. * @param cancelRequest the Request that we've just received. */ - void processCancel(ServerTransaction serverTransaction, - Request cancelRequest) + private void processCancel(ServerTransaction serverTransaction, + Request cancelRequest) { // find the call CallParticipantSipImpl callParticipant = @@ -2966,11 +2989,11 @@ public class OperationSetBasicTelephonySipImpl //exception as it would go to the stack and there's nothing it could //do with it. logger.error( - "Failed to created an SDP description for an ok response " - + "to an INVITE request!", + "Failed to create an SDP description for an OK response " + + "to an INVITE request!", ex); this.sayError((CallParticipantSipImpl) participant, - Response.NOT_ACCEPTABLE_HERE); + Response.NOT_ACCEPTABLE_HERE); } catch (ParseException ex) { @@ -2981,7 +3004,7 @@ public class OperationSetBasicTelephonySipImpl "Failed to parse sdp data while creating invite request!", ex); this.sayError((CallParticipantSipImpl) participant, - Response.NOT_ACCEPTABLE_HERE); + Response.NOT_ACCEPTABLE_HERE); } ContactHeader contactHeader = protocolProvider.getContactHeader( @@ -2998,7 +3021,8 @@ public class OperationSetBasicTelephonySipImpl callParticipant.setState(CallParticipantState.DISCONNECTED); throwOperationFailedException( "Failed to send an OK response to an INVITE request", - OperationFailedException.NETWORK_FAILURE, ex); + OperationFailedException.NETWORK_FAILURE, + ex); } } // answer call diff --git a/src/net/java/sip/communicator/service/media/CallSession.java b/src/net/java/sip/communicator/service/media/CallSession.java index 8e3d915..8911003 100644 --- a/src/net/java/sip/communicator/service/media/CallSession.java +++ b/src/net/java/sip/communicator/service/media/CallSession.java @@ -179,7 +179,7 @@ public interface CallSession * by the caller in their <tt>sdpOffer</tt>. * * @throws MediaException code INTERNAL_ERROR if processing the offer and/or - * generating the anser fail for some reason. + * generating the answer fail for some reason. * @throws ParseException if <tt>sdpOfferStr</tt> does not contain a valid * sdp string. */ @@ -252,6 +252,14 @@ public interface CallSession throws MediaException; /** + * Calls {@link #startStreaming() in order to start the streaming of the + * local media and then begins processing the received and sent media + * streams. + */ + public void startStreamingAndProcessingMedia() + throws MediaException; + + /** * Stops and closes the audio and video streams flowing through this * session. * |