aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java
diff options
context:
space:
mode:
authorLyubomir Marinov <lyubomir.marinov@jitsi.org>2009-03-16 12:48:14 +0000
committerLyubomir Marinov <lyubomir.marinov@jitsi.org>2009-03-16 12:48:14 +0000
commita29f088db924ab5912776029ea560d9162f0f9d5 (patch)
treea7486086af23f09d85411f24f907a5c559cd0c5d /src/net/java
parenta4bd4879917e82161b8cd8adbfa89119fa104ad6 (diff)
downloadjitsi-a29f088db924ab5912776029ea560d9162f0f9d5.zip
jitsi-a29f088db924ab5912776029ea560d9162f0f9d5.tar.gz
jitsi-a29f088db924ab5912776029ea560d9162f0f9d5.tar.bz2
Supports enabling/disabling the streaming of the local video to the remote call participants.
Diffstat (limited to 'src/net/java')
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java7
-rw-r--r--src/net/java/sip/communicator/impl/media/CallSessionImpl.java192
-rw-r--r--src/net/java/sip/communicator/impl/media/MediaControl.java130
-rw-r--r--src/net/java/sip/communicator/impl/media/codec/EncodingConfiguration.java85
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java47
-rw-r--r--src/net/java/sip/communicator/service/media/CallSession.java47
6 files changed, 327 insertions, 181 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java
index 43bebab..1d7aa19 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java
@@ -27,7 +27,7 @@ import net.java.sip.communicator.util.swing.border.*;
public class CallDialog
extends SIPCommFrame
implements ActionListener,
- MouseListener
+ MouseListener
{
private static final String DIAL_BUTTON = "DIAL_BUTTON";
@@ -71,10 +71,8 @@ public class CallDialog
muteButton = new MuteButton(call);
dialButton.setName(DIAL_BUTTON);
-
dialButton.setToolTipText(
GuiActivator.getResources().getI18NString("service.gui.DIALPAD"));
-
dialButton.addActionListener(this);
dialButton.addMouseListener(this);
@@ -83,15 +81,14 @@ public class CallDialog
contentPane.add(buttonsPanel, BorderLayout.SOUTH);
hangupButton.setName(HANGUP_BUTTON);
-
hangupButton.setToolTipText(
GuiActivator.getResources().getI18NString("service.gui.HANG_UP"));
-
hangupButton.addActionListener(this);
settingsPanel.add(dialButton);
settingsPanel.add(holdButton);
settingsPanel.add(muteButton);
+ settingsPanel.add(new LocalVideoButton(getCall()));
buttonsPanel.add(settingsPanel, BorderLayout.WEST);
buttonsPanel.add(hangupButton, BorderLayout.EAST);
diff --git a/src/net/java/sip/communicator/impl/media/CallSessionImpl.java b/src/net/java/sip/communicator/impl/media/CallSessionImpl.java
index 3bcfbe4..5b8be00 100644
--- a/src/net/java/sip/communicator/impl/media/CallSessionImpl.java
+++ b/src/net/java/sip/communicator/impl/media/CallSessionImpl.java
@@ -196,13 +196,7 @@ public class CallSessionImpl
* The flag which signals that this side of the call has put the other on
* hold.
*/
- private static final byte ON_HOLD_LOCALLY = 1 << 1;
-
- /**
- * The flag which signals that the other side of the call has put this on
- * hold.
- */
- private static final byte ON_HOLD_REMOTELY = 1 << 2;
+ private static final byte ON_HOLD_LOCALLY = 1 << 0;
/**
* Indicates an audio session type.
@@ -395,7 +389,7 @@ public class CallSessionImpl
throws MediaException
{
//start all audio streams
- boolean startedAtLeastOneStream = false;
+ boolean startedAtLeastOneAudioStream = false;
RTPManager rtpManager = getAudioRtpManager();
List<SendStream> sendStreams = rtpManager.getSendStreams();
@@ -411,7 +405,7 @@ public class CallSessionImpl
/** @todo are we sure we want to connect here? */
stream.getDataSource().connect();
stream.start();
- startedAtLeastOneStream = true;
+ startedAtLeastOneAudioStream = true;
}
catch (IOException ex)
{
@@ -425,6 +419,8 @@ public class CallSessionImpl
}
//start video streams
+ boolean startedAtLeastOneVideoStream = false;
+
rtpManager = getVideoRtpManager();
if(mediaServCallback.getMediaControl(getCall()).isLocalVideoAllowed()
&& ((sendStreams = rtpManager.getSendStreams()) != null)
@@ -438,24 +434,24 @@ public class CallSessionImpl
try
{
stream.start();
- startedAtLeastOneStream = true;
+ startedAtLeastOneVideoStream = true;
}
catch (IOException ex)
{
logger.warn("Failed to start stream.", ex);
}
}
-
- if (startedAtLeastOneStream)
- setLocalVideoStreaming(true);
}
else
{
logger.trace("No video send streams will be started.");
}
+ setLocalVideoStreaming(startedAtLeastOneVideoStream);
- if(!startedAtLeastOneStream && sendStreams.size() > 0)
+ if(!startedAtLeastOneAudioStream
+ && !startedAtLeastOneVideoStream
+ && (sendStreams.size() > 0))
{
stopStreaming();
throw new MediaException("Failed to start streaming"
@@ -841,17 +837,10 @@ public class CallSessionImpl
mediaDescription.setAttribute(newAttribute, null);
}
- /**
- * Determines whether a specific SDP description <tt>String</tt> offers
- * this party to be put on hold.
- *
- * @param sdpOffer the SDP description <tt>String</tt> to be examined for
- * an offer to this party to be put on hold
- * @return <tt>true</tt> if the specified SDP description <tt>String</tt>
- * offers this party to be put on hold; <tt>false</tt>, otherwise
- * @throws MediaException
+ /*
+ * Implements CallSession#getSdpOfferMediaFlags(String).
*/
- public boolean isSdpOfferToHold(String sdpOffer) throws MediaException
+ public int getSdpOfferMediaFlags(String sdpOffer) throws MediaException
{
SessionDescription description = null;
try
@@ -878,44 +867,96 @@ public class CallSessionImpl
MediaException.INTERNAL_ERROR, ex);
}
+ int mediaFlags = 0;
+
+ /* Determine whether we're being put on hold. */
boolean isOfferToHold = true;
for (Iterator<MediaDescription> mediaDescriptionIter
= mediaDescriptions.iterator();
- mediaDescriptionIter.hasNext()
- && isOfferToHold;)
+ mediaDescriptionIter.hasNext() && isOfferToHold;)
{
MediaDescription mediaDescription = mediaDescriptionIter.next();
- Vector<Attribute> attributes
+ Collection<Attribute> attributes
= mediaDescription.getAttributes(false);
isOfferToHold = false;
if (attributes != null)
{
for (Iterator<Attribute> attributeIter = attributes.iterator();
- attributeIter.hasNext()
- && !isOfferToHold;)
+ attributeIter.hasNext() && !isOfferToHold;)
{
try
{
String attribute = attributeIter.next().getName();
if ("sendonly".equalsIgnoreCase(attribute)
- || "inactive".equalsIgnoreCase(attribute))
- {
+ || "inactive".equalsIgnoreCase(attribute))
isOfferToHold = true;
- }
}
catch (SdpParseException ex)
{
throw new MediaException(
- "Failed to get SDP media description attribute name",
- MediaException.INTERNAL_ERROR,
- ex);
+ "Failed to get SDP media description attribute name",
+ MediaException.INTERNAL_ERROR,
+ ex);
}
}
}
}
- return isOfferToHold;
+ if (isOfferToHold)
+ mediaFlags |= ON_HOLD_REMOTELY;
+
+ /* Determine which of the media is to be received. */
+ for (MediaDescription mediaDescription : mediaDescriptions)
+ {
+ String mediaType;
+
+ try
+ {
+ mediaType = mediaDescription.getMedia().getMediaType();
+ }
+ catch (SdpParseException ex)
+ {
+ throw new MediaException(
+ "Failed to determine SDP description media type",
+ MediaException.INTERNAL_ERROR,
+ ex);
+ }
+
+ int mediaFlag = 0;
+
+ if ("audio".equalsIgnoreCase(mediaType))
+ mediaFlag = RECEIVE_AUDIO;
+ else if ("video".equalsIgnoreCase(mediaType))
+ mediaFlag = RECEIVE_VIDEO;
+
+ mediaFlags |= mediaFlag;
+
+ Collection<Attribute> attributes
+ = mediaDescription.getAttributes(false);
+
+ if (attributes != null)
+ for (Attribute attribute : attributes)
+ {
+ try
+ {
+ String name = attribute.getName();
+
+ if ("recvonly".equalsIgnoreCase(name)
+ || "inactive".equalsIgnoreCase(name))
+ mediaFlags &= ~mediaFlag;
+ }
+ catch (SdpParseException ex)
+ {
+ throw new MediaException(
+ "Failed to get SDP media description attribute name",
+ MediaException.INTERNAL_ERROR,
+ ex);
+ }
+ }
+ }
+
+ return mediaFlags;
}
/**
@@ -1070,7 +1111,11 @@ public class CallSessionImpl
CallParticipantState responderState = responder.getState();
if (CallParticipantState.CONNECTED.equals(responderState)
|| CallParticipantState.isOnHold(responderState))
+ {
+ mediaServCallback.getMediaControl(getCall())
+ .startProcessingMedia(this);
startStreaming();
+ }
}
/**
@@ -1476,9 +1521,8 @@ public class CallSessionImpl
}
else
{
- if (((lastIntendedDestination == null) && (intendedDestination != null))
- || ((lastIntendedDestination != null) && !lastIntendedDestination
- .equals(intendedDestination)))
+ if ((intendedDestination != null)
+ && !intendedDestination.equals(lastIntendedDestination))
{
startStreaming = stopStreaming();
audioRtpManager = RTPManager.newInstance();
@@ -2420,29 +2464,11 @@ public class CallSessionImpl
this);
// close all players that we have created in this session
- Iterator<Player> playersIter = players.iterator();
-
- while (playersIter.hasNext())
- {
- Player player = playersIter.next();
- player.stop();
-
- /*
- * The player is being disposed so let the (interested)
- * listeners know its Player#getVisualComponent() (if any)
- * should be released.
- */
- Component visualComponent = getVisualComponent(player);
- if (visualComponent != null)
- {
- fireVideoEvent(VideoEvent.VIDEO_REMOVED, visualComponent,
- VideoEvent.REMOTE);
- }
+ Player[] players
+ = this.players.toArray(new Player[this.players.size()]);
- player.deallocate();
- player.close();
- playersIter.remove();
- }
+ for (Player player : players)
+ disposePlayer(player);
// remove ourselves as listeners from the call
evt.getSourceCall().removeCallChangeListener(this);
@@ -2462,6 +2488,26 @@ public class CallSessionImpl
}
}
+ private void disposePlayer(Player player)
+ {
+ player.stop();
+
+ /*
+ * The player is being disposed so let the (interested) listeners know
+ * its Player#getVisualComponent() (if any) should be released.
+ */
+ Component visualComponent = getVisualComponent(player);
+
+ player.deallocate();
+ player.close();
+
+ players.remove(player);
+
+ if (visualComponent != null)
+ fireVideoEvent(VideoEvent.VIDEO_REMOVED, visualComponent,
+ VideoEvent.REMOTE);
+ }
+
/**
* Indicates that a change has occurred in the status of the source
* CallParticipant.
@@ -2758,8 +2804,8 @@ public class CallSessionImpl
}
else if (ce instanceof ControllerErrorEvent)
{
- logger
- .error("The following error was reported while starting a player"
+ logger.error(
+ "The following error was reported while starting a player"
+ ce);
}
else if (ce instanceof ControllerClosedEvent)
@@ -3247,6 +3293,26 @@ public class CallSessionImpl
return localVideoStreaming;
}
+ /*
+ * Implements CallSession#setReceiveStreaming(int).
+ */
+ public void setReceiveStreaming(int mediaFlags)
+ {
+ if ((mediaFlags & RECEIVE_VIDEO) == 0)
+ {
+ Player[] players
+ = this.players.toArray(new Player[this.players.size()]);
+
+ for (Player player : players)
+ {
+ Component visualComponent = getVisualComponent(player);
+
+ if (visualComponent != null)
+ disposePlayer(player);
+ }
+ }
+ }
+
private class LocalVisualComponentData
{
public final VideoListener listener;
diff --git a/src/net/java/sip/communicator/impl/media/MediaControl.java b/src/net/java/sip/communicator/impl/media/MediaControl.java
index 3ace374..800cc40 100644
--- a/src/net/java/sip/communicator/impl/media/MediaControl.java
+++ b/src/net/java/sip/communicator/impl/media/MediaControl.java
@@ -10,6 +10,7 @@ import java.awt.Dimension;
import java.io.*;
import java.net.*;
import java.util.*;
+
import javax.media.*;
import javax.media.control.*;
import javax.media.format.*;
@@ -90,7 +91,7 @@ public class MediaControl
* The processor that will be handling content coming from our capture data
* sources.
*/
- private Processor sourceProcessor = null;
+ public Processor sourceProcessor = null;
/**
* The list of readers currently using our processor.
@@ -248,7 +249,7 @@ public class MediaControl
setVideoDataSource((SourceCloneable) cloneableVideoDataSource);
}
- // Create the av data source
+ // Create the audio/video data source.
if (audioDataSource != null && videoDataSource != null)
{
try
@@ -263,10 +264,12 @@ public class MediaControl
{
logger.fatal(
"Failed to create a media data source!"
- + "Media transmission won't be enabled!", exc);
- throw new InternalError("Failed to create a media data source!"
- + "Media transmission won't be enabled!"
- + exc.getMessage());
+ + "Media transmission won't be enabled!",
+ exc);
+ throw new InternalError(
+ "Failed to create a media data source!"
+ + "Media transmission won't be enabled!"
+ + exc.getMessage());
}
}
else if (audioDataSource != null)
@@ -279,6 +282,8 @@ public class MediaControl
//avDataSource may be null (Bug report Vince Fourcade)
if (avDataSource != null)
initProcessor(avDataSource);
+ else
+ sourceProcessor = null;
}
/**
@@ -321,9 +326,7 @@ public class MediaControl
//avDataSource may be null (Bug report Vince Fourcade)
if (avDataSource != null)
- {
initProcessor(avDataSource);
- }
}
@@ -352,11 +355,11 @@ public class MediaControl
{
logger.error(
"An internal error occurred while"
- + " trying to connec to to datasource!"
+ + " trying to connec to the datasource!"
, ex);
throw new MediaException(
"An internal error occurred while"
- + " trying to connec to to datasource!"
+ + " trying to connec to the datasource!"
, MediaException.INTERNAL_ERROR
, ex);
}
@@ -389,7 +392,7 @@ public class MediaControl
{
throw new MediaException(
"Media manager could not configure processor\n"
- + "for the specified data source",
+ + "for the specified data source",
MediaException.INTERNAL_ERROR);
}
@@ -398,12 +401,12 @@ public class MediaControl
{
logger.error(
"Media manager could not create a processor\n"
- + "for the specified data source"
+ + "for the specified data source"
, ex
);
throw new MediaException(
"Media manager could not create a processor\n"
- + "for the specified data source"
+ + "for the specified data source"
, MediaException.INTERNAL_ERROR
, ex);
}
@@ -411,15 +414,15 @@ public class MediaControl
{
logger.error(
"Media manager could not connect "
- + "to the specified data source"
+ + "to the specified data source"
, ex);
throw new MediaException("Media manager could not connect "
- + "to the specified data source"
+ + "to the specified data source"
, MediaException.INTERNAL_ERROR
, ex);
}
- sourceProcessor.setContentDescriptor(new ContentDescriptor(
- ContentDescriptor.RAW_RTP));
+ sourceProcessor.setContentDescriptor(
+ new ContentDescriptor(ContentDescriptor.RAW_RTP));
/*
* The lists of the supported audio and video encodings will have to be
@@ -612,61 +615,57 @@ public class MediaControl
* @throws MediaException if creating the data source fails for some reason.
*/
public DataSource createDataSourceForEncodings(
- Hashtable<String, List<String>> encodingSets)
+ Map<String, List<String>> encodingSets)
throws MediaException
{
if (sourceProcessor == null)
{
logger.error("Processor is null.");
throw new MediaException("The source Processor has not been "
- + "initialized."
+ + "initialized."
, MediaException.INTERNAL_ERROR);
}
// Wait for the sourceProcessor to configure
- boolean processorIsReady = true;
if (sourceProcessor.getState() < Processor.Configured)
{
- processorIsReady = processorUtility
- .waitForState(sourceProcessor, Processor.Configured);
- }
- if (!processorIsReady)
- {
- logger.error("Couldn't configure sourceProcessor");
- throw new MediaException("Couldn't configure sourceProcessor"
- , MediaException.INTERNAL_ERROR);
+ if (!processorUtility.waitForState(sourceProcessor,
+ Processor.Configured))
+ {
+ logger.error("Couldn't configure sourceProcessor");
+ throw new MediaException("Couldn't configure sourceProcessor"
+ , MediaException.INTERNAL_ERROR);
+ }
}
// Get the tracks from the sourceProcessor
TrackControl[] tracks = sourceProcessor.getTrackControls();
- // Do we have atleast one track?
- if (tracks == null || tracks.length < 1)
+ // Do we have at least one track?
+ if ((tracks == null) || (tracks.length < 1))
{
logger.error("Couldn't find any tracks in sourceProcessor");
throw new MediaException(
"Couldn't find any tracks in sourceProcessor"
, MediaException.INTERNAL_ERROR);
}
- // Set the output content descriptor to RAW_RTP
- // This will limit the supported formats reported from
- // Track.getSupportedFormats to only valid RTP formats.
- ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.
- RAW_RTP);
- sourceProcessor.setContentDescriptor(cd);
- Format supported[];
- Format chosenFormat;
+ if (logger.isDebugEnabled()
+ && (sourceProcessor.getState() > Processor.Configured))
+ logger.debug(
+ "sourceProcessor is in state "
+ + sourceProcessor.getState()
+ + "which is > Processor.Configured"
+ + "and then TrackControl.setFormat(Format) may not work.");
boolean atLeastOneTrack = false;
// Program the tracks.
for (int i = 0; i < tracks.length; i++)
{
if (tracks[i].isEnabled())
{
- supported = tracks[i].getSupportedFormats();
+ Format[] supported = tracks[i].getSupportedFormats();
if (logger.isDebugEnabled())
{
logger.debug("Available encodings are:");
for (int j = 0; j < supported.length; j++)
{
- logger.debug("track[" + (i + 1) + "] format[" +
- (j + 1) + "]="
+ logger.debug("track[" + i + "] format[" + j + "]="
+ supported[j].getEncoding());
}
}
@@ -685,7 +684,7 @@ public class MediaControl
encodingSets);
if (index != -1)
{
- chosenFormat = assertSize(
+ Format chosenFormat = assertSize(
(VideoFormat)supported[index]);
tracks[i].setFormat(chosenFormat);
@@ -711,12 +710,15 @@ public class MediaControl
encodingSets);
if (index != -1)
{
- tracks[i].setFormat(supported[index]);
+ Format setFormat
+ = tracks[i].setFormat(supported[index]);
if (logger.isDebugEnabled())
{
- logger.debug("Track " + i +
- " is set to transmit as: "
- + supported[index]);
+ logger.debug(
+ "Track "
+ + i
+ + " is set to transmit as: "
+ + setFormat);
}
atLeastOneTrack = true;
}
@@ -747,9 +749,8 @@ public class MediaControl
}
// Realize the sourceProcessor. This will internally create a flow
// graph and attempt to create an output datasource
- processorIsReady = processorUtility.waitForState(sourceProcessor
- , Controller.Realized);
- if (!processorIsReady)
+ if (!processorUtility.waitForState(sourceProcessor,
+ Controller.Realized))
{
logger.error("Couldn't realize sourceProcessor");
throw new MediaException("Couldn't realize sourceProcessor"
@@ -888,23 +889,24 @@ public class MediaControl
* @return the index of the format corresponding to the first encoding that
* had a marching format in the <tt>availableFormats</tt> array.
*/
- protected int findFirstMatchingFormat(Format[] availableFormats,
- Hashtable<String, List<String>> requestedEncodings)
+ protected int findFirstMatchingFormat(
+ Format[] availableFormats,
+ Map<String, List<String>> requestedEncodings)
{
if (availableFormats == null || requestedEncodings == null)
{
return -1;
}
- Enumeration<List<String>> formatSets = requestedEncodings.elements();
- while (formatSets.hasMoreElements())
+ for (List<String> requestedEncodingSet : requestedEncodings.values())
{
- for (String currentSetElement : formatSets.nextElement())
+ for (String requestedEncoding : requestedEncodingSet)
{
for (int i = 0; i < availableFormats.length; i++)
{
- if (availableFormats[i].getEncoding().equals(
- currentSetElement))
+ String availableEncoding = availableFormats[i].getEncoding();
+
+ if (availableEncoding.equals(requestedEncoding))
{
return i;
}
@@ -914,7 +916,6 @@ public class MediaControl
return -1;
}
-
/**
* Returns an array of Strings containing video formats in the order of
* preference.
@@ -945,7 +946,7 @@ public class MediaControl
* that we don't pull the plug from underneath their feet.
*
* @param reader a reference to the object calling this method, that we
- * could use for keeping the number of simulaneous active readers.
+ * could use for keeping the number of simultaneous active readers.
*/
public void startProcessingMedia(Object reader)
{
@@ -1158,10 +1159,19 @@ public class MediaControl
localVideoAllowed = allowed;
if (sourceProcessor != null)
+ {
sourceProcessor.stop();
+ if (sourceProcessor.getState() == Processor.Realized)
+ {
+ DataSource dataOutput = sourceProcessor.getDataOutput();
+
+ if (dataOutput != null)
+ dataOutput.disconnect();
+ }
+ sourceProcessor.deallocate();
+ sourceProcessor.close();
+ }
initCaptureDevices();
- if (sourceProcessor.getState() != Processor.Started)
- sourceProcessor.start();
}
}
diff --git a/src/net/java/sip/communicator/impl/media/codec/EncodingConfiguration.java b/src/net/java/sip/communicator/impl/media/codec/EncodingConfiguration.java
index e6a77b0..0318d4e 100644
--- a/src/net/java/sip/communicator/impl/media/codec/EncodingConfiguration.java
+++ b/src/net/java/sip/communicator/impl/media/codec/EncodingConfiguration.java
@@ -32,20 +32,22 @@ public class EncodingConfiguration
* SDP Codes of all video formats that JMF supports.
*/
private final String[] availableVideoEncodings = new String[]
- { Integer.toString(Constants.H264_RTP_SDP),
- // javax.media.format.VideoFormat.H263_RTP
+ {
+ Integer.toString(Constants.H264_RTP_SDP),
+ // javax.media.format.VideoFormat.H263_RTP
Integer.toString(SdpConstants.H263),
// javax.media.format.VideoFormat.JPEG_RTP
Integer.toString(SdpConstants.JPEG),
// javax.media.format.VideoFormat.H261_RTP
- Integer.toString(SdpConstants.H261) };
+ Integer.toString(SdpConstants.H261)
+ };
/**
* SDP Codes of all audio formats that JMF supports.
*/
private final String[] availableAudioEncodings = new String[]
{
- // ILBC
+ // ILBC
Integer.toString(97),
// javax.media.format.AudioFormat.G723_RTP
Integer.toString(SdpConstants.G723),
@@ -58,13 +60,14 @@ public class EncodingConfiguration
// javax.media.format.AudioFormat.DVI_RTP;
Integer.toString(SdpConstants.DVI4_16000),
// javax.media.format.AudioFormat.ALAW;
- Integer.toString(SdpConstants.PCMA), Integer.toString(110),
+ Integer.toString(SdpConstants.PCMA),
+ Integer.toString(110),
// javax.media.format.AudioFormat.G728_RTP;
Integer.toString(SdpConstants.G728)
- // javax.media.format.AudioFormat.G729_RTP
+ // javax.media.format.AudioFormat.G729_RTP
// g729 is not suppported by JMF
// Integer.toString(SdpConstants.G729)
- };
+ };
private final Set<String> supportedVideoEncodings =
new TreeSet<String>(new EncodingComparator());
@@ -82,7 +85,7 @@ public class EncodingConfiguration
private final Map<String, Integer> encodingPreferences =
new Hashtable<String, Integer>();
- private static final String[] customCodecs =
+ private static final String[] CUSTOM_CODECS =
new String[]
{
FMJConditionals.FMJ_CODECS ? "net.sf.fmj.media.codec.audio.alaw.Encoder"
@@ -269,14 +272,12 @@ public class EncodingConfiguration
*/
public void registerCustomCodecs()
{
- // use a set to check if the codecs are already
- // registered in jmf.properties
- Set<String> registeredPlugins = new HashSet<String>();
-
- registeredPlugins.addAll(PlugInManager.getPlugInList(null, null,
- PlugInManager.CODEC));
+ // Register the custom codec which haven't already been registered.
+ Collection<String> registeredPlugins = new HashSet<String>(
+ PlugInManager.getPlugInList(null, null, PlugInManager.CODEC));
+ boolean commit = false;
- for (String className : customCodecs)
+ for (String className : CUSTOM_CODECS)
{
if (registeredPlugins.contains(className))
{
@@ -284,34 +285,50 @@ public class EncodingConfiguration
}
else
{
+ commit = true;
+
+ boolean registered;
+ Throwable exception = null;
+
try
{
- Object instance = Class.forName(className).newInstance();
-
- boolean result =
- PlugInManager.addPlugIn(className, ((Codec) instance)
- .getSupportedInputFormats(), ((Codec) instance)
- .getSupportedOutputFormats(null),
+ Codec codec = (Codec)
+ Class.forName(className).newInstance();
+
+ registered =
+ PlugInManager.addPlugIn(
+ className,
+ codec.getSupportedInputFormats(),
+ codec.getSupportedOutputFormats(null),
PlugInManager.CODEC);
- logger.debug("Codec : " + className
- + " is successfully registered : " + result);
}
catch (Throwable ex)
{
- logger.debug("Codec : " + className
- + " is NOT succsefully registered", ex);
+ registered = false;
+ exception = ex;
}
+ if (registered)
+ logger.debug(
+ "Codec "
+ + className
+ + " is successfully registered");
+ else
+ logger.debug(
+ "Codec "
+ + className
+ + " is NOT succsefully registered", exception);
}
}
- try
- {
- PlugInManager.commit();
- }
- catch (IOException ex)
- {
- logger.error("Cannot commit to PlugInManager", ex);
- }
+ if (commit)
+ try
+ {
+ PlugInManager.commit();
+ }
+ catch (IOException ex)
+ {
+ logger.error("Cannot commit to PlugInManager", ex);
+ }
// Register the custom codec formats with the RTP manager once at
// initialization. This is needed for the Sun JMF implementation. It
@@ -399,7 +416,7 @@ public class EncodingConfiguration
}
/**
- * Comaparator sorting the sets according the settings in
+ * Comaparator sorting the sets according to the settings in
* encodingPreferences.
*/
private class EncodingComparator
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java
index 67484a8..624ba3b 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java
@@ -885,7 +885,7 @@ public class OperationSetBasicTelephonySipImpl
if (callParticipant.getState()
== CallParticipantState.CONNECTING_WITH_EARLY_MEDIA)
{
- // This can happen if we are receigin early media for a second time.
+ // This can happen if we are receiving early media for a second time.
logger.warn("Ignoring invite 183 since call participant is "
+ "already exchanging early media.");
return;
@@ -1026,7 +1026,8 @@ public class OperationSetBasicTelephonySipImpl
/*
* Receiving an Invite OK is allowed even when the participant is
- * already connected for the purposes of call hold.
+ * already connected. Examples include call hold, enabling/disabling the
+ * streaming of local video while in a call.
*/
Request ack = null;
@@ -1074,7 +1075,7 @@ public class OperationSetBasicTelephonySipImpl
// listeners get alerted and they need the sdp
// ignore sdp if we have already received one in early media
if(!CallParticipantState.CONNECTING_WITH_EARLY_MEDIA.
- equals(callParticipant.getState()))
+ equals(callParticipant.getState()))
callParticipant.setSdpDescription(new String(ok.getRawContent()));
// notify the media manager of the sdp content
@@ -1128,13 +1129,17 @@ public class OperationSetBasicTelephonySipImpl
}
}
- // ignore sdp process if we have already received one in early media
+ /*
+ * We used to not process the SDP if we had already received one in
+ * early media. But functionality using re-invites (e.g. toggling
+ * the streaming of local video while in a call) may need to process
+ * the SDP (e.g. because of re-negotiating the media after toggling
+ * the streaming of local video).
+ */
CallParticipantState callParticipantState =
callParticipant.getState();
- if ((callParticipantState != CallParticipantState.CONNECTED)
- && !CallParticipantState.isOnHold(callParticipantState)
- && !CallParticipantState.CONNECTING_WITH_EARLY_MEDIA.
- equals(callParticipantState))
+ if (!CallParticipantState.CONNECTING_WITH_EARLY_MEDIA
+ .equals(callParticipantState))
{
callSession.processSdpAnswer(callParticipant, callParticipant
.getSdpDescription());
@@ -1145,7 +1150,7 @@ public class OperationSetBasicTelephonySipImpl
*/
callParticipant.setCallInfoURL(callSession.getCallInfoURL());
}
- //at this point we have already sent our ack so in adition to logging
+ //at this point we have already sent our ack so in addition to logging
//an error we also need to hangup the call participant.
catch (Exception exc)//Media or parse exception.
{
@@ -1791,8 +1796,10 @@ public class OperationSetBasicTelephonySipImpl
try
{
sdpAnswer =
- callSession.createSdpDescriptionForHold(sdpOffer, callSession
- .isSdpOfferToHold(sdpOffer));
+ callSession.createSdpDescriptionForHold(
+ sdpOffer,
+ (callSession.getSdpOfferMediaFlags(sdpOffer)
+ & CallSession.ON_HOLD_REMOTELY) != 0);
}
catch (MediaException ex)
{
@@ -1831,12 +1838,12 @@ public class OperationSetBasicTelephonySipImpl
CallParticipantSipImpl sipParticipant =
(CallParticipantSipImpl) participant;
- boolean on = false;
+ int mediaFlags = 0;
try
{
- on =
+ mediaFlags =
callSession
- .isSdpOfferToHold(sipParticipant.getSdpDescription());
+ .getSdpOfferMediaFlags(sipParticipant.getSdpDescription());
}
catch (MediaException ex)
{
@@ -1845,6 +1852,12 @@ public class OperationSetBasicTelephonySipImpl
OperationFailedException.INTERNAL_ERROR, ex);
}
+ /*
+ * Comply with the request of the SDP offer with respect to putting on
+ * hold.
+ */
+ boolean on = ((mediaFlags & CallSession.ON_HOLD_REMOTELY) != 0);
+
callSession.putOnHold(on, false);
CallParticipantState state = sipParticipant.getState();
@@ -1867,6 +1880,12 @@ public class OperationSetBasicTelephonySipImpl
{
sipParticipant.setState(CallParticipantState.ON_HOLD_REMOTELY);
}
+
+ /*
+ * Reflect the request of the SDP offer with respect to the modification
+ * of the availability of media.
+ */
+ callSession.setReceiveStreaming(mediaFlags);
}
/**
diff --git a/src/net/java/sip/communicator/service/media/CallSession.java b/src/net/java/sip/communicator/service/media/CallSession.java
index b6d2582..8e3d915 100644
--- a/src/net/java/sip/communicator/service/media/CallSession.java
+++ b/src/net/java/sip/communicator/service/media/CallSession.java
@@ -100,16 +100,53 @@ public interface CallSession
boolean onHold) throws MediaException;
/**
+ * The media flag which signals that the other side of the call has put this
+ * on hold.
+ */
+ public static final byte ON_HOLD_REMOTELY = 1 << 1;
+
+ /**
+ * The media flag which signals that audio streams being received are to be
+ * handled (e.g. played).
+ */
+ public static final byte RECEIVE_AUDIO = 1 << 2;
+
+ /**
+ * The media flag which signals that video streams being received are to be
+ * handled (e.g. played).
+ */
+ public static final byte RECEIVE_VIDEO = 1 << 3;
+
+ /**
* Determines whether a specific SDP description <tt>String</tt> offers
- * this party to be put on hold.
+ * this party to be put on hold and which media types are offered to be
+ * received.
*
* @param sdpOffer the SDP description <tt>String</tt> to be examined for
- * an offer to this party to be put on hold
- * @return <tt>true</tt> if the specified SDP description <tt>String</tt>
- * offers this party to be put on hold; <tt>false</tt>, otherwise
+ * an offer to this party to be put on hold and media types to be
+ * received
+ * @return an <tt>int</tt> bit mask containing
+ * <code>ON_HOLD_REMOTELY</code> if the specified SDP description
+ * offers this party to be put on hold, <code>RECEIVE_AUDIO</code>
+ * and/or <code>RECEIVE_VIDEO</code> if audio and/or video,
+ * respectively, are to be received
* @throws MediaException
*/
- public boolean isSdpOfferToHold(String sdpOffer) throws MediaException;
+ public int getSdpOfferMediaFlags(String sdpOffer) throws MediaException;
+
+ /**
+ * Modifies the current setup of the stream receiving in accord with a
+ * specific set of media flags (which are usually obtained through
+ * {@link #getSdpOfferMediaFlags(String)}. For example, if
+ * <code>RECEIVE_VIDEO</code> isn't present and video is currently being
+ * received and played, stops its receiving and playback.
+ *
+ * @param mediaFlags an <code>int</code> bit mask containing any of the
+ * media-related flags such as <code>RECEIVE_AUDIO</code> and
+ * <code>RECEIVE_VIDEO</code> and thus specifying which media
+ * types are to be received
+ */
+ public void setReceiveStreaming(int mediaFlags);
/**
* Puts the media of this <tt>CallSession</tt> on/off hold depending on