diff options
author | Vincent Lucas <chenzo@jitsi.org> | 2012-05-25 15:24:04 +0000 |
---|---|---|
committer | Vincent Lucas <chenzo@jitsi.org> | 2012-05-25 15:24:04 +0000 |
commit | b7df011c28671b65a5c151df6f3b7011260e44bd (patch) | |
tree | b202efb8956eca2011953154c2b428ba72f711e2 /src/net/java/sip/communicator | |
parent | 121861fccf57a9887bee7cc8a7a23d0aef9873a0 (diff) | |
download | jitsi-b7df011c28671b65a5c151df6f3b7011260e44bd.zip jitsi-b7df011c28671b65a5c151df6f3b7011260e44bd.tar.gz jitsi-b7df011c28671b65a5c151df6f3b7011260e44bd.tar.bz2 |
Adds answer video call with video functionality.
Diffstat (limited to 'src/net/java/sip/communicator')
11 files changed, 543 insertions, 313 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/menus/AutoAnswerMenu.java b/src/net/java/sip/communicator/impl/gui/main/menus/AutoAnswerMenu.java index 371bf4a..2d9563c 100644 --- a/src/net/java/sip/communicator/impl/gui/main/menus/AutoAnswerMenu.java +++ b/src/net/java/sip/communicator/impl/gui/main/menus/AutoAnswerMenu.java @@ -328,6 +328,11 @@ public class AutoAnswerMenu private JRadioButton customValueRadio; /** + * Check box to active the video answer for wideo calls. + */ + private SIPCommCheckBox answerWithVideoCheckBox; + + /** * Custom field name text field. */ private JTextField headerNameField = new JTextField(); @@ -469,6 +474,17 @@ public class AutoAnswerMenu c.insets = new Insets(10, 0, 0, 0); } + c.gridy = currentRow++; + mainPanel.add( + getTitlePanel( + R.getI18NString("service.gui.AUTO_ANSWER_VIDEO")), + c); + c.gridy = currentRow++; + answerWithVideoCheckBox = new SIPCommCheckBox( + R.getI18NString( + "service.gui.AUTO_ANSWER_VIDEO_CALLS_WITH_VIDEO")); + mainPanel.add(answerWithVideoCheckBox, c); + TransparentPanel buttonsPanel = new TransparentPanel(new FlowLayout(FlowLayout.RIGHT)); @@ -580,6 +596,9 @@ public class AutoAnswerMenu opSetAdvanced.setCallForward( callFwdNumberField.getText()); } + + opset.setAutoAnswerWithVideo( + answerWithVideoCheckBox.isSelected()); } dispose(); @@ -641,6 +660,9 @@ public class AutoAnswerMenu callFwdNumberField.setText(opSetAdvanced.getCallForward()); } } + + answerWithVideoCheckBox.setSelected( + opset.isAutoAnswerWithVideoSet()); } } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallGTalkImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallGTalkImpl.java index abc7eeb..c067c51 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/CallGTalkImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallGTalkImpl.java @@ -162,6 +162,21 @@ public class CallGTalkImpl if(this.getCallPeerCount() == 1 && this.getCallGroup() == null) parentOpSet.fireCallEvent( CallEvent.CALL_RECEIVED, this); + // Manages auto answer with "audio only", or "audio / video" answer. + OperationSetAutoAnswerJabberImpl autoAnswerOpSet + = (OperationSetAutoAnswerJabberImpl) + this.getProtocolProvider() + .getOperationSet(OperationSetBasicAutoAnswer.class); + + if(autoAnswerOpSet != null) + { + // With Gtalk, we do not actually supports the detection if the + // incoming call is a video call (cf. the fireCallEvent above with + // only 2 arguments). Thus, we set the auto-answer video + // parameter to false. + autoAnswerOpSet.autoAnswer(this, false); + } + return callPeer; } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java index 6b81c16..44d43a2 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java @@ -303,6 +303,18 @@ public class CallJabberImpl parentOpSet.fireCallEvent(CallEvent.CALL_RECEIVED, this, directions); + // Manages auto answer with "audio only", or "audio / video" answer. + OperationSetAutoAnswerJabberImpl autoAnswerOpSet + = (OperationSetAutoAnswerJabberImpl) + this.getProtocolProvider() + .getOperationSet(OperationSetBasicAutoAnswer.class); + + if(autoAnswerOpSet != null) + { + autoAnswerOpSet.autoAnswer(this, directions); + } + + return callPeer; } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetAutoAnswerJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetAutoAnswerJabberImpl.java index af07efc..12343d1 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetAutoAnswerJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetAutoAnswerJabberImpl.java @@ -6,6 +6,7 @@ */ package net.java.sip.communicator.impl.protocol.jabber; +import net.java.sip.communicator.service.neomedia.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; @@ -17,59 +18,29 @@ import java.util.*; * calls. * * @author Damian Minkov + * @author Vincent Lucas */ public class OperationSetAutoAnswerJabberImpl - extends CallPeerAdapter - implements OperationSetBasicAutoAnswer + extends AbstractOperationSetBasicAutoAnswer { /** - * Our class logger. - */ - private static final Logger logger - = Logger.getLogger(OperationSetAutoAnswerJabberImpl.class); - - /** - * Should we unconditionally answer. - */ - private boolean answerUnconditional = false; - - /** - * The parent operation set. - */ - private final OperationSetBasicTelephonyJabberImpl telephonyJabber; - - /** * Creates this operation set, loads stored values, populating * local variable settings. * - * @param telephonyJabber the parent opset. - */ - OperationSetAutoAnswerJabberImpl( - OperationSetBasicTelephonyJabberImpl telephonyJabber) - { - this.telephonyJabber = telephonyJabber; - - // init values from account props - load(); - } - - /** - * Load values from account properties. + * @param protocolProvider the parent Protocol Provider. */ - private void load() + public OperationSetAutoAnswerJabberImpl( + ProtocolProviderServiceJabberImpl protocolProvider) { - AccountID acc = telephonyJabber.getProtocolProvider().getAccountID(); - - answerUnconditional - = acc.getAccountPropertyBoolean(AUTO_ANSWER_UNCOND_PROP, false); + super(protocolProvider); } /** * Saves values to account properties. */ - private void save() + protected void save() { - AccountID acc = telephonyJabber.getProtocolProvider().getAccountID(); + AccountID acc = protocolProvider.getAccountID(); Map<String, String> accProps = acc.getAccountProperties(); // lets clear anything before saving :) @@ -78,124 +49,50 @@ public class OperationSetAutoAnswerJabberImpl if(answerUnconditional) accProps.put(AUTO_ANSWER_UNCOND_PROP, Boolean.TRUE.toString()); + accProps.put(AUTO_ANSWER_WITH_VIDEO_PROP, + Boolean.toString(this.answerWithVideo)); + acc.setAccountProperties(accProps); JabberActivator.getProtocolProviderFactory().storeAccount(acc); } /** - * Sets the auto answer option to unconditionally answer all incoming calls. - */ - public void setAutoAnswerUnconditional() - { - clearLocal(); - - this.answerUnconditional = true; - - save(); - } - - /** - * Is the auto answer option set to unconditionally - * answer all incoming calls. - * @return is auto answer set to unconditional. - */ - public boolean isAutoAnswerUnconditionalSet() - { - return answerUnconditional; - } - - /** - * Clear local settings. - */ - private void clearLocal() - { - this.answerUnconditional = false; - } - - /** - * Clear any previous settings. + * Checks if the call satisfy the auto answer conditions. + * + * @param call The new incoming call to auto-answer if needed. + * + * @return <tt>true</tt> if the call satisfy the auto answer conditions. + * <tt>False</tt> otherwise. */ - public void clear() + protected boolean satisfyAutoAnswerConditions(Call call) { - clearLocal(); - - save(); + // Nothing to do here, as long as the jabber account does not implements + // advanced auto answer functionnalities. + return false; } /** - * Makes a check after creating call locally, should we answer it. - * @param call the created call to answer if needed. + * Auto-answers to a call with "audio only" or "audio/video" if the incoming + * call is a video call. + * + * @param call The new incoming call to auto-answer if needed. + * @param directions The media type (audio / video) stream directions. + * * @return <tt>true</tt> if we have processed and no further processing is * needed, <tt>false</tt> otherwise. */ - boolean followCallCheck(AbstractCall<?, ?> call) - { - if(!answerUnconditional) - return false; - - // We are here because we satisfy the conditional, or unconditional is - // true. - Iterator<? extends CallPeer> peers = call.getCallPeers(); - - while (peers.hasNext()) - answerPeer(peers.next()); - - return true; - } - - /** - * Answers call if peer in correct state or wait for it. - * @param peer the peer to check and answer. - */ - private void answerPeer(final CallPeer peer) + public boolean autoAnswer( + Call call, + Map<MediaType, MediaDirection> directions) { - CallPeerState state = peer.getState(); + boolean isVideoCall = false; + MediaDirection direction = directions.get(MediaType.VIDEO); - if (state == CallPeerState.INCOMING_CALL) - { - // answer in separate thread, don't block current processing - new Thread(new Runnable() - { - public void run() - { - try - { - telephonyJabber.answerCallPeer(peer); - } - catch (OperationFailedException e) - { - logger.error("Could not answer to : " + peer - + " caused by the following exception: " + e); - } - } - }, getClass().getName()).start(); - } - else + if(direction != null) { - peer.addCallPeerListener(this); + isVideoCall = (direction == MediaDirection.SENDRECV); } - } - /** - * If we peer was not in proper state wait for it and then answer. - * @param evt the <tt>CallPeerChangeEvent</tt> instance containing the - */ - public void peerStateChanged(CallPeerChangeEvent evt) - { - CallPeerState newState = (CallPeerState) evt.getNewValue(); - - if (newState == CallPeerState.INCOMING_CALL) - { - CallPeer peer = evt.getSourceCallPeer(); - - peer.removeCallPeerListener(this); - - answerPeer(peer); - } - else if (newState == CallPeerState.DISCONNECTED - || newState == CallPeerState.FAILED) - { - evt.getSourceCallPeer().removeCallPeerListener(this); - } + return super.autoAnswer(call, isVideoCall); } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java index 731b892..c012e7a 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java @@ -1042,16 +1042,6 @@ public class OperationSetBasicTelephonyJabberImpl public void run() { callThread.processSessionInitiate(jingleIQ); - - OperationSetAutoAnswerJabberImpl autoAnswerOpSet = - (OperationSetAutoAnswerJabberImpl)protocolProvider - .getOperationSet(OperationSetBasicAutoAnswer.class); - - if(autoAnswerOpSet != null - && autoAnswerOpSet.isAutoAnswerUnconditionalSet()) - { - autoAnswerOpSet.followCallCheck(callThread); - } } }.start(); @@ -1245,16 +1235,6 @@ public class OperationSetBasicTelephonyJabberImpl CallGTalkImpl call = new CallGTalkImpl(this); call.processGTalkInitiate(sessionIQ); - OperationSetAutoAnswerJabberImpl autoAnswerOpSet = - (OperationSetAutoAnswerJabberImpl)protocolProvider - .getOperationSet(OperationSetBasicAutoAnswer.class); - - if(autoAnswerOpSet != null - && autoAnswerOpSet.isAutoAnswerUnconditionalSet()) - { - autoAnswerOpSet.followCallCheck(call); - } - return; } else if (callPeer == null) diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java index e9e133d..ecdf983 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java @@ -1697,7 +1697,7 @@ public class ProtocolProviderServiceJabberImpl addSupportedOperationSet( OperationSetBasicAutoAnswer.class, - new OperationSetAutoAnswerJabberImpl(basicTelephony)); + new OperationSetAutoAnswerJabberImpl(this)); // init DTMF OperationSetDTMFJabberImpl operationSetDTMFSip diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetAutoAnswerSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetAutoAnswerSipImpl.java index a8bc35f..8883317 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetAutoAnswerSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetAutoAnswerSipImpl.java @@ -7,14 +7,17 @@ package net.java.sip.communicator.impl.protocol.sip; import gov.nist.javax.sip.header.*; +import net.java.sip.communicator.impl.protocol.sip.sdp.*; +import net.java.sip.communicator.service.neomedia.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; import javax.sip.*; import javax.sip.address.*; -import javax.sip.header.*; +import javax.sip.header.ContactHeader; // Disambiguation. import javax.sip.message.*; +import javax.sdp.*; import java.util.*; /** @@ -24,11 +27,11 @@ import java.util.*; * on existence of specified header name and value. * * @author Damian Minkov + * @author Vincent Lucas */ public class OperationSetAutoAnswerSipImpl - extends CallPeerAdapter - implements OperationSetBasicAutoAnswer, - OperationSetAdvancedAutoAnswer + extends AbstractOperationSetBasicAutoAnswer + implements OperationSetAdvancedAutoAnswer { /** * Our class logger. @@ -37,16 +40,6 @@ public class OperationSetAutoAnswerSipImpl Logger.getLogger(OperationSetBasicTelephonySipImpl.class); /** - * The parent operation set. - */ - private OperationSetBasicTelephonySipImpl telephonySip; - - /** - * Should we unconditionally answer. - */ - private boolean answerUnconditional = false; - - /** * Should we answer on existence of some header and/or name. */ private boolean answerConditional = false; @@ -70,26 +63,22 @@ public class OperationSetAutoAnswerSipImpl * Creates this operation set, loads stored values, populating * local variable settings. * - * @param telephonySip the parent opset. + * @param protocolProvider the parent Protocol Provider. */ - OperationSetAutoAnswerSipImpl( - OperationSetBasicTelephonySipImpl telephonySip) + public OperationSetAutoAnswerSipImpl( + ProtocolProviderServiceSipImpl protocolProvider) { - this.telephonySip = telephonySip; - - // init values from account props - load(); + super(protocolProvider); } /** * Load values from account properties. */ - private void load() + protected void load() { - AccountID acc = telephonySip.getProtocolProvider().getAccountID(); + super.load(); - answerUnconditional = - acc.getAccountPropertyBoolean(AUTO_ANSWER_UNCOND_PROP, false); + AccountID acc = protocolProvider.getAccountID(); headerName = acc.getAccountPropertyString(AUTO_ANSWER_COND_NAME_PROP); @@ -105,9 +94,9 @@ public class OperationSetAutoAnswerSipImpl /** * Saves values to account properties. */ - private void save() + protected void save() { - AccountID acc = telephonySip.getProtocolProvider().getAccountID(); + AccountID acc = protocolProvider.getAccountID(); Map<String, String> accProps = acc.getAccountProperties(); // lets clear anything before saving :) @@ -131,38 +120,20 @@ public class OperationSetAutoAnswerSipImpl { accProps.put(AUTO_ANSWER_FWD_NUM_PROP, callFwdTo); } + accProps.put( + AUTO_ANSWER_WITH_VIDEO_PROP, + Boolean.toString(answerWithVideo)); acc.setAccountProperties(accProps); SipActivator.getProtocolProviderFactory().storeAccount(acc); } /** - * Sets the auto answer option to unconditionally answer all incoming calls. - */ - public void setAutoAnswerUnconditional() - { - clearLocal(); - - this.answerUnconditional = true; - - save(); - } - - /** - * Is the auto answer option set to unconditionally - * answer all incoming calls. - * @return is auto answer set to unconditional. - */ - public boolean isAutoAnswerUnconditionalSet() - { - return answerUnconditional; - } - - /** * Sets a specified header and its value if they exist in the incoming * call packet this will activate auto answer. * If value is empty or null it will be considered as any (will search * only for a header with that name and ignore the value) + * * @param headerName the name of the header to search * @param value the value for the header, can be null. */ @@ -180,6 +151,7 @@ public class OperationSetAutoAnswerSipImpl /** * Is the auto answer option set to conditionally * answer all incoming calls. + * * @return is auto answer set to conditional. */ public boolean isAutoAnswerConditionSet() @@ -190,6 +162,7 @@ public class OperationSetAutoAnswerSipImpl /** * Set to automatically forward all calls to the specified * number using the same provider. + * * @param numberTo number to use for forwarding */ public void setCallForward(String numberTo) @@ -203,7 +176,8 @@ public class OperationSetAutoAnswerSipImpl /** * Get the value for automatically forward all calls to the specified - * number using the same provider.. + * number using the same provider. + * * @return numberTo number to use for forwarding */ public String getCallForward() @@ -214,9 +188,10 @@ public class OperationSetAutoAnswerSipImpl /** * Clear local settings. */ - private void clearLocal() + protected void clearLocal() { - this.answerUnconditional = false; + super.clearLocal(); + this.answerConditional = false; this.headerName = null; this.headerValue = null; @@ -224,17 +199,8 @@ public class OperationSetAutoAnswerSipImpl } /** - * Clear any previous settings. - */ - public void clear() - { - clearLocal(); - - save(); - } - - /** * Returns the name of the header if conditional auto answer is set. + * * @return the name of the header if conditional auto answer is set. */ public String getAutoAnswerHeaderName() @@ -244,6 +210,7 @@ public class OperationSetAutoAnswerSipImpl /** * Returns the value of the header for the conditional auto answer. + * * @return the value of the header for the conditional auto answer. */ public String getAutoAnswerHeaderValue() @@ -253,13 +220,16 @@ public class OperationSetAutoAnswerSipImpl /** * Makes a check before locally creating call, should we just forward it. + * * @param invite the current invite to check. * @param serverTransaction the transaction. + * * @return <tt>true</tt> if we have processed and no further processing is * needed, <tt>false</tt> otherwise. */ - boolean preCallCheck(Request invite, - ServerTransaction serverTransaction) + public boolean forwardCall( + Request invite, + ServerTransaction serverTransaction) { if(StringUtils.isNullOrEmpty(callFwdTo)) return false; @@ -270,13 +240,15 @@ public class OperationSetAutoAnswerSipImpl if (logger.isTraceEnabled()) logger.trace("will send moved temporally response: "); - response = telephonySip.getProtocolProvider().getMessageFactory() + response = ((ProtocolProviderServiceSipImpl) protocolProvider) + .getMessageFactory() .createResponse(Response.MOVED_TEMPORARILY, invite); ContactHeader contactHeader = - (ContactHeader)response.getHeader(ContactHeader.NAME); + (ContactHeader)response.getHeader(ContactHeader.NAME); AddressFactory addressFactory = - telephonySip.getProtocolProvider().getAddressFactory(); + ((ProtocolProviderServiceSipImpl) protocolProvider) + .getAddressFactory(); String destination = getCallForward(); if(!destination.startsWith("sip")) @@ -300,105 +272,117 @@ public class OperationSetAutoAnswerSipImpl } /** - * Makes a check after creating call locally, should we answer it. - * @param invite the current invite to check. - * @param call the created call to answer if needed. - * @return <tt>true</tt> if we have processed and no further processing is - * needed, <tt>false</tt> otherwise. + * Checks if the call satisfy the auto answer conditions. + * + * @param call The new incoming call to auto-answer if needed. + * + * @return <tt>true</tt> if the call satisfy the auto answer conditions. + * <tt>False</tt> otherwise. */ - boolean followCallCheck(Request invite, - CallSipImpl call) + protected boolean satisfyAutoAnswerConditions(Call call) { - if(!(answerConditional || answerUnconditional)) - return false; + Iterator<? extends CallPeer> peers = call.getCallPeers(); + CallPeer peer; // lets check for headers if(answerConditional) { - SIPHeader callAnswerHeader = - (SIPHeader)invite.getHeader(headerName); - - if(callAnswerHeader == null) - return false; - - if(!StringUtils.isNullOrEmpty(headerValue)) + while(peers.hasNext()) { - String value = callAnswerHeader.getHeaderValue(); + peer = peers.next(); + Transaction transaction = ((CallPeerSipImpl) peer) + .getLatestInviteTransaction(); + if(transaction != null) + { + Request invite = transaction.getRequest(); + SIPHeader callAnswerHeader = (SIPHeader) + invite.getHeader(headerName); - if(value == null || !headerValue.equals(value)) - return false; + if(callAnswerHeader != null) + { + if(!StringUtils.isNullOrEmpty(headerValue)) + { + String value = callAnswerHeader.getHeaderValue(); + + if(value != null && headerValue.equals(value)) + { + return true; + } + } + } + } } } + return false; + } - // we are here cause we satisfy the conditional, - // or unconditional is true - Iterator<? extends CallPeer> peers = call.getCallPeers(); - - while (peers.hasNext()) + /** + * Makes a check after creating call locally, should we answer it. + * + * @param call The new incoming call to auto-answer if needed. + * @param isVideoCall Indicates if the remote peer which has created this + * call wish to have a video call. + * + * @return <tt>true</tt> if we have processed and no further processing is + * needed, <tt>false</tt> otherwise. + */ + public boolean autoAnswer(Call call) + { + if(answerUnconditional || satisfyAutoAnswerConditions(call)) { - final CallPeer peer = peers.next(); - - answerPeer(peer); + boolean isVideoCall = doesRequestContainsActiveVideoMediaType(call); + this.answerCall(call, isVideoCall); + return true; } - - return true; + return false; } /** - * Answers call if peer in correct state or wait for it. - * @param peer the peer to check and answer. + * Detects if the incoming call is a video call. Parses the SDP from the SIP + * request to determine if the video is active. + * + * @param call The new incoming call to auto-answer if needed. + * + * @return True if the incoming call is a video call. False, otherwise. */ - private void answerPeer(final CallPeer peer) + private boolean doesRequestContainsActiveVideoMediaType(Call call) { - CallPeerState state = peer.getState(); + Iterator<? extends CallPeer> peers = call.getCallPeers(); - if (state == CallPeerState.INCOMING_CALL) + while(peers.hasNext()) { - // answer in separate thread, don't block current - // processing - new Thread(new Runnable() + Transaction transaction = ((CallPeerSipImpl) peers.next()) + .getLatestInviteTransaction(); + if(transaction != null) { - public void run() + Request inviteReq = transaction.getRequest(); + + if(inviteReq != null && inviteReq.getRawContent() != null) { - try + String sdpStr = SdpUtils.getContentAsString(inviteReq); + SessionDescription sesDescr + = SdpUtils.parseSdpString(sdpStr); + List<MediaDescription> remoteDescriptions + = SdpUtils.extractMediaDescriptions(sesDescr); + + for (MediaDescription mediaDescription : + remoteDescriptions) { - telephonySip.answerCallPeer(peer); - } - catch (OperationFailedException e) - { - logger.error("Could not answer to : " + peer - + " caused by the following exception: " + e); + if(SdpUtils.getMediaType(mediaDescription) + == MediaType.VIDEO) + { + if(SdpUtils.getDirection(mediaDescription) + == MediaDirection.SENDRECV) + { + return true; + } + + } } } - }, getClass().getName()).start(); - } - else - { - peer.addCallPeerListener(this); + } } - } - /** - * If we peer was not in proper state wait for it and then answer. - * @param evt the <tt>CallPeerChangeEvent</tt> instance containing the - */ - public void peerStateChanged(CallPeerChangeEvent evt) - { - - CallPeerState newState = (CallPeerState) evt.getNewValue(); - - if (newState == CallPeerState.INCOMING_CALL) - { - CallPeer peer = evt.getSourceCallPeer(); - - peer.removeCallPeerListener(this); - - answerPeer(peer); - } - else if (newState == CallPeerState.DISCONNECTED - || newState == CallPeerState.FAILED) - { - evt.getSourceCallPeer().removeCallPeerListener(this); - } + return false; } } 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 839f7f1..d1eb25e 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java @@ -1051,9 +1051,9 @@ public class OperationSetBasicTelephonySipImpl CallPeerSipImpl existingPeer = activeCallsRepository.findCallPeer(dialog); - OperationSetAutoAnswerSipImpl autoAnswerOpSet = - (OperationSetAutoAnswerSipImpl) - protocolProvider.getOperationSet(OperationSetBasicAutoAnswer.class); + OperationSetAutoAnswerSipImpl autoAnswerOpSet + = (OperationSetAutoAnswerSipImpl) protocolProvider.getOperationSet( + OperationSetBasicAutoAnswer.class); if(existingPeer == null) { @@ -1067,7 +1067,7 @@ public class OperationSetBasicTelephonySipImpl // checks for forward of call, if no further processing // is needed return if(autoAnswerOpSet != null - && autoAnswerOpSet.preCallCheck(invite, serverTransaction)) + && autoAnswerOpSet.forwardCall(invite, serverTransaction)) return; //this is a brand new call (not a transferred one) @@ -1125,12 +1125,12 @@ public class OperationSetBasicTelephonySipImpl return; } - - // checks for auto answering of call, if no further processing - // is needed return - if(autoAnswerOpSet != null - && autoAnswerOpSet.followCallCheck(invite, call)) - return; + // Manages auto answer with "audio only", or "audio / video" + // answer. + if(autoAnswerOpSet != null) + { + autoAnswerOpSet.autoAnswer(call); + } } else { diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java index f7bc2e9..6602f4a 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java @@ -419,9 +419,8 @@ public class ProtocolProviderServiceSipImpl OperationSetAdvancedTelephony.class, opSetBasicTelephonySipImpl); - OperationSetAutoAnswerSipImpl autoAnswerOpSet = - new OperationSetAutoAnswerSipImpl( - opSetBasicTelephonySipImpl); + OperationSetAutoAnswerSipImpl autoAnswerOpSet + = new OperationSetAutoAnswerSipImpl(this); addSupportedOperationSet( OperationSetBasicAutoAnswer.class, autoAnswerOpSet); addSupportedOperationSet( diff --git a/src/net/java/sip/communicator/service/protocol/AbstractOperationSetBasicAutoAnswer.java b/src/net/java/sip/communicator/service/protocol/AbstractOperationSetBasicAutoAnswer.java new file mode 100644 index 0000000..f90e4b1 --- /dev/null +++ b/src/net/java/sip/communicator/service/protocol/AbstractOperationSetBasicAutoAnswer.java @@ -0,0 +1,298 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.protocol; + +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; + +import java.util.*; + +/** + * An Abstract Operation Set defining option to unconditionally auto answer + * incoming calls. + * + * @author Damian Minkov + * @author Vincent Lucas + */ +public abstract class AbstractOperationSetBasicAutoAnswer + implements OperationSetBasicAutoAnswer +{ + /** + * Our class logger. + */ + private static final Logger logger + = Logger.getLogger(AbstractOperationSetBasicAutoAnswer.class); + + /** + * The parent Protocol Provider. + */ + protected final ProtocolProviderService protocolProvider; + + /** + * Should we unconditionally answer. + */ + protected boolean answerUnconditional = false; + + /** + * Should we answer video calls with video. + */ + protected boolean answerWithVideo = false; + + /** + * Creates this operation set, loads stored values, populating + * local variable settings. + * + * @param protocolProvider the parent Protocol Provider. + */ + public AbstractOperationSetBasicAutoAnswer( + ProtocolProviderService protocolProvider) + { + this.protocolProvider = protocolProvider; + + // init values from account props + load(); + } + + /** + * Load values from account properties. + */ + protected void load() + { + AccountID acc = protocolProvider.getAccountID(); + + answerUnconditional + = acc.getAccountPropertyBoolean(AUTO_ANSWER_UNCOND_PROP, false); + answerWithVideo + = acc.getAccountPropertyBoolean(AUTO_ANSWER_WITH_VIDEO_PROP, false); + } + + /** + * Saves values to account properties. + */ + protected abstract void save(); + + /** + * Clear local settings. + */ + protected void clearLocal() + { + this.answerUnconditional = false; + } + + /** + * Clear any previous settings. + */ + public void clear() + { + clearLocal(); + + this.answerWithVideo = false; + + save(); + } + + /** + * Makes a check after creating call locally, should we answer it. + * + * @param call The new incoming call to auto-answer if needed. + * @param isVideoCall Indicates if the remote peer which has created this + * call wish to have a video call. + * + * @return <tt>true</tt> if we have processed and no further processing is + * needed, <tt>false</tt> otherwise. + */ + public boolean autoAnswer(Call call, boolean isVideoCall) + { + if(answerUnconditional || satisfyAutoAnswerConditions(call)) + { + this.answerCall(call, isVideoCall); + return true; + } + return false; + } + + + /** + * Answers call if peer in correct state or wait for it. + * + * @param call The new incoming call to auto-answer if needed. + * @param isVideoCall Indicates if the remote peer which has created this + * call wish to have a video call. + */ + protected void answerCall(Call call, boolean isVideoCall) + { + // We are here because we satisfy the conditional, or unconditional is + // true. + Iterator<? extends CallPeer> peers = call.getCallPeers(); + + while (peers.hasNext()) + { + new AutoAnswerThread(peers.next(), isVideoCall); + } + } + + /** + * Checks if the call satisfy the auto answer conditions. + * + * @param call The new incoming call to auto-answer if needed. + * + * @return <tt>true</tt> if the call satisfy the auto answer conditions. + * <tt>False</tt> otherwise. + */ + protected abstract boolean satisfyAutoAnswerConditions(Call call); + + /** + * Sets the auto answer option to unconditionally answer all incoming calls. + */ + public void setAutoAnswerUnconditional() + { + clearLocal(); + + this.answerUnconditional = true; + + save(); + } + + /** + * Is the auto answer option set to unconditionally + * answer all incoming calls. + * + * @return is auto answer set to unconditional. + */ + public boolean isAutoAnswerUnconditionalSet() + { + return answerUnconditional; + } + + /** + * Sets the auto answer with video to video calls. + * + * @param answerWithVideo A boolean set to true to activate the auto answer + * with video when receiving a video call. False otherwise. + */ + public void setAutoAnswerWithVideo(boolean answerWithVideo) + { + this.answerWithVideo = answerWithVideo; + this.save(); + } + + /** + * Returns if the auto answer with video to video calls is activated. + * + * @return A boolean set to true if the auto answer with video when + * receiving a video call is activated. False otherwise. + */ + public boolean isAutoAnswerWithVideoSet() + { + return this.answerWithVideo; + } + + /** + * Waits for peer to switch into INCOMING_CALL state, before + * auto-answering the call in a new thread. + */ + private class AutoAnswerThread + extends CallPeerAdapter + implements Runnable + { + /** + * The call peer which has generated the call. + */ + private CallPeer peer; + + /** + * Indicates if the remote peer which has created this call wish to have + * a video call. + */ + private boolean isVideoCall; + + /** + * Waits for peer to switch into INCOMING_CALL state, before + * auto-answering the call in a new thread. + * + * @param peer The call peer which has generated the call. + * @param isVideoCall Indicates if the remote peer which has created + * this call wish to have a video call. + */ + public AutoAnswerThread(CallPeer peer, boolean isVideoCall) + { + this.peer = peer; + this.isVideoCall = isVideoCall; + + if (peer.getState() == CallPeerState.INCOMING_CALL) + { + new Thread(this).start(); + } + else + { + peer.addCallPeerListener(this); + } + + } + + /** + * Answers the call. + */ + public void run() + { + OperationSetBasicAutoAnswer opSetBasicAutoAnswer + = protocolProvider.getOperationSet( + OperationSetBasicAutoAnswer.class); + OperationSetBasicTelephony opSetBasicTelephony + = protocolProvider.getOperationSet( + OperationSetBasicTelephony.class); + OperationSetVideoTelephony opSetVideoTelephony + = protocolProvider.getOperationSet( + OperationSetVideoTelephony.class); + try + { + // If this is a video call and that the user has configured to + // answer it with wideo, then create a video call. + if(this.isVideoCall + && answerWithVideo + && opSetVideoTelephony != null) + { + System.out.println("CHENZO: VIDEO"); + opSetVideoTelephony.answerVideoCallPeer(peer); + } + // Else sends only audio to the repote peer (the remote peer is + // still able to send us its video stream). + else if(opSetBasicTelephony != null) + { + System.out.println("CHENZO: AUDIO"); + opSetBasicTelephony.answerCallPeer(peer); + } + } + catch (OperationFailedException e) + { + logger.error("Could not answer to : " + peer + + " caused by the following exception: " + e); + } + } + + /** + * If we peer was not in proper state wait for it and then answer. + * + * @param evt the <tt>CallPeerChangeEvent</tt> instance containing the + */ + public void peerStateChanged(CallPeerChangeEvent evt) + { + CallPeerState newState = (CallPeerState) evt.getNewValue(); + + if (newState == CallPeerState.INCOMING_CALL) + { + evt.getSourceCallPeer().removeCallPeerListener(this); + new Thread(this).start(); + } + else if (newState == CallPeerState.DISCONNECTED + || newState == CallPeerState.FAILED) + { + evt.getSourceCallPeer().removeCallPeerListener(this); + } + } + } +} diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetBasicAutoAnswer.java b/src/net/java/sip/communicator/service/protocol/OperationSetBasicAutoAnswer.java index cdb3b46..ca7ad65 100644 --- a/src/net/java/sip/communicator/service/protocol/OperationSetBasicAutoAnswer.java +++ b/src/net/java/sip/communicator/service/protocol/OperationSetBasicAutoAnswer.java @@ -22,6 +22,12 @@ public interface OperationSetBasicAutoAnswer "AUTO_ANSWER_UNCONDITIONAL"; /** + * Auto answer video calls with video account property. + */ + public static final String AUTO_ANSWER_WITH_VIDEO_PROP = + "AUTO_ANSWER_WITH_VIDEO"; + + /** * Sets the auto answer option to unconditionally answer all incoming calls. */ public void setAutoAnswerUnconditional(); @@ -37,4 +43,21 @@ public interface OperationSetBasicAutoAnswer * Clear any previous settings. */ public void clear(); + + /** + * Sets the auto answer with video to video calls. + * + * @param answerWithVideo A boolean set to true to activate the auto answer + * with video when receiving a video call. False otherwise. + */ + public void setAutoAnswerWithVideo(boolean answerWithVideo); + + /** + * Returns if the auto answer with video to video calls is activated. + * + * @return A boolean set to true if the auto answer with video when + * receiving a video call is activated. False otherwise. + */ + public boolean isAutoAnswerWithVideoSet(); + } |