From e57467e87d6270ce296c1896ab73f0a886264ef1 Mon Sep 17 00:00:00 2001 From: Emil Ivov Date: Sat, 12 Dec 2009 12:18:20 +0000 Subject: [PATCH] Adds more CSRC level encoding params. Adds a new CsrcAudioLevelListener --- .../impl/neomedia/AudioMediaStreamImpl.java | 31 ++++++++-- .../communicator/impl/neomedia/RawPacket.java | 57 ++++++++++++++++++- .../audiolevel/CsrcAudioLevelListener.java | 31 ++++++++++ .../device/AudioMediaDeviceSession.java | 3 +- .../service/neomedia/AudioMediaStream.java | 10 ++-- 5 files changed, 116 insertions(+), 16 deletions(-) create mode 100644 src/net/java/sip/communicator/impl/neomedia/audiolevel/CsrcAudioLevelListener.java 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