Fixes issues with video conferences such as adding peers and allowing non-focus peers to start their video first.

cusax-fix
Lyubomir Marinov 14 years ago
parent 9b808b2b7c
commit ebc08c2075

@ -433,7 +433,7 @@
<!-- make and deploy target used in intellij idea --> <!-- make and deploy target used in intellij idea -->
<target name="make-and-deploy" <target name="make-and-deploy"
depends="compile,package,deploy-os-specific-bundles" depends="make,deploy-os-specific-bundles"
description="make and deploy target used in intellij idea"/> description="make and deploy target used in intellij idea"/>
<!-- Determines the Jitsi version if any--> <!-- Determines the Jitsi version if any-->

@ -211,20 +211,19 @@ public CallToggleButtonModel(Call call)
public synchronized void actionPerformed(ActionEvent event) public synchronized void actionPerformed(ActionEvent event)
{ {
if(!spawnActionInNewThread) if(spawnActionInNewThread)
{ {
buttonPressed(); if (runner == null)
return; {
} runner = new Thread(this, LocalVideoButton.class.getName());
runner.setDaemon(true);
if (runner == null)
{
runner = new Thread(this, LocalVideoButton.class.getName());
runner.setDaemon(true);
setEnabled(false); setEnabled(false);
runner.start(); runner.start();
}
} }
else
buttonPressed();
} }
public void run() public void run()

