diff --git a/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_FFmpeg.c b/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_FFmpeg.c
index c05d3231e..d033b6b39 100644
--- a/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_FFmpeg.c
+++ b/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_FFmpeg.c
@@ -302,6 +302,7 @@ DEFINE_AVCODECCONTEXT_I_PROPERTY_SETTER(me_1method, me_method)
DEFINE_AVCODECCONTEXT_I_PROPERTY_SETTER(me_1range, me_range)
DEFINE_AVCODECCONTEXT_I_PROPERTY_SETTER(me_1subpel_1quality, me_subpel_quality)
DEFINE_AVCODECCONTEXT_I_PROPERTY_SETTER(pix_1fmt, pix_fmt)
+DEFINE_AVCODECCONTEXT_I_PROPERTY_SETTER(profile, profile)
DEFINE_AVCODECCONTEXT_F_PROPERTY_SETTER(qcompress, qcompress)
diff --git a/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_FFmpeg.h b/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_FFmpeg.h
index c95f85c4a..1823d73ff 100644
--- a/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_FFmpeg.h
+++ b/src/native/ffmpeg/net_java_sip_communicator_impl_neomedia_codec_FFmpeg.h
@@ -311,6 +311,14 @@ JNIEXPORT void JNICALL Java_net_java_sip_communicator_impl_neomedia_codec_FFmpeg
JNIEXPORT void JNICALL Java_net_java_sip_communicator_impl_neomedia_codec_FFmpeg_avcodeccontext_1set_1pix_1fmt
(JNIEnv *, jclass, jlong, jint);
+/*
+ * Class: net_java_sip_communicator_impl_neomedia_codec_FFmpeg
+ * Method: avcodeccontext_set_profile
+ * Signature: (JI)V
+ */
+JNIEXPORT void JNICALL Java_net_java_sip_communicator_impl_neomedia_codec_FFmpeg_avcodeccontext_1set_1profile
+ (JNIEnv *, jclass, jlong, jint);
+
/*
* Class: net_java_sip_communicator_impl_neomedia_codec_FFmpeg
* Method: avcodeccontext_set_qcompress
diff --git a/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java b/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java
index fe0a0a0f8..e2af1636a 100644
--- a/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java
+++ b/src/net/java/sip/communicator/impl/neomedia/VideoMediaStreamImpl.java
@@ -20,6 +20,7 @@
import net.java.sip.communicator.impl.neomedia.transform.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.neomedia.QualityControl; // disambiguation
+import net.java.sip.communicator.service.neomedia.control.*;
import net.java.sip.communicator.service.neomedia.control.KeyFrameControl; // disambiguation
import net.java.sip.communicator.service.neomedia.device.*;
import net.java.sip.communicator.service.neomedia.format.*;
@@ -870,7 +871,7 @@ public QualityControl getQualityControl()
* @author Lyubomir Marinov
*/
private class KeyFrameControlImpl
- implements KeyFrameControl
+ extends KeyFrameControlAdapter
{
}
diff --git a/src/net/java/sip/communicator/impl/neomedia/codec/FFmpeg.java b/src/net/java/sip/communicator/impl/neomedia/codec/FFmpeg.java
index 02eab6c72..daca4e1a3 100644
--- a/src/net/java/sip/communicator/impl/neomedia/codec/FFmpeg.java
+++ b/src/net/java/sip/communicator/impl/neomedia/codec/FFmpeg.java
@@ -96,6 +96,10 @@ public class FFmpeg
*/
public static final int FF_MIN_BUFFER_SIZE = 16384;
+ public static final int FF_PROFILE_H264_BASELINE = 66;
+
+ public static final int FF_PROFILE_H264_MAIN = 77;
+
/**
* ARGB format.
*/
@@ -466,6 +470,9 @@ public static native void avcodeccontext_set_me_subpel_quality(long avctx,
public static native void avcodeccontext_set_pix_fmt(long avctx,
int pix_fmt);
+ public static native void avcodeccontext_set_profile(long avctx,
+ int profile);
+
public static native void avcodeccontext_set_qcompress(long avctx,
float qcompress);
diff --git a/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/JNIEncoder.java b/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/JNIEncoder.java
index e1ea4d8ce..39846ee76 100644
--- a/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/JNIEncoder.java
+++ b/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/JNIEncoder.java
@@ -15,6 +15,7 @@
import net.java.sip.communicator.impl.neomedia.codec.*;
import net.java.sip.communicator.impl.neomedia.format.*;
import net.java.sip.communicator.service.neomedia.event.*;
+import net.java.sip.communicator.util.*;
import net.sf.fmj.media.*;
/**
@@ -28,6 +29,11 @@ public class JNIEncoder
extends AbstractCodec
implements RTCPFeedbackListener
{
+ /**
+ * The logger used by the JNIEncoder class and its instances for
+ * logging output.
+ */
+ private static final Logger logger = Logger.getLogger(JNIEncoder.class);
/**
* The frame rate to be assumed by JNIEncoder instance in the
@@ -348,9 +354,25 @@ public synchronized void open()
FFmpeg.avcodeccontext_set_keyint_min(avctx, 0);
if (packetizationMode == 0)
- FFmpeg.avcodeccontext_set_rtp_payload_size(
- avctx,
+ {
+ FFmpeg.avcodeccontext_set_rtp_payload_size(avctx,
Packetizer.MAX_PAYLOAD_SIZE);
+ }
+
+ /*
+ * XXX We do not currently negotiate the profile so, regardless of the
+ * many AVCodecContext properties we have set above, force the baseline
+ * profile which is the default in the absence of negotiation.
+ */
+ try
+ {
+ FFmpeg.avcodeccontext_set_profile(avctx,
+ FFmpeg.FF_PROFILE_H264_BASELINE);
+ }
+ catch (UnsatisfiedLinkError ule)
+ {
+ logger.warn("The FFmpeg JNI library is out-of-date.");
+ }
if (FFmpeg.avcodec_open(avctx, avcodec) < 0)
{
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/dtmf/DTMFInfo.java b/src/net/java/sip/communicator/impl/protocol/sip/dtmf/DTMFInfo.java
index ace7e6fd6..d071bc5c1 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/dtmf/DTMFInfo.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/dtmf/DTMFInfo.java
@@ -12,6 +12,7 @@
import java.util.*;
import javax.sip.*;
+import javax.sip.header.*;
import javax.sip.message.*;
import net.java.sip.communicator.impl.protocol.sip.*;
@@ -28,11 +29,24 @@ public class DTMFInfo
extends MethodProcessorAdapter
{
/**
- * logger for the class
+ * The Logger used by the DTMFInfo class and its instances
+ * for logging output.
*/
private static final Logger logger
= Logger.getLogger(DTMFInfo.class);
+ /**
+ * The sub-type of the content of the Requests being sent by
+ * DTMFInfo.
+ */
+ private static final String CONTENT_SUB_TYPE = "dtmf-relay";
+
+ /**
+ * The type of the content of the Requests being sent by
+ * DTMFInfo.
+ */
+ private static final String CONTENT_TYPE = "application";
+
/**
* Maps call peers and tone and its start time, so we can compute duration.
*/
@@ -120,9 +134,10 @@ private void sayInfo(CallPeerSipImpl callPeer,
callPeer.getDialog(), Request.INFO);
//here we add the body
- ContentType ct = new ContentType("application", "dtmf-relay");
- String content = "Signal=" + dtmftone.getValue()
- + "\r\nDuration=" + duration + "\r\n";
+ ContentType ct = new ContentType(CONTENT_TYPE, CONTENT_SUB_TYPE);
+ String content
+ = "Signal=" + dtmftone.getValue()
+ + "\r\nDuration=" + duration + "\r\n";
ContentLength cl = new ContentLength(content.length());
info.setContentLength(cl);
@@ -182,24 +197,7 @@ private void sayInfo(CallPeerSipImpl callPeer,
, ex);
}
}
-/*
- @Override
- public boolean processRequest(RequestEvent requestEvent)
- {
- try
- {
- requestEvent.getServerTransaction().sendResponse(
- pps.getMessageFactory().createResponse(
- Response.OK, requestEvent.getRequest()));
- }
- catch (Exception e)
- {
- e.printStackTrace(System.err);
- return false;
- }
- return true;
- }
-*/
+
/**
* Just look if the DTMF signal was well received, and log it
*
@@ -211,31 +209,72 @@ public boolean processRequest(RequestEvent requestEvent)
@Override
public boolean processResponse(ResponseEvent responseEvent)
{
+ boolean processed = false;
+
if (responseEvent == null)
{
if (logger.isDebugEnabled())
logger.debug("null responseEvent");
- return false;
- }
- Response response = responseEvent.getResponse();
- if (response == null)
- {
- if (logger.isDebugEnabled())
- logger.debug("null response");
- return false;
- }
- int code = response.getStatusCode();
- if (logger.isDebugEnabled())
- logger.debug("DTMF status code=" + code);
- if (code != 200)
- {
- logger.error("DTMF Send failed :" + code);
}
else
{
- if (logger.isDebugEnabled())
- logger.debug("DTMF succeeded");
+ Response response = responseEvent.getResponse();
+
+ if (response == null)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("null response");
+ }
+ else
+ {
+ // Is it even for us?
+ ClientTransaction clientTransaction
+ = responseEvent.getClientTransaction();
+
+ if (clientTransaction == null)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("null clientTransaction");
+ }
+ else
+ {
+ Request request = clientTransaction.getRequest();
+
+ if (request == null)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("null request");
+ }
+ else
+ {
+ ContentTypeHeader contentTypeHeader
+ = (ContentTypeHeader)
+ request.getHeader(ContentTypeHeader.NAME);
+
+ if ((contentTypeHeader != null)
+ && CONTENT_TYPE.equalsIgnoreCase(
+ contentTypeHeader.getContentType())
+ && CONTENT_SUB_TYPE.equalsIgnoreCase(
+ contentTypeHeader.getContentSubType()))
+ {
+ processed = true;
+
+ int statusCode = response.getStatusCode();
+
+ if (statusCode == 200)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug(
+ "DTMF send succeeded: "
+ + statusCode);
+ }
+ else
+ logger.error("DTMF send failed: " + statusCode);
+ }
+ }
+ }
+ }
}
- return true;
+ return processed;
}
}
diff --git a/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControl.java b/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControl.java
index 9fda6b737..9cd523b87 100644
--- a/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControl.java
+++ b/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControl.java
@@ -6,6 +6,8 @@
*/
package net.java.sip.communicator.service.neomedia.control;
+import java.util.*;
+
/**
* Represents a control over the key frame-related logic of a
* VideoMediaStream.
@@ -14,4 +16,48 @@
*/
public interface KeyFrameControl
{
+ /**
+ * Adds a KeyFrameRequester to be made available through this
+ * KeyFrameControl.
+ *
+ * @param index the zero-based index at which keyFrameRequester is
+ * to be added to the list of KeyFrameRequesters made available
+ * through this KeyFrameControl
+ * @param keyFrameRequester the KeyFrameRequester to be added to
+ * this KeyFrameControl so that it is made available through it
+ */
+ public void addKeyFrameRequester(
+ int index,
+ KeyFrameRequester keyFrameRequester);
+
+ /**
+ * Gets the KeyFrameRequesters made available through this
+ * KeyFrameControl.
+ *
+ * @return an unmodifiable list of KeyFrameRequesters made
+ * available through this KeyFrameControl
+ */
+ public List getKeyFrameRequesters();
+
+ /**
+ * Removes a KeyFrameRequester to no longer be made available
+ * through this KeyFrameControl.
+ *
+ * @param keyFrameRequester the KeyFrameRequester to be removed
+ * from this KeyFrameControl so that it is no longer made available
+ * through it
+ * @return true if keyFrameRequester was found in this
+ * KeyFrameControl; otherwise, false
+ */
+ public boolean removeKeyFrameRequester(KeyFrameRequester keyFrameRequester);
+
+ /**
+ * Represents a way for a VideoMediaStream to request a key frame
+ * from its remote peer.
+ *
+ * @author Lyubomir Marinov
+ */
+ public interface KeyFrameRequester
+ {
+ }
}
diff --git a/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControlAdapter.java b/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControlAdapter.java
new file mode 100644
index 000000000..ab48257ff
--- /dev/null
+++ b/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControlAdapter.java
@@ -0,0 +1,107 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.neomedia.control;
+
+import java.util.*;
+
+/**
+ * Provides a default implementation of {@link KeyFrameControl}.
+ *
+ * @author Lyubomir Marinov
+ */
+public class KeyFrameControlAdapter
+ implements KeyFrameControl
+{
+ /**
+ * The KeyFrameRequesters made available by this
+ * KeyFrameControl.
+ */
+ private List keyFrameRequesters
+ = new ArrayList(0);
+
+ /**
+ * An unmodifiable view of {@link #keyFrameRequesters} appropriate to be
+ * returned by {@link #getKeyFrameRequesters()}.
+ */
+ private List unmodifiableKeyFrameRequesters;
+
+ /**
+ * Implements
+ * {@link KeyFrameControl#addKeyFrameRequester(int, KeyFrameRequester)}.
+ *
+ * {@inheritDoc}
+ */
+ public void addKeyFrameRequester(
+ int index,
+ KeyFrameRequester keyFrameRequester)
+ {
+ if (keyFrameRequester == null)
+ throw new NullPointerException("keyFrameRequester");
+ synchronized (this)
+ {
+ if (!keyFrameRequesters.contains(keyFrameRequester))
+ {
+ List newKeyFrameRequesters
+ = new ArrayList(
+ keyFrameRequesters.size() + 1);
+
+ newKeyFrameRequesters.addAll(keyFrameRequesters);
+ newKeyFrameRequesters.add(index, keyFrameRequester);
+
+ keyFrameRequesters = newKeyFrameRequesters;
+ unmodifiableKeyFrameRequesters = null;
+ }
+ }
+ }
+
+ /**
+ * Implements {@link KeyFrameControl#getKeyFrameRequesters()}.
+ *
+ * {@inheritDoc}
+ */
+ public List getKeyFrameRequesters()
+ {
+ synchronized (this)
+ {
+ if (unmodifiableKeyFrameRequesters == null)
+ {
+ unmodifiableKeyFrameRequesters
+ = Collections.unmodifiableList(keyFrameRequesters);
+ }
+ return unmodifiableKeyFrameRequesters;
+ }
+ }
+
+ /**
+ * Implements
+ * {@link KeyFrameControl#removeKeyFrameRequester(KeyFrameRequester)}.
+ *
+ * {@inheritDoc}
+ */
+ public boolean removeKeyFrameRequester(KeyFrameRequester keyFrameRequester)
+ {
+ synchronized (this)
+ {
+ int index = keyFrameRequesters.indexOf(keyFrameRequester);
+
+ if (-1 != index)
+ {
+ List newKeyFrameRequesters
+ = new ArrayList(keyFrameRequesters);
+
+ newKeyFrameRequesters.remove(index);
+
+ keyFrameRequesters = newKeyFrameRequesters;
+ unmodifiableKeyFrameRequesters = null;
+
+ return true;
+ }
+ else
+ return false;
+ }
+ }
+}