diff --git a/src/net/java/sip/communicator/impl/neomedia/AudioMediaStreamImpl.java b/src/net/java/sip/communicator/impl/neomedia/AudioMediaStreamImpl.java
index 7e6ee3d1a..0eb8e2bc4 100644
--- a/src/net/java/sip/communicator/impl/neomedia/AudioMediaStreamImpl.java
+++ b/src/net/java/sip/communicator/impl/neomedia/AudioMediaStreamImpl.java
@@ -10,6 +10,7 @@
import javax.media.format.*;
import javax.media.rtp.*;
+import net.java.sip.communicator.impl.neomedia.audiolevel.*;
import net.java.sip.communicator.impl.neomedia.codec.*;
import net.java.sip.communicator.impl.neomedia.device.*;
import net.java.sip.communicator.service.neomedia.*;
@@ -65,6 +66,12 @@ public class AudioMediaStreamImpl
*/
private static boolean formatsRegisteredOnce = false;
+ /**
+ * The listener that gets notified of changes in the audio level of
+ * remote conference participants.
+ */
+ private CsrcAudioLevelListener csrcAudioLevelListener = null;
+
/**
* Initializes a new AudioMediaStreamImpl instance which will use
* the specified MediaDevice for both capture and playback of audio
@@ -114,16 +121,16 @@ public void setStreamAudioLevelListener(SimpleAudioLevelListener listener)
}
/**
- * Registers listener as the SoundLevelListener that will
- * receive notifications for changes in the levels of conference
+ * Registers listener as the CsrcAudioLevelListener that
+ * will receive notifications for changes in the levels of conference
* participants that the remote party could be mixing.
*
- * @param listener the SoundLevelListener that we'd like to
+ * @param listener the CsrcAudioLevelListener that we'd like to
* register or null if we'd like to stop receiving notifications.
*/
- public void setConferenceMemberAudioLevelListener(
- SimpleAudioLevelListener listener)
+ public void setCsrcAudioLevelListener(CsrcAudioLevelListener listener)
{
+ this.csrcAudioLevelListener = listener;
}
/**
@@ -223,7 +230,7 @@ public void addRTPExtension(byte extensionID, RTPExtension rtpExtension)
if ( RTPExtension.CSRC_AUDIO_LEVEL_URN
.equals(rtpExtension.getURI().toString()))
- getCsrcEngine().setCsrcAudioLevelsEnabled(true);
+ getCsrcEngine().setCsrcAudioLevelAudioLevelExtensionID(extensionID);
}
/**
@@ -277,4 +284,16 @@ public int getLastMeasuredAudioLevel(long ssrc)
else
return devSession.getLastMeasuredAudioLevel(ssrc);
}
+
+ /**
+ * Delivers the audioLevels map to whoever's interested.
+ *
+ * @param audioLevels a bidimensional array mapping CSRC IDs to audio
+ * levels.
+ */
+ private void fireConferenceAudioLevelEvent(final long[][] audioLevels)
+ {
+ if (this.csrcAudioLevelListener != null)
+ this.csrcAudioLevelListener.audioLevelsReceived(audioLevels);
+ }
}
diff --git a/src/net/java/sip/communicator/impl/neomedia/RawPacket.java b/src/net/java/sip/communicator/impl/neomedia/RawPacket.java
index 944e77055..b92eaba39 100755
--- a/src/net/java/sip/communicator/impl/neomedia/RawPacket.java
+++ b/src/net/java/sip/communicator/impl/neomedia/RawPacket.java
@@ -484,8 +484,11 @@ private void setExtensionBit(boolean extBit)
*
* @return the length of the extensions currently added to this packet.
*/
- public int getExtensionsLength()
+ public int getExtensionLength()
{
+ if (!getExtensionBit())
+ return 0;
+
//the extension length comes after the RTP header, the CSRC list, and
//after two bytes in the extension header called "defined by profile"
int extLenIndex = offset
@@ -502,7 +505,7 @@ public int getExtensionsLength()
* @param length the length of the extensions currently recorded in the
* buffer of this packet.
*/
- private void setExtensionsLength(int length)
+ private void setExtensionLength(int length)
{
//the extension length comes after the RTP header, the CSRC list, and
//after two bytes in the extension header called "defined by profile"
@@ -527,9 +530,57 @@ private void setExtensionsLength(int length)
*/
public void addExtension(byte[] extBuff, int length)
{
- byte[] newBuffer = new byte[getLength() + EXT_HEADER_SIZE + length ];
+ int newBuffLen = getLength() + length;
+
+ //if there was no extension previously, we also need to consider adding
+ //the extension header.
+ if (!getExtensionBit())
+ newBuffLen += EXT_HEADER_SIZE;
+
+ byte[] newBuffer = new byte[ newBuffLen ];
+
+ //copy header and CSRC list any previous extensions if any
+ System.arraycopy(buffer, offset, newBuffer, offset,
+ FIXED_HEADER_SIZE
+ + getCsrcCount()*4 + getExtensionLength());
+
+ //raise the extension bit.
+ newBuffer[offset] |= 0x10;
+
+ //if there were no extensions previously, we need to add the hdr now
+ if(! getExtensionBit())
+ {
+ // we will now be adding the RFC 5285 ext header which looks like
+ // this:
+ //
+ // 0 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | 0xBE | 0xDE | length=3 |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ int extHdrOffset = FIXED_HEADER_SIZE + getCsrcCount()*4;
+ newBuffer[extHdrOffset] = (byte)0xBE;
+ newBuffer[extHdrOffset+1] = (byte)0xDE;
+
+ int newExtensionLen = length + getExtensionLength();
+ newBuffer[extHdrOffset+2] = (byte)(newExtensionLen >>4);
+ newBuffer[extHdrOffset+3] = (byte)newExtensionLen;
+ }
+ //copy the extension content from the new extension.
+ System.arraycopy(extBuff, 0, newBuffer, FIXED_HEADER_SIZE
+ + getCsrcCount()*4 + getExtensionLength(),
+ length);
+ //now copy the payload
+ int oldPayloadOffset = FIXED_HEADER_SIZE + getCsrcCount()*4
+ + getExtensionLength();
+ int newPayloadOffset = oldPayloadOffset + length;
+ System.arraycopy(buffer, oldPayloadOffset,
+ newBuffer, newPayloadOffset,
+ FIXED_HEADER_SIZE
+ + getCsrcCount()*4 + getExtensionLength());
}
}
diff --git a/src/net/java/sip/communicator/impl/neomedia/audiolevel/CsrcAudioLevelListener.java b/src/net/java/sip/communicator/impl/neomedia/audiolevel/CsrcAudioLevelListener.java
new file mode 100644
index 000000000..7f3916357
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/neomedia/audiolevel/CsrcAudioLevelListener.java
@@ -0,0 +1,31 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.neomedia.audiolevel;
+
+/**
+ * The CsrcAudioLevelListener delivers audio level events reported by
+ * the remote party in cases where it (the remote party) is acting as a mixer,
+ * mixing flows from numerous contributors. It is up to upper layers such as
+ * SIP to define means of determining the exact members that the CSRC IDs and
+ * hence audio levels participants belong to.
+ *
+ * @author Emil Ivov
+ */
+public interface CsrcAudioLevelListener
+{
+
+ /**
+ * Called by the media service implementation after it has received audio
+ * levels for the various participants (Contributing SouRCes) that are
+ * taking part in a conference call.
+ *
+ * @param audioLevels the new set of levels for the various contributing
+ * sources in the conference call.
+ */
+ public void audioLevelsReceived(final long[][] audioLevels);
+
+}
diff --git a/src/net/java/sip/communicator/impl/neomedia/device/AudioMediaDeviceSession.java b/src/net/java/sip/communicator/impl/neomedia/device/AudioMediaDeviceSession.java
index 1950d87ed..cd387bfd9 100644
--- a/src/net/java/sip/communicator/impl/neomedia/device/AudioMediaDeviceSession.java
+++ b/src/net/java/sip/communicator/impl/neomedia/device/AudioMediaDeviceSession.java
@@ -56,8 +56,7 @@ protected AudioMediaDeviceSession(AbstractMediaDevice device)
}
/**
- * Called by {@link MediaDeviceSession#addReceiveStream(ReceiveStream,
- * DataSource)} when the player associated with this session's
+ * Called by {@link MediaDeviceSession#addReceiveStream(ReceiveStream)} when the player associated with this session's
* ReceiveStream moves enters the Configured state, so
* we use the occasion to add our audio level effect.
*
diff --git a/src/net/java/sip/communicator/service/neomedia/AudioMediaStream.java b/src/net/java/sip/communicator/service/neomedia/AudioMediaStream.java
index 1c5b0e1ff..09e6445ad 100644
--- a/src/net/java/sip/communicator/service/neomedia/AudioMediaStream.java
+++ b/src/net/java/sip/communicator/service/neomedia/AudioMediaStream.java
@@ -6,6 +6,7 @@
*/
package net.java.sip.communicator.service.neomedia;
+import net.java.sip.communicator.impl.neomedia.audiolevel.*;
import net.java.sip.communicator.service.neomedia.event.*;
/**
@@ -29,15 +30,14 @@ public interface AudioMediaStream
public void setStreamAudioLevelListener(SimpleAudioLevelListener listener);
/**
- * Registers listener as the SoundLevelListener that will
- * receive notifications for changes in the levels of conference
+ * Registers listener as the CsrcAudioLevelListener that
+ * will receive notifications for changes in the levels of conference
* participants that the remote party could be mixing.
*
- * @param listener the SoundLevelListener that we'd like to
+ * @param listener the CsrcAudioLevelListener that we'd like to
* register or null if we'd like to stop receiving notifications.
*/
- public void setConferenceMemberAudioLevelListener(
- SimpleAudioLevelListener listener);
+ public void setCsrcAudioLevelListener(CsrcAudioLevelListener listener);
/**
* Sets listener as the SimpleAudioLevelListener