@ -325,14 +325,10 @@ public static void enableLocalVideo(Call call, boolean enable)
public static boolean isLocalVideoEnabled(Call call) public static boolean isLocalVideoEnabled(Call call)
{ {
OperationSetVideoTelephony telephony OperationSetVideoTelephony telephony
= call.getProtocolProvider() = call.getProtocolProvider().getOperationSet(
.getOperationSet(OperationSetVideoTelephony.class); OperationSetVideoTelephony.class);
if (telephony != null
&& telephony.isLocalVideoAllowed(call))
return true;
return false; return (telephony != null) && telephony.isLocalVideoAllowed(call);
} }
/** /**
@ -343,8 +339,8 @@ public static boolean isLocalVideoEnabled(Call call)
* @param contact the contact to call to * @param contact the contact to call to
*/ */
public static void createDesktopSharing( public static void createDesktopSharing(
ProtocolProviderService protocolProvider, ProtocolProviderService protocolProvider,
String contact) String contact)
{ {
// If the user presses cancel on the desktop sharing warning then we // If the user presses cancel on the desktop sharing warning then we
// have nothing more to do here. // have nothing more to do here.
@ -352,16 +348,16 @@ public static void createDesktopSharing(
return; return;
MediaService mediaService = GuiActivator.getMediaService(); MediaService mediaService = GuiActivator.getMediaService();
List<MediaDevice> desktopDevices
List<MediaDevice> desktopDevices = mediaService.getDevices( = mediaService.getDevices(MediaType.VIDEO, MediaUseCase.DESKTOP);
MediaType.VIDEO, MediaUseCase.DESKTOP);
int deviceNumber = desktopDevices.size(); int deviceNumber = desktopDevices.size();
if (deviceNumber == 1) if (deviceNumber == 1)
{ {
createDesktopSharing( createDesktopSharing(
protocolProvider, contact, desktopDevices.get(0)); protocolProvider,
contact,
desktopDevices.get(0));
} }
else if (deviceNumber > 1) else if (deviceNumber > 1)
{ {
@ -369,11 +365,11 @@ else if (deviceNumber > 1)
= new SelectScreenDialog(desktopDevices); = new SelectScreenDialog(desktopDevices);
selectDialog.setVisible(true); selectDialog.setVisible(true);
if (selectDialog.getSelectedDevice() != null) if (selectDialog.getSelectedDevice() != null)
createDesktopSharing( protocolProvider, createDesktopSharing(
contact, protocolProvider,
selectDialog.getSelectedDevice()); contact,
selectDialog.getSelectedDevice());
} }
} }
@ -1848,7 +1844,7 @@ private static class EnableLocalVideoThread
{ {
private final Call call; private final Call call;
private boolean enable; private final boolean enable;
/** /**
* Creates the enable local video call thread. * Creates the enable local video call thread.
@ -1878,20 +1874,16 @@ public void run()
{ {
getActiveCallContainer(call).setDesktopSharingButtonSelected( getActiveCallContainer(call).setDesktopSharingButtonSelected(
false); false);
JFrame frame = DesktopSharingFrame.getFrameForCall(call); JFrame frame = DesktopSharingFrame.getFrameForCall(call);
if(frame != null) if(frame != null)
{
frame.dispose(); frame.dispose();
}
} }
try try
{ {
telephony.setLocalVideoAllowed( telephony.setLocalVideoAllowed(call, enable);
call,
enable);
enableSucceeded = true; enableSucceeded = true;
} }
catch (OperationFailedException ex) catch (OperationFailedException ex)

@ -149,9 +149,10 @@ public class CallPanel
/** /**
* The conference button. * The conference button.
*/ */
private SIPCommButton conferenceButton = new SIPCommButton( private SIPCommButton conferenceButton
ImageLoader.getImage(ImageLoader.CALL_SETTING_BUTTON_BG), = new SIPCommButton(
ImageLoader.getImage(ImageLoader.ADD_TO_CALL_BUTTON)); ImageLoader.getImage(ImageLoader.CALL_SETTING_BUTTON_BG),
ImageLoader.getImage(ImageLoader.ADD_TO_CALL_BUTTON));
/** /**
* Chat button. * Chat button.
@ -266,9 +267,7 @@ public CallPanel(Call call, CallContainer callWindow)
// the focus state of each call peer. // the focus state of each call peer.
Iterator<? extends CallPeer> callPeers = call.getCallPeers(); Iterator<? extends CallPeer> callPeers = call.getCallPeers();
while (callPeers.hasNext()) while (callPeers.hasNext())
{
callPeers.next().addCallPeerConferenceListener(this); callPeers.next().addCallPeerConferenceListener(this);
}
// Initializes all buttons and common panels. // Initializes all buttons and common panels.
init(); init();
@ -417,9 +416,7 @@ public void actionPerformed(ActionEvent evt)
else if (buttonName.equals(DIAL_BUTTON)) else if (buttonName.equals(DIAL_BUTTON))
{ {
if (dialpadDialog == null) if (dialpadDialog == null)
{
dialpadDialog = this.getDialpadDialog(); dialpadDialog = this.getDialpadDialog();
}
if(!dialpadDialog.isVisible()) if(!dialpadDialog.isVisible())
{ {
@ -445,10 +442,7 @@ else if (buttonName.equals(DIAL_BUTTON))
} }
else if (buttonName.equals(CONFERENCE_BUTTON)) else if (buttonName.equals(CONFERENCE_BUTTON))
{ {
ConferenceInviteDialog inviteDialog new ConferenceInviteDialog(call).setVisible(true);
= new ConferenceInviteDialog(call);
inviteDialog.setVisible(true);
} }
else if (buttonName.equals(CHAT_BUTTON)) else if (buttonName.equals(CHAT_BUTTON))
{ {
@ -706,8 +700,8 @@ public void enableButtons(boolean enable)
ProtocolProviderService protocolProvider ProtocolProviderService protocolProvider
= call.getProtocolProvider(); = call.getProtocolProvider();
if (protocolProvider.getOperationSet( if (protocolProvider.getOperationSet(OperationSetVideoTelephony.class)
OperationSetVideoTelephony.class) != null) != null)
{ {
videoButton.setEnabled(enable); videoButton.setEnabled(enable);
} }
@ -724,7 +718,8 @@ public void enableButtons(boolean enable)
} }
if (protocolProvider.getOperationSet( if (protocolProvider.getOperationSet(
OperationSetAdvancedTelephony.class) != null) OperationSetAdvancedTelephony.class)
!= null)
{ {
transferCallButton.setEnabled(enable); transferCallButton.setEnabled(enable);
} }
@ -808,22 +803,18 @@ public void callPeerRemoved(CallPeerEvent evt)
callPeer.removeCallPeerConferenceListener(this); callPeer.removeCallPeerConferenceListener(this);
Timer timer = new Timer(5000, Timer timer = new Timer(5000, new RemovePeerPanelListener(callPeer));
new RemovePeerPanelListener(callPeer));
timer.setRepeats(false); timer.setRepeats(false);
timer.start(); timer.start();
// The call is finished when that last peer is removed. // The call is finished when that last peer is removed.
if (call.getCallPeerCount() == 0) if (call.getCallPeerCount() == 0)
{
this.stopCallTimer(); this.stopCallTimer();
}
} }
public void callStateChanged(CallChangeEvent evt) public void callStateChanged(CallChangeEvent evt)
{ {}
}
/** /**
* Updates <tt>CallPeer</tt> related components to fit the new focus state. * Updates <tt>CallPeer</tt> related components to fit the new focus state.
@ -1002,7 +993,7 @@ public String getCallTitle()
private class RemovePeerPanelListener private class RemovePeerPanelListener
implements ActionListener implements ActionListener
{ {
private CallPeer peer; private final CallPeer peer;
public RemovePeerPanelListener(CallPeer peer) public RemovePeerPanelListener(CallPeer peer)
{ {
@ -1112,15 +1103,29 @@ public void refreshContainer()
// whole window to freeze. // whole window to freeze.
// We check also if the vertical scroll bar is visible in order to // We check also if the vertical scroll bar is visible in order to
// correctly pack the window when a peer is removed. // correctly pack the window when a peer is removed.
boolean isScrollBarVisible = (callPanel instanceof ConferenceCallPanel) boolean isScrollBarVisible;
&& ((ConferenceCallPanel) callPanel).getVerticalScrollBar() != null
&& ((ConferenceCallPanel) callPanel).getVerticalScrollBar() if (callPanel instanceof ConferenceCallPanel)
.isVisible(); {
Component scrollBar
if (!isScrollBarVisible = ((ConferenceCallPanel) callPanel).getVerticalScrollBar();
|| getHeight()
< GraphicsEnvironment.getLocalGraphicsEnvironment() isScrollBarVisible = ((scrollBar != null) && scrollBar.isVisible());
.getMaximumWindowBounds().height) }
else
isScrollBarVisible = false;
/*
* Repacking should be done only when the callWindow is not high enough
* to not have a vertical scroll bar and there is still room left to
* expand its height without going out of the screen.
*/
if (isScrollBarVisible
&& (getHeight()
< GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getMaximumWindowBounds()
.height))
callWindow.pack(); callWindow.pack();
else else
repaint(); repaint();
@ -1195,11 +1200,6 @@ private void updateCurrentCallPanel(JComponent callPanel)
*/ */
private void removeOneToOneSpecificComponents() private void removeOneToOneSpecificComponents()
{ {
// If we want to enable video in conference calls we need to comment
// these lines.
if (videoButton.isSelected())
videoButton.doClick();
// Disable desktop sharing. // Disable desktop sharing.
if (desktopSharingButton.isSelected()) if (desktopSharingButton.isSelected())
desktopSharingButton.doClick(); desktopSharingButton.doClick();

@ -20,7 +20,6 @@
import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*; import net.java.sip.communicator.util.swing.*;
import net.java.sip.communicator.util.swing.transparent.*;
/** /**
* The <tt>UIVideoHandler</tt> is meant to handle all video related events. * The <tt>UIVideoHandler</tt> is meant to handle all video related events.
@ -337,13 +336,11 @@ else if (event.getNewValue().equals(MediaDirection.SENDRECV))
if (CallManager.isDesktopSharingEnabled(call)) if (CallManager.isDesktopSharingEnabled(call))
{ {
callContainer.setDesktopSharingButtonSelected(true); callContainer.setDesktopSharingButtonSelected(true);
if (CallManager.isRegionDesktopSharingEnabled(call)) if (CallManager.isRegionDesktopSharingEnabled(call))
{ {
TransparentFrame frame = DesktopSharingFrame DesktopSharingFrame
.createTransparentFrame(call, false); .createTransparentFrame(call, false)
.setVisible(true);
frame.setVisible(true);
} }
} }
else if (CallManager.isLocalVideoEnabled(call)) else if (CallManager.isLocalVideoEnabled(call))
@ -630,7 +627,6 @@ private void handleLocalVideoStreamingChange(
{ {
if (videoTelephony == null) if (videoTelephony == null)
return; return;
if (callPeer == null || callPeer.getCall() == null) if (callPeer == null || callPeer.getCall() == null)
return; return;

@ -126,20 +126,6 @@ public ConferenceCallPanel(CallPanel callPanel, Call c)
scrollPane.setOpaque(false); scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false); scrollPane.getViewport().setOpaque(false);
this.addLocalCallPeer();
Iterator<? extends CallPeer> iterator = this.call.getCallPeers();
while (iterator.hasNext())
this.addCallPeerPanel(iterator.next());
iterator = this.call.getCrossProtocolCallPeers();
while (iterator.hasNext())
{
this.addCallPeerPanel(iterator.next());
}
scrollPane.setBorder(null); scrollPane.setBorder(null);
/* /*
* The scrollPane seems to receive only a few pixels of width at times * The scrollPane seems to receive only a few pixels of width at times
@ -161,6 +147,22 @@ public ConferenceCallPanel(CallPanel callPanel, Call c)
add(scrollPane, scrollPaneGridBagConstraints); add(scrollPane, scrollPaneGridBagConstraints);
addVideoContainer(); addVideoContainer();
/*
* XXX Call addCallPeerPanel(CallPeer) after calling addVideoContainer()
* because the video may already be flowing between the CallPeers.
* Otherwise, the videos of the remote CallPeers will not be shown.
*/
addLocalCallPeer();
Iterator<? extends CallPeer> iterator;
iterator = this.call.getCallPeers();
while (iterator.hasNext())
addCallPeerPanel(iterator.next());
iterator = this.call.getCrossProtocolCallPeers();
while (iterator.hasNext())
addCallPeerPanel(iterator.next());
} }
/** /**
@ -220,7 +222,7 @@ public void componentAdded(ContainerEvent e)
} }
/* /*
* When the first visual/videoComponent gets added, this * When the first visual/video Component gets added, this
* videoContainer is still not accommodated by the frame * videoContainer is still not accommodated by the frame
* size because it has just become visible. So try to resize * size because it has just become visible. So try to resize
* the frame to accommodate this videoContainer. * the frame to accommodate this videoContainer.
@ -574,6 +576,17 @@ public void ensureSize(Component component, int width, int height)
{ {
Frame frame = CallPeerRendererUtils.getFrame(component); Frame frame = CallPeerRendererUtils.getFrame(component);
/*
* CallPanel creates ConferenceCallPanel and then adds it to the UI
* hierarchy. If the associated Call has just become a conference focus
* and the UI is being updated to reflect the change, the existing
* CallPeer of the Call may cause this method to be called and then this
* ConferenceCallPanel will not have an associated Frame at the time.
* But callPanel will (likely) have one.
*/
if ((frame == null) && (callPanel != null))
frame = CallPeerRendererUtils.getFrame(callPanel);
if (frame == null) if (frame == null)
return; return;
else if ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) else if ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH)

@ -13,8 +13,12 @@
import net.java.sip.communicator.service.neomedia.*; import net.java.sip.communicator.service.neomedia.*;
/** /**
* Provides a base/default implementation of <tt>RTPConnector</tt> which has
* factory methods for its control and data input and output streams and has an
* associated <tt>StreamConnector</tt>.
*
* @author Bing SU (nova.su@gmail.com) * @author Bing SU (nova.su@gmail.com)
* @author Lubomir Marinov * @author Lyubomir Marinov
*/ */
public abstract class AbstractRTPConnector public abstract class AbstractRTPConnector
implements RTPConnector implements RTPConnector
@ -95,13 +99,11 @@ public void close()
dataOutputStream.close(); dataOutputStream.close();
dataOutputStream = null; dataOutputStream = null;
} }
if (controlOutputStream != null) if (controlOutputStream != null)
{ {
controlOutputStream.close(); controlOutputStream.close();
controlOutputStream = null; controlOutputStream = null;
} }
if (dataInputStream != null) if (dataInputStream != null)
{ {
dataInputStream.close(); dataInputStream.close();

@ -348,11 +348,12 @@ public void addRTPExtension(byte extensionID, RTPExtension rtpExtension)
{ {
super.addRTPExtension(extensionID, rtpExtension); super.addRTPExtension(extensionID, rtpExtension);
if ( RTPExtension.CSRC_AUDIO_LEVEL_URN if (RTPExtension.CSRC_AUDIO_LEVEL_URN.equals(
.equals(rtpExtension.getURI().toString())) rtpExtension.getURI().toString()))
{ {
getCsrcEngine().setCsrcAudioLevelAudioLevelExtensionID( getCsrcEngine().setCsrcAudioLevelAudioLevelExtensionID(
extensionID, rtpExtension.getDirection()); extensionID,
rtpExtension.getDirection());
} }
} }

@ -332,12 +332,11 @@ protected void configureRTPManagerBufferControl(
private TransformEngineChain createTransformEngineChain() private TransformEngineChain createTransformEngineChain()
{ {
ArrayList<TransformEngine> engineChain ArrayList<TransformEngine> engineChain
= new ArrayList<TransformEngine>(3); = new ArrayList<TransformEngine>(4);
// CSRCs and audio levels // CSRCs and audio levels
if (csrcEngine == null) if (csrcEngine == null)
csrcEngine = new CsrcTransformEngine(this); csrcEngine = new CsrcTransformEngine(this);
engineChain.add(csrcEngine); engineChain.add(csrcEngine);
// DTMF // DTMF
@ -347,7 +346,7 @@ private TransformEngineChain createTransformEngineChain()
engineChain.add(dtmfEngine); engineChain.add(dtmfEngine);
// RTCP Statistics // RTCP Statistics
if(statisticsEngine == null) if (statisticsEngine == null)
statisticsEngine = new StatisticsEngine(this); statisticsEngine = new StatisticsEngine(this);
engineChain.add(statisticsEngine); engineChain.add(statisticsEngine);
@ -503,7 +502,7 @@ public void close()
srtpControl.cleanup(); srtpControl.cleanup();
if(csrcEngine != null) if (csrcEngine != null)
{ {
csrcEngine.stop(); csrcEngine.stop();
csrcEngine = null; csrcEngine = null;
@ -515,7 +514,7 @@ public void close()
if (rtpManager != null) if (rtpManager != null)
{ {
if(logger.isInfoEnabled()) if (logger.isInfoEnabled())
printFlowStatistics(rtpManager); printFlowStatistics(rtpManager);
rtpManager.removeReceiveStreamListener(this); rtpManager.removeReceiveStreamListener(this);
@ -843,7 +842,6 @@ private void doSetTarget(MediaStreamTarget target)
} }
else else
targetIsSet = true; targetIsSet = true;
if (targetIsSet) if (targetIsSet)
{ {
rtpConnectorTarget = target; rtpConnectorTarget = target;
@ -859,6 +857,7 @@ private void doSetTarget(MediaStreamTarget target)
+ target); + target);
} }
} }
/** /**
* Gets the <tt>MediaDevice</tt> that this stream uses to play back and * Gets the <tt>MediaDevice</tt> that this stream uses to play back and
* capture media. * capture media.
@ -1095,8 +1094,6 @@ private StreamRTPManager getRTPManager()
if (bc != null) if (bc != null)
configureRTPManagerBufferControl(rtpManager, bc); configureRTPManagerBufferControl(rtpManager, bc);
//Emil: if you replace this method with another init method make
//sure you check that the line below still works.
rtpManager.initialize(rtpConnector); rtpManager.initialize(rtpConnector);
/* /*
@ -1256,74 +1253,74 @@ public void setConnector(StreamConnector connector)
if (connector == null) if (connector == null)
throw new NullPointerException("connector"); throw new NullPointerException("connector");
if (rtpConnector != null)
{
// Is the StreamConnector really changing?
if (rtpConnector.getConnector() == connector)
return;
}
AbstractRTPConnector oldValue = rtpConnector; AbstractRTPConnector oldValue = rtpConnector;
if(connector.getProtocol() == StreamConnector.Protocol.UDP) // Is the StreamConnector really changing?
if ((oldValue != null) && (oldValue.getConnector() == connector))
return;
switch (connector.getProtocol())
{ {
case UDP:
rtpConnector rtpConnector
= new RTPTransformUDPConnector(connector) = new RTPTransformUDPConnector(connector)
{
@Override
protected TransformUDPOutputStream createDataOutputStream()
throws IOException
{ {
TransformUDPOutputStream dataOutputStream @Override
= super.createDataOutputStream(); protected TransformUDPOutputStream createDataOutputStream()
throws IOException
{
TransformUDPOutputStream dataOutputStream
= super.createDataOutputStream();
if (dataOutputStream != null) if (dataOutputStream != null)
configureDataOutputStream(dataOutputStream); configureDataOutputStream(dataOutputStream);
return dataOutputStream; return dataOutputStream;
} }
@Override @Override
protected TransformUDPInputStream createDataInputStream() protected TransformUDPInputStream createDataInputStream()
throws IOException throws IOException
{ {
TransformUDPInputStream dataInputStream TransformUDPInputStream dataInputStream
= super.createDataInputStream(); = super.createDataInputStream();
if (dataInputStream != null) if (dataInputStream != null)
configureDataInputStream(dataInputStream); configureDataInputStream(dataInputStream);
return dataInputStream; return dataInputStream;
} }
}; };
} break;
else if(connector.getProtocol() == StreamConnector.Protocol.TCP) case TCP:
{
rtpConnector rtpConnector
= new RTPTransformTCPConnector(connector) = new RTPTransformTCPConnector(connector)
{
@Override
protected TransformTCPOutputStream createDataOutputStream()
throws IOException
{ {
TransformTCPOutputStream dataOutputStream @Override
= super.createDataOutputStream(); protected TransformTCPOutputStream createDataOutputStream()
throws IOException
{
TransformTCPOutputStream dataOutputStream
= super.createDataOutputStream();
if (dataOutputStream != null) if (dataOutputStream != null)
configureDataOutputStream(dataOutputStream); configureDataOutputStream(dataOutputStream);
return dataOutputStream; return dataOutputStream;
} }
@Override @Override
protected TransformTCPInputStream createDataInputStream() protected TransformTCPInputStream createDataInputStream()
throws IOException throws IOException
{ {
TransformTCPInputStream dataInputStream TransformTCPInputStream dataInputStream
= super.createDataInputStream(); = super.createDataInputStream();
if (dataInputStream != null) if (dataInputStream != null)
configureDataInputStream(dataInputStream); configureDataInputStream(dataInputStream);
return dataInputStream; return dataInputStream;
} }
}; };
break;
default:
throw new IllegalArgumentException("connector");
} }
rtpConnectorChanged(oldValue, rtpConnector); rtpConnectorChanged(oldValue, rtpConnector);
@ -1362,7 +1359,7 @@ public void setDevice(MediaDevice device)
startedDirection = deviceSession.getStartedDirection(); startedDirection = deviceSession.getStartedDirection();
deviceSession.removePropertyChangeListener( deviceSession.removePropertyChangeListener(
deviceSessionPropertyChangeListener); deviceSessionPropertyChangeListener);
// keep player active // keep player active
deviceSession.setDisposePlayerOnClose( deviceSession.setDisposePlayerOnClose(
@ -1738,10 +1735,13 @@ private void startSendStreams()
{ {
try try
{ {
DataSource sendStreamDataSource
= sendStream.getDataSource();
// TODO Are we sure we want to connect here? // TODO Are we sure we want to connect here?
sendStream.getDataSource().connect(); sendStreamDataSource.connect();
sendStream.start(); sendStream.start();
sendStream.getDataSource().start(); sendStreamDataSource.start();
if (logger.isTraceEnabled()) if (logger.isTraceEnabled())
{ {
@ -1752,8 +1752,7 @@ private void startSendStreams()
} }
catch (IOException ioe) catch (IOException ioe)
{ {
logger logger.warn("Failed to start stream " + sendStream, ioe);
.warn("Failed to start stream " + sendStream, ioe);
} }
} }
} }
@ -2371,6 +2370,9 @@ private void printFlowStatistics(StreamRTPManager rtpManager)
*/ */
public void setRTPTranslator(RTPTranslator rtpTranslator) public void setRTPTranslator(RTPTranslator rtpTranslator)
{ {
this.rtpTranslator = rtpTranslator; if (this.rtpTranslator != rtpTranslator)
{
this.rtpTranslator = rtpTranslator;
}
} }
} }

@ -441,17 +441,37 @@ public void removeSessionListener(
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
/**
* Notifies this <tt>ReceiveStreamListener</tt> about a specific event
* related to a <tt>ReceiveStream</tt>.
*
* @param event a <tt>ReceiveStreamEvent</tt> which contains the specifics
* of the event this <tt>ReceiveStreamListener</tt> is being notified about
* @see ReceiveStreamListener#update(ReceiveStreamEvent)
*/
public void update(ReceiveStreamEvent event) public void update(ReceiveStreamEvent event)
{ {
StreamRTPManagerDesc streamRTPManagerDesc /*
= findStreamRTPManagerDescByReceiveSSRC( * Because NullPointerException was seen during testing, be thorough
event.getReceiveStream().getSSRC(), * with the null checks.
null); */
if (event != null)
{
ReceiveStream receiveStream = event.getReceiveStream();
if (streamRTPManagerDesc != null) if (receiveStream != null)
for (ReceiveStreamListener listener {
: streamRTPManagerDesc.getReceiveStreamListeners()) StreamRTPManagerDesc streamRTPManagerDesc
listener.update(event); = findStreamRTPManagerDescByReceiveSSRC(
receiveStream.getSSRC(),
null);
if (streamRTPManagerDesc != null)
for (ReceiveStreamListener listener
: streamRTPManagerDesc.getReceiveStreamListeners())
listener.update(event);
}
}
} }
private static class OutputDataStreamDesc private static class OutputDataStreamDesc

@ -598,13 +598,29 @@ public Component createLocalVisualComponent()
* it to the currently registered VideoListeners in a VideoEvent after * it to the currently registered VideoListeners in a VideoEvent after
* returning from the call. * returning from the call.
*/ */
Component localVisualComponent;
synchronized (localPlayerSyncRoot) synchronized (localPlayerSyncRoot)
{ {
if (localPlayer == null) if (localPlayer == null)
localPlayer = createLocalPlayer(); localPlayer = createLocalPlayer();
return localVisualComponent
(localPlayer == null) ? null : getVisualComponent(localPlayer); = (localPlayer == null)
? null
: getVisualComponent(localPlayer);
} }
/*
* If the local visual/video Component exists at this time, it has
* likely been created by a previous call to this method. However, the
* caller may still depend on a VIDEO_ADDED event being fired for it.
*/
if (localVisualComponent != null)
fireVideoEvent(
VideoEvent.VIDEO_ADDED,
localVisualComponent,
VideoEvent.LOCAL,
false);
return localVisualComponent;
} }
/** /**

@ -190,7 +190,6 @@ public void setCsrcAudioLevelAudioLevelExtensionID(byte extID,
{ {
this.csrcAudioLevelExtID = extID; this.csrcAudioLevelExtID = extID;
this.audioLevelDirection = dir; this.audioLevelDirection = dir;
} }
/** /**

@ -8,6 +8,7 @@
import net.java.sip.communicator.impl.neomedia.*; import net.java.sip.communicator.impl.neomedia.*;
import net.java.sip.communicator.impl.neomedia.transform.*; import net.java.sip.communicator.impl.neomedia.transform.*;
import net.java.sip.communicator.service.neomedia.format.*;
import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.*;
import net.sf.fmj.media.rtp.*; import net.sf.fmj.media.rtp.*;
@ -112,17 +113,18 @@ public RawPacket transform(RawPacket pkt)
lost = feedback.getNumLost(); lost = feedback.getNumLost();
// As sender reports are send on every 5 seconds // As sender reports are sent on every 5 seconds, print
// print every 4th packet, on every 20 seconds // every 4th packet, on every 20 seconds.
if(numberOfSenderReports % 4 != 1) if(numberOfSenderReports % 4 != 1)
return pkt; return pkt;
StringBuilder buff = new StringBuilder(RTP_STAT_PREFIX); StringBuilder buff = new StringBuilder(RTP_STAT_PREFIX);
MediaFormat mediaStreamFormat = mediaStream.getFormat();
buff.append("Sending a report for ") buff.append("Sending a report for ")
.append(mediaStream.getFormat() != null ? .append(mediaStreamFormat != null
mediaStream.getFormat().getMediaType() ? mediaStreamFormat.getMediaType()
: "") : "")
.append(" stream SSRC:") .append(" stream SSRC:")
.append(feedback.getSSRC()) .append(feedback.getSSRC())
.append(" [packet count:") .append(" [packet count:")

@ -289,26 +289,30 @@ public CallPeerJabberImpl initiateSession(
// if this was the first peer we added in this call then the call is // if this was the first peer we added in this call then the call is
// new and we also need to notify everyone of its creation. // new and we also need to notify everyone of its creation.
if(getCallPeerCount() == 1 && getCallGroup() == null) CallGroup callGroup = getCallGroup();
if ((getCallPeerCount() == 1) && (callGroup == null))
{ {
parentOpSet.fireCallEvent(CallEvent.CALL_INITIATED, this); parentOpSet.fireCallEvent(CallEvent.CALL_INITIATED, this);
} }
else if(getCallGroup() != null) else if (callGroup != null)
{ {
// only TelephonyConferencing OperationSet should know about it // only TelephonyConferencing OperationSet should know about it
CallEvent cEvent = new CallEvent(this, CallEvent.CALL_INITIATED); CallEvent event = new CallEvent(this, CallEvent.CALL_INITIATED);
AbstractOperationSetTelephonyConferencing<?,?,?,?,?> opSet = AbstractOperationSetTelephonyConferencing<?,?,?,?,?> opSet
(AbstractOperationSetTelephonyConferencing<?,?,?,?,?>) = (AbstractOperationSetTelephonyConferencing<?,?,?,?,?>)
getProtocolProvider().getOperationSet( getProtocolProvider()
OperationSetTelephonyConferencing.class); .getOperationSet(
if(opSet != null) OperationSetTelephonyConferencing.class);
opSet.outgoingCallCreated(cEvent);
if (opSet != null)
opSet.outgoingCallCreated(event);
} }
CallPeerMediaHandlerJabberImpl mediaHandler CallPeerMediaHandlerJabberImpl mediaHandler
= callPeer.getMediaHandler(); = callPeer.getMediaHandler();
/* enable video if it is a videocall */ /* enable video if it is a video call */
mediaHandler.setLocalVideoTransmissionEnabled(localVideoAllowed); mediaHandler.setLocalVideoTransmissionEnabled(localVideoAllowed);
/* enable remote-control if it is a desktop sharing session */ /* enable remote-control if it is a desktop sharing session */
mediaHandler.setLocalInputEvtAware(localInputEvtAware); mediaHandler.setLocalInputEvtAware(localInputEvtAware);
@ -320,22 +324,19 @@ else if(getCallGroup() != null)
// if initializing session fails, set peer to failed // if initializing session fails, set peer to failed
boolean sessionInitiated = false; boolean sessionInitiated = false;
try try
{ {
callPeer.initiateSession(sessionInitiateExtensions); callPeer.initiateSession(sessionInitiateExtensions);
sessionInitiated = true; sessionInitiated = true;
return callPeer;
} }
finally finally
{ {
// if initialization throws an exception // if initialization throws an exception
if(!sessionInitiated) if (!sessionInitiated)
{
callPeer.setState(CallPeerState.FAILED); callPeer.setState(CallPeerState.FAILED);
}
} }
return callPeer;
} }
/** /**

@ -449,17 +449,19 @@ else if(di != null)
// initiate call // initiate call
try try
{ {
if(isGingle) if (isGingle)
{ {
logger.info("initiate Gingle call"); logger.info("initiate Gingle call");
CallGTalkImpl callGTalk = new CallGTalkImpl(this); CallGTalkImpl callGTalk = new CallGTalkImpl(this);
MediaUseCase useCase = call.getMediaUseCase(); MediaUseCase useCase = call.getMediaUseCase();
boolean isVideo = call.isLocalVideoAllowed(useCase); boolean isVideo = call.isLocalVideoAllowed(useCase);
callGTalk.setCallGroup(call.getCallGroup());
callGTalk.setCallGroup(call.getCallGroup());
callGTalk.setLocalVideoAllowed(isVideo, useCase); callGTalk.setLocalVideoAllowed(isVideo, useCase);
peer = callGTalk.initiateGTalkSession(fullCalleeURI, peer
sessionInitiateExtensions); = callGTalk.initiateGTalkSession(
fullCalleeURI,
sessionInitiateExtensions);
} }
else if(di != null) else if(di != null)
{ {

@ -22,7 +22,7 @@
* by the associated protocol provider to be capabilities possessed by the * by the associated protocol provider to be capabilities possessed by the
* Jabber <tt>Contact</tt> in question. * Jabber <tt>Contact</tt> in question.
* *
* @author Lubomir Marinov * @author Lyubomir Marinov
* @author Yana Stamcheva * @author Yana Stamcheva
*/ */
public class OperationSetContactCapabilitiesJabberImpl public class OperationSetContactCapabilitiesJabberImpl
@ -318,14 +318,7 @@ private <U extends OperationSet> U getOperationSet(String jid,
* should fail anyway). * should fail anyway).
*/ */
if (!online) if (!online)
{ return OFFLINE_OPERATION_SETS.contains(opsetClass) ? opset : null;
if (OFFLINE_OPERATION_SETS.contains(opsetClass))
return opset;
else
{
return null;
}
}
/* /*
* If we know the features required for the support of opsetClass, check * If we know the features required for the support of opsetClass, check
@ -351,19 +344,20 @@ private <U extends OperationSet> U getOperationSet(String jid,
{ {
if(CAPS_OPERATION_SETS_TO_FEATURES.containsKey(opsetClass)) if(CAPS_OPERATION_SETS_TO_FEATURES.containsKey(opsetClass))
{ {
String[] extFeatures = String[] extFeatures
CAPS_OPERATION_SETS_TO_FEATURES.get( = CAPS_OPERATION_SETS_TO_FEATURES.get(opsetClass);
opsetClass);
// test GTalk // test GTalk
if(!parentProvider.isGTalkTesting()) if (!parentProvider.isGTalkTesting())
{ {
opset = null; opset = null;
} }
else else if((extFeatures == null)
if((extFeatures == null) || ((extFeatures.length != 0) && || ((extFeatures.length != 0)
!parentProvider.isExtFeatureListSupported(jid, && !parentProvider
extFeatures))) .isExtFeatureListSupported(
jid,
extFeatures)))
{ {
opset = null; opset = null;
} }

@ -123,7 +123,7 @@ protected void notifyAll(Call call)
/** /**
* Notifies all CallPeer associated with and established in a * Notifies all CallPeer associated with and established in a
* specific call has occurred * specific call has occurred
* @param call the <tt>Call</tt> *
* @param callPeer the <tt>CallPeer</tt> * @param callPeer the <tt>CallPeer</tt>
*/ */
private void notify(CallPeer callPeer) private void notify(CallPeer callPeer)
@ -461,8 +461,10 @@ protected CallPeer inviteCalleeToCall(
{ {
if (!wasConferenceFocus && call.isConferenceFocus()) if (!wasConferenceFocus && call.isConferenceFocus())
{ {
// reinvite other peers if any, to inform them that from now /*
// it is a conference call * Re-INVITE existing CallPeers to inform them that from now
* the specified call is a conference call.
*/
Iterator<CallPeerJabberImpl> callPeerIter = call.getCallPeers(); Iterator<CallPeerJabberImpl> callPeerIter = call.getCallPeers();
while (callPeerIter.hasNext()) while (callPeerIter.hasNext())
@ -473,10 +475,15 @@ protected CallPeer inviteCalleeToCall(
} }
} }
CoinPacketExtension confInfo = new CoinPacketExtension(true); return
return getBasicTelephony().createOutgoingCall( getBasicTelephony().createOutgoingCall(
call, calleeAddress, call,
Arrays.asList(new PacketExtension[] { confInfo })); calleeAddress,
Arrays.asList(
new PacketExtension[]
{
new CoinPacketExtension(true)
}));
} }
/** /**

@ -132,12 +132,16 @@ protected Call createOutgoingVideoCall(String calleeAddress)
/* enable video */ /* enable video */
call.setLocalVideoAllowed(true, getMediaUseCase()); call.setLocalVideoAllowed(true, getMediaUseCase());
CallPeer callPeer =
basicTelephony.createOutgoingCall(call, calleeAddress);
// if call is a Google Talk ones, return the CallGTalkImpl CallPeer callPeer
= basicTelephony.createOutgoingCall(call, calleeAddress);
return callPeer.getCall() == call ? call : callPeer.getCall(); /*
* XXX OperationSetBasicTelephonyJabberImpl#createOutgoingCall(
* CallJabberImpl, String) may have replaced the CallJabberImpl instance
* created above with a CallGTalkImpl instance.
*/
return callPeer.getCall();
} }
/** /**

@ -46,7 +46,7 @@
* *
* @author Damian Minkov * @author Damian Minkov
* @author Symphorien Wanko * @author Symphorien Wanko
* @author Lubomir Marinov * @author Lyubomir Marinov
* @author Yana Stamcheva * @author Yana Stamcheva
* @author Emil Ivov * @author Emil Ivov
*/ */
@ -2433,13 +2433,15 @@ public SecurityAuthority getAuthority()
*/ */
public boolean isGTalkTesting() public boolean isGTalkTesting()
{ {
return (Boolean.getBoolean("gtalktesting") || return
JabberActivator.getConfigurationService().getBoolean( Boolean.getBoolean("gtalktesting")
"net.java.sip.communicator.impl.protocol.jabber.gtalktesting" || JabberActivator.getConfigurationService().getBoolean(
, false) || "net.java.sip.communicator.impl.protocol.jabber"
accountID.getAccountPropertyBoolean( + ".gtalktesting",
ProtocolProviderFactory.IS_USE_GOOGLE_ICE, false)
true)); || accountID.getAccountPropertyBoolean(
ProtocolProviderFactory.IS_USE_GOOGLE_ICE,
true);
} }
UserCredentials getUserCredentials() UserCredentials getUserCredentials()

