Adds answer video call with video functionality.

cusax-fix
Vincent Lucas 14 years ago
parent 121861fccf
commit b7df011c28

@ -626,6 +626,8 @@ service.gui.AUTO_ANSWER_VALUE=Value:
service.gui.AUTO_ANSWER_DESCR_VLUE=leave empty for any
service.gui.AUTO_ANSWER_FWD_CALLS=Forward Calls
service.gui.AUTO_ANSWER_FWD_CALLS_TO=Forward all calls to the following number or URI:
service.gui.AUTO_ANSWER_VIDEO=Video
service.gui.AUTO_ANSWER_VIDEO_CALLS_WITH_VIDEO=Answer video calls with video
service.gui.security.SECURE_AUDIO=Secure audio
service.gui.security.AUDIO_NOT_SECURED=Audio not secure

@ -327,6 +327,11 @@ private class AutoAnswerOptionsDialog
*/
private JRadioButton customValueRadio;
/**
* Check box to active the video answer for wideo calls.
*/
private SIPCommCheckBox answerWithVideoCheckBox;
/**
* Custom field name text field.
*/
@ -469,6 +474,17 @@ private void initComponents()
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 @@ else if(callFwd.isSelected())
opSetAdvanced.setCallForward(
callFwdNumberField.getText());
}
opset.setAutoAnswerWithVideo(
answerWithVideoCheckBox.isSelected());
}
dispose();
@ -641,6 +660,9 @@ private void loadValues()
callFwdNumberField.setText(opSetAdvanced.getCallForward());
}
}
answerWithVideoCheckBox.setSelected(
opset.isAutoAnswerWithVideoSet());
}
}
}

@ -162,6 +162,21 @@ public CallPeerGTalkImpl processGTalkInitiate(SessionIQ sessionIQ)
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;
}

@ -303,6 +303,18 @@ else if(MediaType.VIDEO.toString().equals(contentName))
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;
}

@ -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 @@
* 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 @@ private void save()
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);
}
}

@ -1042,16 +1042,6 @@ && getFullCalleeURI(attendant.getAddress())
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 void run()
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)

@ -1697,7 +1697,7 @@ protected void initialize(String screenname,
addSupportedOperationSet(
OperationSetBasicAutoAnswer.class,
new OperationSetAutoAnswerJabberImpl(basicTelephony));
new OperationSetAutoAnswerJabberImpl(this));
// init DTMF
OperationSetDTMFJabberImpl operationSetDTMFSip

@ -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 @@
* 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.
@ -36,16 +39,6 @@ public class OperationSetAutoAnswerSipImpl
private static final Logger logger =
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.
*/
@ -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 @@ private void load()
/**
* 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 @@ else if(!StringUtils.isNullOrEmpty(callFwdTo))
{
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 void setAutoAnswerCondition(String headerName, String value)
/**
* 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 boolean isAutoAnswerConditionSet()
/**
* 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 void setCallForward(String numberTo)
/**
* 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,27 +188,19 @@ public String getCallForward()
/**
* Clear local settings.
*/
private void clearLocal()
protected void clearLocal()
{
this.answerUnconditional = false;
super.clearLocal();
this.answerConditional = false;
this.headerName = null;
this.headerValue = null;
this.callFwdTo = null;
}
/**
* 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 String getAutoAnswerHeaderName()
/**
* 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 String getAutoAnswerHeaderValue()
/**
* 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 @@ boolean preCallCheck(Request invite,
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 @@ boolean preCallCheck(Request invite,
}
/**
* 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;
}
}

@ -1051,9 +1051,9 @@ private void processInvite(SipProvider sourceProvider,
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 @@ private void processInvite(SipProvider sourceProvider,
// 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 @@ private void processInvite(SipProvider sourceProvider,
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
{

@ -419,9 +419,8 @@ protected void initialize(String sipAddress,
OperationSetAdvancedTelephony.class,
opSetBasicTelephonySipImpl);
OperationSetAutoAnswerSipImpl autoAnswerOpSet =
new OperationSetAutoAnswerSipImpl(
opSetBasicTelephonySipImpl);
OperationSetAutoAnswerSipImpl autoAnswerOpSet
= new OperationSetAutoAnswerSipImpl(this);
addSupportedOperationSet(
OperationSetBasicAutoAnswer.class, autoAnswerOpSet);
addSupportedOperationSet(

@ -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);
}
}
}
}

@ -21,6 +21,12 @@ public interface OperationSetBasicAutoAnswer
public static final String AUTO_ANSWER_UNCOND_PROP =
"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.
*/
@ -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();
}

Loading…
Cancel
Save