Commits work in progress on improving, stabalising audio and video telephony conferencing.

cusax-fix
Lyubomir Marinov 13 years ago
parent 8b55f38090
commit 93d702f9b0

@ -31,7 +31,6 @@
import org.jitsi.service.neomedia.*;
import org.jitsi.service.neomedia.device.*;
import org.jitsi.service.resources.*;
import org.jitsi.util.*;
/**
* The <tt>CallManager</tt> is the one that handles calls. It contains also
@ -44,17 +43,11 @@
public class CallManager
{
/**
* Our class logger.
* The <tt>Logger</tt> used by the <tt>CallManager</tt> class and its
* instances for logging output.
*/
private static final Logger logger = Logger.getLogger(CallManager.class);
/**
* A table mapping protocol <tt>Call</tt> objects to the GUI dialogs
* that are currently used to display them.
*/
private static Hashtable<Call, CallPanel> activeCalls
= new Hashtable<Call, CallPanel>();
/**
* The name of the property which indicates whether the user should be
* warned when starting a desktop sharing session.
@ -63,44 +56,44 @@ public class CallManager
= "net.java.sip.communicator.impl.gui.main"
+ ".call.SHOW_DESKTOP_SHARING_WARNING";
/**
* The <tt>CallPanel</tt>s opened by <tt>CallManager</tt> (because
* <tt>CallContainer</tt> does not give access to such lists.)
*/
private static final Map<CallConference, CallPanel> callPanels
= new HashMap<CallConference, CallPanel>();
/**
* The group of notifications dedicated to missed calls.
*/
private static UINotificationGroup missedCallGroup;
/**
* A call listener.
* A <tt>CallListener</tt>.
*/
public static class GuiCallListener
implements CallListener
extends SwingCallListener
{
/**
* Implements {@link CallListener#incomingCallReceived(CallEvent)}. When
* a call is received, creates a <tt>ReceivedCallDialog</tt> and plays
* the ring phone sound to the user.
*
* @param event the <tt>CallEvent</tt>
* @param ev the <tt>CallEvent</tt>
*/
public void incomingCallReceived(final CallEvent event)
@Override
public void incomingCallReceivedInEventDispatchThread(CallEvent ev)
{
if(!SwingUtilities.isEventDispatchThread())
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
incomingCallReceived(event);
}
});
return;
}
Call sourceCall = event.getSourceCall();
boolean isVideoCall = event.isVideoCall() && ConfigurationManager
.hasEnabledVideoFormat(sourceCall.getProtocolProvider());
Call sourceCall = ev.getSourceCall();
boolean isVideoCall
= ev.isVideoCall()
&& ConfigurationManager.hasEnabledVideoFormat(
sourceCall.getProtocolProvider());
final ReceivedCallDialog receivedCallDialog
= new ReceivedCallDialog(sourceCall, isVideoCall,
(CallManager.getInProgressCalls().size() > 0));
= new ReceivedCallDialog(
sourceCall,
isVideoCall,
(CallManager.getInProgressCalls().size() > 0));
receivedCallDialog.setVisible(true);
@ -120,8 +113,21 @@ public void run()
sourceCall.addCallChangeListener(new CallChangeAdapter()
{
@Override
public void callStateChanged(CallChangeEvent evt)
public void callStateChanged(final CallChangeEvent ev)
{
if(!SwingUtilities.isEventDispatchThread())
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
callStateChanged(ev);
}
});
return;
}
// When the call state changes, we ensure here that the
// received call notification dialog is closed.
if (receivedCallDialog.isVisible())
@ -129,8 +135,8 @@ public void callStateChanged(CallChangeEvent evt)
// Ensure that the CallDialog is created, because it is the
// one that listens for CallPeers.
Object newValue = evt.getNewValue();
Call call = evt.getSourceCall();
Object newValue = ev.getNewValue();
Call call = ev.getSourceCall();
if (CallState.CALL_INITIALIZATION.equals(newValue)
|| CallState.CALL_IN_PROGRESS.equals(newValue))
@ -139,12 +145,12 @@ public void callStateChanged(CallChangeEvent evt)
}
else if (CallState.CALL_ENDED.equals(newValue))
{
if (evt.getOldValue().equals(
if (ev.getOldValue().equals(
CallState.CALL_INITIALIZATION))
{
// if call was answered elsewhere, don't add it
// to missed calls
CallPeerChangeEvent cause = evt.getCause();
CallPeerChangeEvent cause = ev.getCause();
if((cause == null)
|| (cause.getReasonCode()
@ -175,14 +181,7 @@ else if (CallState.CALL_ENDED.equals(newValue))
* Notify the existing CallPanels about the CallEvent (in case they
* need to update their UI, for example).
*/
List<CallPanel> callPanels
= new ArrayList<CallPanel>(activeCalls.values());
for (CallPanel callPanel : callPanels)
{
if (callPanel != null)
callPanel.incomingCallReceived(event);
}
forwardCallEventToCallPanels(ev);
}
/**
@ -190,42 +189,33 @@ else if (CallState.CALL_ENDED.equals(newValue))
* the moment if there're any. Removes the <tt>CallPanel</tt> and
* disables the hang-up button.
*
* @param event the <tt>CallEvent</tt> which specifies the <tt>Call</tt>
* @param ev the <tt>CallEvent</tt> which specifies the <tt>Call</tt>
* that has ended
*/
public void callEnded(CallEvent event)
@Override
public void callEndedInEventDispatchThread(CallEvent ev)
{
Call sourceCall = event.getSourceCall();
CallPanel callContainer = getActiveCallContainer(sourceCall);
Call sourceCall = ev.getSourceCall();
if (callContainer != null)
{
closeCallContainerIfNotNecessary(sourceCall, true);
closeCallContainerIfNotNecessary(sourceCall, true);
/*
* Notify the existing CallPanels about the CallEvent (in case
* they need to update their UI, for example).
*/
List<CallPanel> callPanels
= new ArrayList<CallPanel>(activeCalls.values());
for (CallPanel callPanel : callPanels)
{
if (callPanel != null)
callPanel.callEnded(event);
}
}
/*
* Notify the existing CallPanels about the CallEvent (in case
* they need to update their UI, for example).
*/
forwardCallEventToCallPanels(ev);
}
/**
* Creates and opens a call dialog. Implements
* {@link CallListener#outgoingCallCreated(CallEvent)}.
*
* @param event the <tt>CallEvent</tt>
* @param ev the <tt>CallEvent</tt>
*/
public void outgoingCallCreated(CallEvent event)
@Override
public void outgoingCallCreatedInEventDispatchThread(CallEvent ev)
{
Call sourceCall = event.getSourceCall();
Call sourceCall = ev.getSourceCall();
openCallContainerIfNecessary(sourceCall);
@ -233,14 +223,7 @@ public void outgoingCallCreated(CallEvent event)
* Notify the existing CallPanels about the CallEvent (in case they
* need to update their UI, for example).
*/
List<CallPanel> callPanels
= new ArrayList<CallPanel>(activeCalls.values());
for (CallPanel callPanel : callPanels)
{
if (callPanel != null)
callPanel.outgoingCallCreated(event);
}
forwardCallEventToCallPanels(ev);
}
}
@ -287,15 +270,17 @@ public static void answerCallInFirstExistingCall(Call call)
}
/**
* Merge multiple existing <tt>Call</tt>s into a single conference
* <tt>Call</tt>.
* Merges specific existing <tt>Call</tt>s into a specific telephony
* conference.
*
* @param first first call
* @param calls list of calls
*/
public static void mergeExistingCall(Call first, Collection<Call> calls)
public static void mergeExistingCalls(
CallConference conference,
Collection<Call> calls)
{
new MergeExistingCalls(first, calls).start();
new MergeExistingCalls(conference, calls).start();
}
/**
@ -313,7 +298,7 @@ public static void answerVideoCall(Call call)
*
* @param call the call to hang up
*/
public static void hangupCall(final Call call)
public static void hangupCall(Call call)
{
new HangupCallThread(call).start();
}
@ -323,9 +308,21 @@ public static void hangupCall(final Call call)
*
* @param callPeer the <tt>CallPeer</tt> to hang up
*/
public static void hangupCallPeer(final CallPeer callPeer)
public static void hangupCallPeer(CallPeer peer)
{
new HangupCallThread(peer).start();
}
/**
* Asynchronously hangs up the <tt>Call</tt>s participating in a specific
* <tt>CallConference</tt>.
*
* @param conference the <tt>CallConference</tt> whose participating
* <tt>Call</tt>s are to be hanged up
*/
public static void hangupCalls(CallConference conference)
{
new HangupCallPeerThread(callPeer).start();
new HangupCallThread(conference).start();
}
/**
@ -381,10 +378,11 @@ public static void createVideoCall(ProtocolProviderService protocolProvider,
}
/**
* Enables/disables local video for the given call.
* Enables/disables local video for a specific <tt>Call</tt>.
*
* @param enable indicates whether to enable or disable the local video
* @param call the call for which the local video should be enabled/disabled
* @param call the <tt>Call</tt> to enable/disable to local video for
* @param enable <tt>true</tt> to enable the local video; otherwise,
* <tt>false</tt>
*/
public static void enableLocalVideo(Call call, boolean enable)
{
@ -884,8 +882,7 @@ public static void createConferenceCall(
* @param callees the list of contacts to invite
* @param call the protocol provider to which this call belongs
*/
public static void inviteToConferenceCall( String[] callees,
Call call)
public static void inviteToConferenceCall(String[] callees, Call call)
{
Map<ProtocolProviderService, List<String>> crossProtocolCallees
= new HashMap<ProtocolProviderService, List<String>>();
@ -910,6 +907,37 @@ public static void inviteToConferenceCall(
new InviteToConferenceCallThread(callees, call).start();
}
/**
* Invites specific <tt>callees</tt> to a specific telephony conference.
*
* @param callees the list of contacts to invite
* @param conference the telephony conference to invite the specified
* <tt>callees</tt> into
*/
public static void inviteToConferenceCall(
Map<ProtocolProviderService, List<String>> callees,
CallConference conference)
{
/*
* InviteToConferenceCallThread takes a specific Call but actually
* invites to the telephony conference associated with the specified
* Call (if any). In order to not change the signature of its
* constructor at this time, just pick up a Call participating in the
* specified telephony conference (if any).
*/
Call call = null;
if (conference != null)
{
List<Call> calls = conference.getCalls();
if (!calls.isEmpty())
call = calls.get(0);
}
new InviteToConferenceCallThread(callees, call).start();
}
/**
* Asynchronously creates a new conference <tt>Call</tt> with a specific
* list of participants/callees.
@ -995,79 +1023,130 @@ public static void transferCall(CallPeer peer, String target)
* {@link CallContainer#close(CallPanel)}
*/
private static void closeCallContainerIfNotNecessary(
Call call,
boolean wait)
final Call call,
final boolean wait)
{
CallPanel callPanel = activeCalls.remove(call);
if (!SwingUtilities.isEventDispatchThread())
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
closeCallContainerIfNotNecessary(call, wait);
}
});
return;
}
/*
* XXX The integrity of the execution of the method may be compromised
* if it is not invoked on the AWT event dispatching thread because
* findCallPanel and callPanels.remove must be atomically executed. The
* uninterrupted execution (with respect to the synchronization) is
* guaranteed by requiring all modifications to callPanels to be made on
* the AWT event dispatching thread.
*/
CallConference conference = call.getConference();
if ((callPanel != null) && !activeCalls.containsValue(callPanel))
for (Iterator<Map.Entry<CallConference, CallPanel>> entryIter
= callPanels.entrySet().iterator();
entryIter.hasNext();)
{
CallContainer callContainer = callPanel.getCallWindow();
Map.Entry<CallConference, CallPanel> entry = entryIter.next();
CallConference aConference = entry.getKey();
List<Call> calls = aConference.getCalls();
boolean notNecessary = true;
if (wait)
callContainer.closeWait(callPanel);
else
callContainer.close(callPanel);
for (Call aCall : calls)
{
if (!CallState.CALL_ENDED.equals(aCall.getCallState()))
{
notNecessary = false;
break;
}
}
if (notNecessary)
{
CallPanel aCallPanel = entry.getValue();
CallContainer window = aCallPanel.getCallWindow();
try
{
if (wait && (aConference == conference))
window.closeWait(aCallPanel);
else
window.close(aCallPanel);
}
finally
{
/*
* We allow non-modifications i.e. reads of callPanels on
* threads other than the AWT event dispatching thread so we
* have to make sure that we will not cause
* ConcurrentModificationException.
*/
synchronized (callPanels)
{
entryIter.remove();
}
aCallPanel.dispose();
}
}
}
}
/**
* Opens a <tt>CallPanel</tt> for a specific <tt>Call</tt> if there is none.
* <p>
* <b>Note</b>: The method can be called only on the AWT event dispatching
* thread.
* </p>
*
* @param call the <tt>Call</tt> to open a <tt>CallPanel</tt> for
* @return the <tt>CallPanel</tt> associated with the <tt>Call</tt>
* @throws RuntimeException if the method is not called on the AWT event
* dispatching thread
*/
private static CallPanel openCallContainerIfNecessary(Call call)
{
CallPanel callPanel = activeCalls.get(call);
/*
* XXX The integrity of the execution of the method may be compromised
* if it is not invoked on the AWT event dispatching thread because
* findCallPanel and callPanels.put must be atomically executed. The
* uninterrupted execution (with respect to the synchronization) is
* guaranteed by requiring all modifications to callPanels to be made on
* the AWT event dispatching thread.
*/
assertIsEventDispatchingThread();
/*
* CallPanel displays a CallConference (which may contain multiple
* Calls.)
*/
CallConference conference = call.getConference();
CallPanel callPanel = findCallPanel(conference);
if (callPanel == null)
{
/*
* Technically, CallPanel displays a whole CallConference, not a
* single Call. Try to locate the CallPanel for the specified Call
* by looking at the CallPanels of the other Calls.
*/
CallConference conference = call.getConference();
// If we're in single-window mode, the single window is the
// CallContainer.
CallContainer callContainer
= GuiActivator.getUIService().getSingleWindowContainer();
if (conference != null)
{
for (Call conferenceCall : conference.getCalls())
{
CallPanel conferenceCallPanel
= activeCalls.get(conferenceCall);
// If we're in multi-window mode, we create the CallDialog.
if (callContainer == null)
callContainer = new CallDialog();
if (conferenceCallPanel != null)
{
if (callPanel == null)
callPanel = conferenceCallPanel;
else if (logger.isDebugEnabled()
&& (conferenceCallPanel != callPanel))
{
logger.debug(
"Calls in the same CallConference"
+ " have different CallPanels.");
}
}
}
}
callPanel = new CallPanel(conference, callContainer);
callContainer.addCallPanel(callPanel);
if (callPanel == null)
synchronized (callPanels)
{
// If we're in single-window mode, the single window is the
// CallContainer.
CallContainer callContainer
= GuiActivator.getUIService().getSingleWindowContainer();
// If we're in multi-window mode, we create the CallDialog.
if (callContainer == null)
callContainer = new CallDialog();
callPanel = new CallPanel(call, callContainer);
callContainer.addCallPanel(callPanel);
callPanels.put(conference, callPanel);
}
activeCalls.put(call, callPanel);
}
return callPanel;
@ -1104,7 +1183,26 @@ public static List<ProtocolProviderService> getTelephonyProviders()
*/
public static Collection<Call> getActiveCalls()
{
return activeCalls.keySet();
CallConference[] conferences;
synchronized (callPanels)
{
Set<CallConference> keySet = callPanels.keySet();
conferences = keySet.toArray(new CallConference[keySet.size()]);
}
List<Call> calls = new ArrayList<Call>();
for (CallConference conference : conferences)
{
for (Call call : conference.getCalls())
{
if (call.getCallState() == CallState.CALL_IN_PROGRESS)
calls.add(call);
}
}
return calls;
}
/**
@ -1114,21 +1212,16 @@ public static Collection<Call> getActiveCalls()
*/
public static Collection<Call> getInProgressCalls()
{
Set<Call> calls = activeCalls.keySet();
ArrayList<Call> inProgressCalls = new ArrayList<Call>(calls.size());
Iterator<Call> it = calls.iterator();
Call tmpCall;
/* TODO Synchronize the access to the callPanels field. */
while(it.hasNext())
Collection<Call> calls = getActiveCalls();
List<Call> inProgressCalls = new ArrayList<Call>(calls.size());
for (Call call : calls)
{
tmpCall = it.next();
if(tmpCall.getCallState() == CallState.CALL_IN_PROGRESS)
{
inProgressCalls.add(tmpCall);
}
if (call.getCallState() == CallState.CALL_IN_PROGRESS)
inProgressCalls.add(call);
}
//return calls;
return inProgressCalls;
}
@ -1143,7 +1236,7 @@ public static Collection<Call> getInProgressCalls()
*/
public static CallPanel getActiveCallContainer(Call call)
{
return activeCalls.get(call);
return findCallPanel(call.getConference());
}
/**
@ -1295,31 +1388,45 @@ public void run()
/**
* Indicates if we have video streams to show in this interface.
*
* @return <tt>true</tt> if we have video streams to show in this interface,
* otherwise we return <tt>false</tt>.
* @return <tt>true</tt> if we have video streams to show in this interface;
* otherwise, <tt>false</tt>
*/
public static boolean isVideoStreaming(Call call)
{
OperationSetVideoTelephony videoOpSet
= call.getProtocolProvider()
.getOperationSet(OperationSetVideoTelephony.class);
if (videoOpSet == null)
return false;
if (videoOpSet.isLocalVideoStreaming(call))
return true;
return isVideoStreaming(call.getConference());
}
Iterator<? extends CallPeer> callPeers = call.getCallPeers();
while (callPeers.hasNext())
/**
* Indicates if we have video streams to show in this interface.
*
* @return <tt>true</tt> if we have video streams to show in this interface;
* otherwise, <tt>false</tt>
*/
public static boolean isVideoStreaming(CallConference conference)
{
for (Call call : conference.getCalls())
{
List<Component> remoteVideos
= videoOpSet.getVisualComponents(callPeers.next());
OperationSetVideoTelephony videoTelephony
= call.getProtocolProvider().getOperationSet(
OperationSetVideoTelephony.class);
if (remoteVideos != null && remoteVideos.size() > 0)
if (videoTelephony == null)
continue;
if (videoTelephony.isLocalVideoStreaming(call))
return true;
}
Iterator<? extends CallPeer> callPeers = call.getCallPeers();
while (callPeers.hasNext())
{
List<Component> remoteVideos
= videoTelephony.getVisualComponents(callPeers.next());
if ((remoteVideos != null) && (remoteVideos.size() > 0))
return true;
}
}
return false;
}
@ -1963,74 +2070,112 @@ public void run()
}
/**
* Hang-ups all call peers in the given call.
* Hangs up a specific <tt>Call</tt> (i.e. all <tt>CallPeer</tt>s associated
* with a <tt>Call</tt>), <tt>CallConference</tt> (i.e. all <tt>Call</tt>s
* participating in a <tt>CallConference</tt>), or <tt>CallPeer</tt>.
*/
private static class HangupCallThread
extends Thread
{
private final Call call;
private final CallConference conference;
private final CallPeer peer;
/**
* Initializes a new <tt>HangupCallThread</tt> instance which is to hang
* up a specific <tt>Call</tt> i.e. all <tt>CallPeer</tt>s associated
* with the <tt>Call</tt>.
*
* @param call the <tt>Call</tt> whose associated <tt>CallPeer</tt>s are
* to be hanged up
*/
public HangupCallThread(Call call)
{
this.call = call;
this(call, null, null);
}
@Override
public void run()
/**
* Initializes a new <tt>HangupCallThread</tt> instance which is to hang
* up a specific <tt>CallConference</tt> i.e. all <tt>Call</tt>s
* participating in the <tt>CallConference</tt>.
*
* @param conference the <tt>CallConference</tt> whose participating
* <tt>Call</tt>s re to be hanged up
*/
public HangupCallThread(CallConference conference)
{
for (Call conferenceCall : CallConference.getCalls(call))
{
Iterator<? extends CallPeer> peerIter
= conferenceCall.getCallPeers();
OperationSetBasicTelephony<?> basicTelephony
= conferenceCall.getProtocolProvider().getOperationSet(
OperationSetBasicTelephony.class);
while (peerIter.hasNext())
{
CallPeer peer = peerIter.next();
try
{
basicTelephony.hangupCallPeer(peer);
}
catch (OperationFailedException ofe)
{
logger.error("Could not hang up: " + peer, ofe);
}
}
}
this(null, conference, null);
}
}
/**
* Hang-ups the given <tt>CallPeer</tt>.
*/
private static class HangupCallPeerThread
extends Thread
{
private final CallPeer callPeer;
/**
* Initializes a new <tt>HangupCallThread</tt> instance which is to hang
* up a specific <tt>CallPeer</tt>.
*
* @param peer the <tt>CallPeer</tt> to hang up
*/
public HangupCallThread(CallPeer peer)
{
this(null, null, peer);
}
public HangupCallPeerThread(CallPeer callPeer)
/**
* Initializes a new <tt>HangupCallThread</tt> instance which is to hang
* up a specific <tt>Call</tt>, <tt>CallConference</tt>, or
* <tt>CallPeer</tt>.
*
* @param call the <tt>Call</tt> whose associated <tt>CallPeer</tt>s are
* to be hanged up
* @param conference the <tt>CallConference</tt> whose participating
* <tt>Call</tt>s re to be hanged up
* @param peer the <tt>CallPeer</tt> to hang up
*/
private HangupCallThread(
Call call,
CallConference conference,
CallPeer peer)
{
this.callPeer = callPeer;
this.call = call;
this.conference = conference;
this.peer = peer;
}
@Override
public void run()
{
ProtocolProviderService pps = callPeer.getProtocolProvider();
OperationSetBasicTelephony<?> telephony
= pps.getOperationSet(OperationSetBasicTelephony.class);
/*
* There is only an OperationSet which hangs up a CallPeer at a time
* so prepare a list of all CallPeers to be hanged up.
*/
Set<CallPeer> peers = new HashSet<CallPeer>();
try
if (call != null)
{
telephony.hangupCallPeer(callPeer);
Iterator<? extends CallPeer> peerIter = call.getCallPeers();
while (peerIter.hasNext())
peers.add(peer);
}
catch (OperationFailedException e)
if (conference != null)
peers.addAll(conference.getCallPeers());
if (peer != null)
peers.add(peer);
for (CallPeer peer : peers)
{
logger.error("Could not hang up : " + callPeer
+ " caused by the following exception: " + e);
OperationSetBasicTelephony<?> basicTelephony
= peer.getProtocolProvider().getOperationSet(
OperationSetBasicTelephony.class);
try
{
basicTelephony.hangupCallPeer(peer);
}
catch (OperationFailedException ofe)
{
logger.error("Could not hang up: " + peer, ofe);
}
}
}
}
@ -2141,15 +2286,16 @@ public void run()
}
/**
* Merge existing calls thread.
* Merges specific existing <tt>Call</tt>s into a specific telephony
* conference.
*/
private static class MergeExistingCalls
extends Thread
{
/**
* First call.
* The telephony conference in which {@link #calls} are to be merged.
*/
private final Call first;
private final CallConference conference;
/**
* Second call.
@ -2157,14 +2303,20 @@ private static class MergeExistingCalls
private final Collection<Call> calls;
/**
* Constructor.
* Initializes a new <tt>MergeExistingCalls</tt> instance which is to
* merge specific existing <tt>Call</tt>s into a specific telephony
* conference.
*
* @param first first call
* @param calls list of calls
* @param conference the telephony conference in which the specified
* <tt>Call</tt>s are to be merged
* @param calls the <tt>Call</tt>s to be merged into the specified
* telephony conference
*/
public MergeExistingCalls(Call first, Collection<Call> calls)
public MergeExistingCalls(
CallConference conference,
Collection<Call> calls)
{
this.first = first;
this.conference = conference;
this.calls = calls;
}
@ -2212,17 +2364,16 @@ private void putOffHold(Call call)
@Override
public void run()
{
// first
putOffHold(first);
// conference
for (Call call : conference.getCalls())
putOffHold(call);
// calls
if (!calls.isEmpty())
{
CallConference conference = first.getConference();
for(Call call : calls)
{
if (call == first)
if (conference.containsCall(call))
continue;
putOffHold(call);
@ -2293,4 +2444,88 @@ private static void normalizePhoneNumbers(String callees[])
for (int i = 0 ; i < callees.length ; i++)
callees[i] = PhoneNumberI18nService.normalize(callees[i]);
}
/**
* Throws a <tt>RuntimeException</tt> if the current thread is not the AWT
* event dispatching thread.
*/
private static void assertIsEventDispatchingThread()
{
if (!SwingUtilities.isEventDispatchThread())
{
throw new RuntimeException(
"The methon can be called only on the AWT event dispatching"
+ " thread.");
}
}
/**
* Finds the <tt>CallPanel</tt>, if any, which depicts a specific
* <tt>CallConference</tt>.
* <p>
* <b>Note</b>: The method can be called only on the AWT event dispatching
* thread.
* </p>
*
* @param conference the <tt>CallConference</tt> to find the depicting
* <tt>CallPanel</tt> of
* @return the <tt>CallPanel</tt> which depicts the specified
* <tt>CallConference</tt> if such a <tt>CallPanel</tt> exists; otherwise,
* <tt>null</tt>
* @throws RuntimeException if the method is not called on the AWT event
* dispatching thread
*/
private static CallPanel findCallPanel(CallConference conference)
{
synchronized (callPanels)
{
return callPanels.get(conference);
}
}
/**
* Notifies {@link #callPanels} about a specific <tt>CallEvent</tt> received
* by <tt>CallManager</tt> (because they may need to update their UI, for
* example).
* <p>
* <b>Note</b>: The method can be called only on the AWT event dispatching
* thread.
* </p>
*
* @param ev the <tt>CallEvent</tt> received by <tt>CallManager</tt> which
* is to be forwarded to <tt>callPanels</tt> for further
* <tt>CallPanel</tt>-specific handling
* @throws RuntimeException if the method is not called on the AWT event
* dispatching thread
*/
private static void forwardCallEventToCallPanels(CallEvent ev)
{
assertIsEventDispatchingThread();
CallPanel[] callPanels;
synchronized (CallManager.callPanels)
{
Collection<CallPanel> values = CallManager.callPanels.values();
callPanels = values.toArray(new CallPanel[values.size()]);
}
for (CallPanel callPanel : callPanels)
{
try
{
callPanel.onCallEvent(ev);
}
catch (Exception ex)
{
/*
* There is no practical reason while the failure of a CallPanel
* to handle the CallEvent should cause the other CallPanels to
* be left out-of-date.
*/
logger.error("A CallPanel failed to handle a CallEvent", ex);
}
}
}
}

@ -103,14 +103,12 @@ public class OneToOneCallPanel
* call type (incoming or outgoing) and the parent dialog.
*
* @param callContainer the container containing this panel
* @param call the call corresponding to this panel
* @param callPeer the remote participant in the call
*/
public OneToOneCallPanel( CallPanel callContainer,
Call call,
CallPeer callPeer)
{
this(callContainer, call, callPeer, null);
this(callContainer, callPeer, null);
}
/**
@ -118,18 +116,17 @@ public OneToOneCallPanel( CallPanel callContainer,
* call type (incoming or outgoing) and the parent dialog.
*
* @param callContainer the container containing this panel
* @param call the call corresponding to this panel
* @param callPeer the remote participant in the call
* @param videoHandler
*/
public OneToOneCallPanel( CallPanel callContainer,
Call call,
CallPeer callPeer,
UIVideoHandler videoHandler)
{
super(new BorderLayout());
this.callContainer = callContainer;
this.call = call;
this.call = callPeer.getCall();
this.callPeer = callPeer;
if (videoHandler == null)
@ -662,21 +659,23 @@ private String getPeerDisplayText(CallPeer peer, String displayName)
* @param callPeer the parent call peer
* @param conferenceMember the member that was added
*/
public void conferenceMemberAdded(CallPeer callPeer,
ConferenceMember conferenceMember)
public void conferenceMemberAdded(
CallPeer callPeer,
ConferenceMember conferenceMember)
{
// We don't want to add the local member to the list of members.
if (CallManager.isLocalUser(conferenceMember))
return;
if (CallManager.addressesAreEqual(
conferenceMember.getAddress(), callPeer.getAddress()))
conferenceMember.getAddress(),
callPeer.getAddress()))
{
return;
}
getCallContainer().enableConferenceInterface(
CallManager.isVideoStreaming(call));
CallManager.isVideoStreaming(call));
}
/**

@ -28,6 +28,7 @@
* button in the chat toolbar.
*
* @author Yana Stamcheva
* @author Lyubomir Marinov
*/
public class ConferenceInviteDialog
extends InviteDialog
@ -48,9 +49,10 @@ public class ConferenceInviteDialog
private Object lastSelectedAccount;
/**
* The call.
* The telephony conference into which this instance is to invite
* participants.
*/
private final Call call;
private final CallConference conference;
/**
* The current provider contact source.
@ -63,17 +65,18 @@ public class ConferenceInviteDialog
private ContactSourceService currentStringContactSource;
/**
* Creates <tt>ConferenceInviteDialog</tt> by specifying the call, to which
* the contacts are invited.
* Initializes a new <tt>ConferenceInviteDialog</tt> instance which is to
* invite contacts/participants in a specific telephony conference.
*
* @param call the call to which the contacts are invited
* @param conference the telephony conference in which the new instance is
* to invite contacts/participants
*/
public ConferenceInviteDialog(Call call)
public ConferenceInviteDialog(CallConference conference)
{
super(GuiActivator.getResources()
.getI18NString("service.gui.INVITE_CONTACT_TO_CALL"));
this.call = call;
this.conference = conference;
JLabel accountSelectorLabel = new JLabel(
GuiActivator.getResources().getI18NString("service.gui.CALL_VIA"));
@ -201,33 +204,46 @@ public ConferenceInviteDialog()
private void initAccountListData()
{
Iterator<ProtocolProviderService> protocolProviders
= GuiActivator.getUIService()
.getMainFrame().getProtocolProviders();
= GuiActivator.getUIService().getMainFrame().getProtocolProviders();
while(protocolProviders.hasNext())
{
ProtocolProviderService protocolProvider
= protocolProviders.next();
OperationSet opSet
= protocolProvider
.getOperationSet(
= protocolProvider.getOperationSet(
OperationSetTelephonyConferencing.class);
if (opSet != null && protocolProvider.isRegistered())
{
if ((opSet != null) && protocolProvider.isRegistered())
accountSelectorBox.addItem(protocolProvider);
}
}
// Obtain the last conference provider used.
ProtocolProviderService lastConfProvider
// Try to select the last used account if available.
ProtocolProviderService pps
= ConfigurationManager.getLastCallConferenceProvider();
// Try to select the last used account if it's available.
if(call != null)
accountSelectorBox.setSelectedItem(call.getProtocolProvider());
else if (lastConfProvider != null)
accountSelectorBox.setSelectedItem(lastConfProvider);
if (pps != null)
accountSelectorBox.setSelectedItem(pps);
else if (conference != null)
{
/*
* Pick up the first account from the ones participating in the
* associated telephony conference which supports
* OperationSetTelephonyConferencing.
*/
for (Call call : conference.getCalls())
{
ProtocolProviderService callPps = call.getProtocolProvider();
if (callPps.getOperationSet(
OperationSetTelephonyConferencing.class)
!= null)
{
pps = callPps;
break;
}
}
}
}
/**
@ -290,9 +306,11 @@ private void inviteContacts(Collection<UIContact> contacts)
OperationSetBasicTelephony.class);
if (selectedProvider == null)
{
selectedProvider
= (ProtocolProviderService) accountSelectorBox
.getSelectedItem();
= (ProtocolProviderService)
accountSelectorBox.getSelectedItem();
}
if(selectedProvider != null
&& selectedProviderCallees.get(selectedProvider) != null)
@ -309,9 +327,11 @@ private void inviteContacts(Collection<UIContact> contacts)
}
}
if(call != null)
if(conference != null)
{
CallManager.inviteToConferenceCall(selectedProviderCallees, call);
CallManager.inviteToConferenceCall(
selectedProviderCallees,
conference);
}
else
{

@ -44,10 +44,15 @@ public void closeOperation(MouseEvent e)
Component c = getComponentAt(tabIndex);
if (c instanceof ChatPanel)
{
GuiActivator.getUIService()
.getChatWindowManager().closeChat((ChatPanel) c);
}
else if (c instanceof CallPanel)
CallManager.hangupCall(((CallPanel) c).getCall());
{
CallManager.hangupCalls(
((CallPanel) c).getCallConference());
}
}
});

Loading…
Cancel
Save