@ -16,7 +16,7 @@
* order to make it easier for implementers to provide complete solutions while * order to make it easier for implementers to provide complete solutions while
* focusing on protocol-specific details. * focusing on protocol-specific details.
* *
* @author Lubomir Marinov * @author Lyubomir Marinov
*/ */
public abstract class AbstractProtocolProviderService public abstract class AbstractProtocolProviderService
implements ProtocolProviderService implements ProtocolProviderService
@ -128,11 +128,8 @@ public void fireRegistrationStateChanged( RegistrationState oldState,
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug( logger.debug(
"Dispatching " "Dispatching " + event + " to " + listeners.length
+ event + " listeners.");
+ " to "
+ listeners.length
+ " listeners.");
for (RegistrationStateChangeListener listener : listeners) for (RegistrationStateChangeListener listener : listeners)
try try
@ -141,7 +138,6 @@ public void fireRegistrationStateChanged( RegistrationState oldState,
} }
catch (Throwable throwable) catch (Throwable throwable)
{ {
/* /*
* The registration state has already changed and we're not * The registration state has already changed and we're not
* using the RegistrationStateChangeListeners to veto the change * using the RegistrationStateChangeListeners to veto the change
@ -153,7 +149,10 @@ public void fireRegistrationStateChanged( RegistrationState oldState,
if (throwable instanceof ThreadDeath) if (throwable instanceof ThreadDeath)
throw (ThreadDeath) throwable; throw (ThreadDeath) throwable;
logger.error( logger.error(
"An error occurred while executing RegistrationStateChangeLister#registrationStateChanged(RegistrationStateChangeEvent) of " "An error occurred while executing "
+ "RegistrationStateChangeListener"
+ "#registrationStateChanged"
+ "(RegistrationStateChangeEvent) of "
+ listener, + listener,
throwable); throwable);
} }
@ -188,9 +187,10 @@ public <T extends OperationSet> T getOperationSet(Class<T> opsetClass)
*/ */
public String getProtocolDisplayName() public String getProtocolDisplayName()
{ {
String displayName = String displayName
getAccountID().getAccountPropertyString( = getAccountID().getAccountPropertyString(
ProtocolProviderFactory.PROTOCOL); ProtocolProviderFactory.PROTOCOL);
return (displayName == null) ? getProtocolName() : displayName; return (displayName == null) ? getProtocolName() : displayName;
} }

@ -182,7 +182,7 @@ public void removeVideoListener(CallPeer peer, VideoListener listener)
* @param allowed <tt>true</tt> if local video transmission is allowed and * @param allowed <tt>true</tt> if local video transmission is allowed and
* <tt>false</tt> otherwise. * <tt>false</tt> otherwise.
* *
* @throws OperationFailedException if video initialization fails. * @throws OperationFailedException if video initialization fails.
*/ */
public void setLocalVideoAllowed(Call call, boolean allowed) public void setLocalVideoAllowed(Call call, boolean allowed)
throws OperationFailedException throws OperationFailedException

@ -1261,12 +1261,16 @@ protected MediaStream initStream(StreamConnector connector,
logger.trace("The media types of device and format differ."); logger.trace("The media types of device and format differ.");
// check whether a control already exists // check whether a control already exists
SrtpControl control
= srtpControls.size() > 0
? srtpControls.get(
new MediaTypeSrtpControl(
mediaType,
srtpControls.firstKey().srtpControlType))
: null;
MediaService mediaService MediaService mediaService
= ProtocolMediaActivator.getMediaService(); = ProtocolMediaActivator.getMediaService();
SrtpControl control = srtpControls.size() > 0 ?
srtpControls.get(new MediaTypeSrtpControl(mediaType,
srtpControls.firstKey().srtpControlType)) : null;
if(control == null) if(control == null)
{ {
// this creates the default control, currently ZRTP without // this creates the default control, currently ZRTP without

@ -380,7 +380,19 @@ public RTPTranslator getRTPTranslator(MediaType mediaType)
{ {
RTPTranslator rtpTranslator = null; RTPTranslator rtpTranslator = null;
if (isConferenceFocus() && MediaType.VIDEO.equals(mediaType)) /*
* XXX The conferenceAudioMixer is created even when this Call is not a
* conference focus in order to enable additional functionality.
* Similarly, the videoRTPTranslator is created even when this Call is
* not a conference focus in order to enable this Call to turn into a
* conference focus at a later time. More specifically, MediaStreamImpl
* is unable to accommodate an RTPTranslator after it has created its
* RTPManager. Yet again like conferenceAudioMixer, we'd better not try
* to use it on Android at this time because of performance issues that
* may arise.
*/
if (MediaType.VIDEO.equals(mediaType)
&& (!OSUtils.IS_ANDROID || isConferenceFocus()))
{ {
if (videoRTPTranslator == null) if (videoRTPTranslator == null)
{ {
@ -504,16 +516,20 @@ public MediaDevice getDefaultDevice(MediaType mediaType)
switch (mediaType) switch (mediaType)
{ {
case AUDIO: case AUDIO:
/*
* TODO AudioMixer leads to very poor audio quality on Android so do
* not use it unless it is really really necessary.
*/
if ((conferenceAudioMixer == null) if ((conferenceAudioMixer == null)
&& (device != null) && (device != null)
/*
* TODO AudioMixer leads to very poor audio quality on
* Android so do not use it unless it is really really
* necessary.
*/
&& (!OSUtils.IS_ANDROID || isConferenceFocus()) && (!OSUtils.IS_ANDROID || isConferenceFocus())
// we can use audio mixer only if we /*
// have capture device (device can send) * We can use the AudioMixer only if the device is able to
&& (device.getDirection().allowsSending())) * capture (because the AudioMixer will push when the
* capture device pushes).
*/
&& device.getDirection().allowsSending())
conferenceAudioMixer = mediaService.createMixer(device); conferenceAudioMixer = mediaService.createMixer(device);
if (conferenceAudioMixer != null) if (conferenceAudioMixer != null)
device = conferenceAudioMixer; device = conferenceAudioMixer;
@ -745,10 +761,7 @@ public MediaUseCase getMediaUseCase()
*/ */
public boolean isLocalVideoAllowed(MediaUseCase useCase) public boolean isLocalVideoAllowed(MediaUseCase useCase)
{ {
if (mediaUseCase.equals(useCase)) return mediaUseCase.equals(useCase) && localVideoAllowed;
return localVideoAllowed;
else
return false;
} }
/** /**
@ -1069,7 +1082,7 @@ public void callAdded(CallGroupEvent evt)
CallPeer p = peers.next(); CallPeer p = peers.next();
getCrossProtocolCallPeersVector().add(p); getCrossProtocolCallPeersVector().add(p);
fireCallPeerEvent(p, CallPeerEvent.CALL_PEER_ADDED); fireCallPeerEvent(p, CallPeerEvent.CALL_PEER_ADDED);
this.setConferenceFocus(true); setConferenceFocus(true);
} }
} }

Loading…
Cancel
Save