Adds final touches to CSRC level decoding. Implements event dispatching for CSRC audio levels.

cusax-fix
Emil Ivov 16 years ago
parent d251d3e1f3
commit 43c58e4b7b

@ -286,12 +286,14 @@ public int getLastMeasuredAudioLevel(long ssrc)
}
/**
* Delivers the <tt>audioLevels</tt> map to whoever's interested.
* Delivers the <tt>audioLevels</tt> map to whoever's interested. This
* method is meant for use primarily by the transform engine handling
* incoming RTP packets (currently <tt>CsrcTransformEngine</tt>).
*
* @param audioLevels a bidimensional array mapping CSRC IDs to audio
* @param audioLevels a bi-dimensional array mapping CSRC IDs to audio
* levels.
*/
private void fireConferenceAudioLevelEvent(final long[][] audioLevels)
public void fireConferenceAudioLevelEvent(final long[][] audioLevels)
{
if (this.csrcAudioLevelListener != null)
this.csrcAudioLevelListener.audioLevelsReceived(audioLevels);

@ -345,6 +345,9 @@ public void close()
engine.cleanup();
}
if(csrcEngine != null)
csrcEngine.stop();
rtpConnector.removeTargets();
rtpConnectorTarget = null;

@ -6,6 +6,8 @@
*/
package net.java.sip.communicator.impl.neomedia.transform.csrc;
import javax.media.*;
import net.java.sip.communicator.impl.neomedia.*;
import net.java.sip.communicator.impl.neomedia.transform.*;
@ -43,6 +45,11 @@ public class CsrcTransformEngine
*/
private int extensionBuffLen = 0;
/**
* The dispatcher that is delivering audio levels to the media steam.
*/
private CsrcAudioLevelDispatcher csrcLevelDispatcher = null;
/**
* Creates an engine instance that will be adding CSRC lists to the
* specified <tt>stream</tt>.
@ -94,6 +101,22 @@ public PacketTransformer getRTPTransformer()
*/
public RawPacket reverseTransform(RawPacket pkt)
{
if (csrcAudioLevelExtID > 0)
{
//extract the audio levels and send them to the dispatcher.
long[][] levels = pkt.extractCsrcLevels(csrcAudioLevelExtID);
if(levels != null)
{
if (csrcLevelDispatcher == null)
csrcLevelDispatcher = new CsrcAudioLevelDispatcher();
if( ! csrcLevelDispatcher.isRunning )
new Thread(csrcLevelDispatcher).start();
csrcLevelDispatcher.addLevels(levels);
}
}
return pkt;
}
@ -133,6 +156,15 @@ public synchronized RawPacket transform(RawPacket pkt)
return pkt;
}
/**
* Stops threads that this transform engine is using for even delivery.
*/
public void stop()
{
if(csrcLevelDispatcher != null)
csrcLevelDispatcher.stop();
}
/**
* Sets the ID that this transformer should be using for audio level
* extensions or disables audio level extensions if <tt>extID</tt> is
@ -199,4 +231,90 @@ private byte[] getExtensionBuff(int ensureCapacity)
return extensionBuff;
}
/**
* A simple thread that waits for new levels to be reported from incoming
* RTP packets and then delivers them to the <tt>AudioMediaStream</tt>
* associated with this engine. The reason we need to do this in a separate
* thread is of course the time sensitive nature of incoming RTP packets.
*/
private class CsrcAudioLevelDispatcher
implements Runnable
{
/** Indicates whether this thread is supposed to be running */
private boolean isRunning = true;
/** The levels that we last received from the reverseTransform thread*/
private long[][] lastReportedLevels = null;
/**
* Waits for new levels to be reported via the <tt>addLevels()</tt>
* method and then delivers them to the <tt>AudioMediaStream</tt> that
* we are associated with.
*/
public void run()
{
isRunning = true;
//no point in listening if our stream is not an audio one.
if(!(mediaStream instanceof AudioMediaStreamImpl))
return;
while(isRunning)
{
synchronized(this)
{
if(lastReportedLevels == null)
{
try
{
wait();
}
catch (InterruptedException ie) {}
}
}
if(lastReportedLevels != null)
{
//now notify our listener
if (mediaStream != null)
{
((AudioMediaStreamImpl)mediaStream)
.fireConferenceAudioLevelEvent(lastReportedLevels);
}
}
}
}
/**
* A level matrix that we should deliver to our media stream and
* its listeners in a separate thread.
*
* @param levels the levels that we'd like to queue for processing.
*/
public void addLevels(long[][] levels)
{
synchronized(this)
{
this.lastReportedLevels = levels;
notifyAll();
}
}
/**
* Causes our run method to exit so that this thread would stop
* handling levels.
*/
public void stop()
{
synchronized(this)
{
this.lastReportedLevels = null;
isRunning = false;
notifyAll();
}
}
}
}

@ -16,8 +16,7 @@
import javax.sip.message.*;
import net.java.sip.communicator.impl.protocol.sip.sdp.*;
import net.java.sip.communicator.service.neomedia.event.ZrtpListener;
import net.java.sip.communicator.service.neomedia.event.SimpleAudioLevelListener;
import net.java.sip.communicator.service.neomedia.event.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
@ -32,6 +31,7 @@ public class CallPeerSipImpl
extends AbstractCallPeer
implements SimpleAudioLevelListener,
CallPeerConferenceListener,
CsrcAudioLevelListener,
ZrtpListener
{
/**
@ -129,6 +129,15 @@ public class CallPeerSipImpl
private List<SoundLevelListener> streamAudioLevelListeners
= new ArrayList<SoundLevelListener>();
/**
* Holds listeners registered for level changes in the audio of participants
* that this peer might be mixing and that we are not directly communicating
* with.
*/
private List<ConferenceMembersSoundLevelListener>
conferenceMemberAudioLevelListeners
= new ArrayList<ConferenceMembersSoundLevelListener>();
/**
* Creates a new call peer with address <tt>peerAddress</tt>.
*
@ -1742,8 +1751,21 @@ public void removeStreamSoundLevelListener(SoundLevelListener listener)
* @param listener the <tt>ConferenceMembersSoundLevelListener</tt> to add
*/
public void addConferenceMembersSoundLevelListener(
ConferenceMembersSoundLevelListener listener)
ConferenceMembersSoundLevelListener listener)
{
synchronized (conferenceMemberAudioLevelListeners)
{
if (conferenceMemberAudioLevelListeners.size() == 0)
{
// if this is the first listener that's being registered with
// us, we also need to register ourselves as a CSRC audio level
// listener with the media handler.
getMediaHandler().setCsrcAudioLevelListener(this);
}
conferenceMemberAudioLevelListeners.add(listener);
}
}
/**
@ -1757,6 +1779,31 @@ public void addConferenceMembersSoundLevelListener(
public void removeConferenceMembersSoundLevelListener(
ConferenceMembersSoundLevelListener listener)
{
synchronized (conferenceMemberAudioLevelListeners)
{
conferenceMemberAudioLevelListeners.remove(listener);
if (conferenceMemberAudioLevelListeners.size() == 0)
{
// if this was the last listener then we also remove ourselves
// as a CSRC audio level listener from the handler so that we
// don't have to create new events and maps for something no one
// is interested in.
getMediaHandler().setCsrcAudioLevelListener(null);
}
}
}
/**
* Implements {@link CsrcAudioLevelListener#audioLevelsReceived(long[][])}
* so that we could deliver to {@link ConferenceMembersSoundLevelListener}s
* the events corresponding to the audio level changes that are being
* reported here.
*/
public void audioLevelsReceived(long[][] audioLevels)
{
// TODO Auto-generated method stub
}
/**

Loading…
Cancel
Save