Adds local user sound level indicators and their implementation. Change Players to be Processors in neomedia service impl, in order to have control on codec chain and to add there the sound level indicators.

cusax-fix
Damian Minkov 16 years ago
parent 1c680929a8
commit 82f658f998

@ -19,6 +19,7 @@
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.keybindings.*;
import net.java.sip.communicator.service.metahistory.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.notification.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.resources.*;
@ -66,6 +67,8 @@ public class GuiActivator implements BundleActivator
private static DesktopService desktopService;
private static MediaService mediaService;
private static final Map<Object, ProtocolProviderFactory>
providerFactoriesMap = new Hashtable<Object, ProtocolProviderFactory>();
@ -453,6 +456,25 @@ public static DesktopService getDesktopService()
return desktopService;
}
/**
* Returns the <tt>MediaService</tt> obtained from the bundle context.
*
* @return the <tt>MediaService</tt> obtained from the bundle context
*/
public static MediaService getMediaService()
{
if (mediaService == null)
{
ServiceReference serviceReference = bundleContext
.getServiceReference(MediaService.class.getName());
mediaService = (MediaService) bundleContext
.getService(serviceReference);
}
return mediaService;
}
/**
* Implements the <tt>ServiceListener</tt>. Verifies whether the
* passed event concerns a <tt>NotificationService</tt> and if so

@ -11,8 +11,8 @@
import javax.swing.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.main.call.*;
import net.java.sip.communicator.impl.gui.main.call.CallPeerAdapter;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.swing.*;
@ -129,7 +129,8 @@ private void addLocalCallPeer()
.getOperationSet(OperationSetBasicTelephony.class);
if (telephonyOpSet != null)
telephonyOpSet.addLocalUserSoundLevelListener(localPeerPanel);
GuiActivator.getMediaService().
addLocalUserSoundLevelListener(localPeerPanel);
}
/**

@ -18,6 +18,7 @@
import net.java.sip.communicator.impl.gui.utils.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.service.neomedia.event.*;
import net.java.sip.communicator.util.swing.*;
/**

@ -23,6 +23,8 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.keybindings,
net.java.sip.communicator.service.metahistory,
net.java.sip.communicator.service.msghistory,
net.java.sip.communicator.service.neomedia,
net.java.sip.communicator.service.neomedia.event,
net.java.sip.communicator.service.notification,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.event,

@ -109,6 +109,20 @@ public void addSoundLevelListener(SoundLevelListener listener)
// TODO Auto-generated method stub
}
/**
* Adds <tt>listener</tt> to the list of <tt>SoundLevelListener</tt>s
* registered to receive notifications for changes in the levels of
* conference participants that the remote party could be mixing.
*
* @param listener the <tt>SoundLevelListener</tt> that we'd like to
* register.
*/
public void addConferenceMemberSoundLevelListener(
SoundLevelListener listener)
{
}
/**
* Registers {@link #CUSTOM_CODEC_FORMATS} with a specific
* <tt>RTPManager</tt>.
@ -180,6 +194,19 @@ public void removeSoundLevelListener(SoundLevelListener listener)
// TODO Auto-generated method stub
}
/**
* Removes <tt>listener</tt> from the list of <tt>SoundLevelListener</tt>s
* registered to receive notification events upon changes of the sound
* level.
*
* @param listener the listener that we'd like to unregister.
*/
public void removeConferenceMemberSoundLevelListener(
SoundLevelListener listener)
{
}
/**
* Starts sending the specified <tt>DTMFTone</tt> until the
* <tt>stopSendingDTMF()</tt> method is called. Callers should keep in mind

@ -15,6 +15,7 @@
import net.java.sip.communicator.impl.neomedia.format.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.neomedia.device.*;
import net.java.sip.communicator.service.neomedia.event.*;
import net.java.sip.communicator.service.neomedia.format.*;
/**
@ -91,6 +92,12 @@ public class MediaServiceImpl
private final List<MediaDeviceImpl> videoDevices
= new ArrayList<MediaDeviceImpl>();
/**
* A list of listeners registered for local user sound level events.
*/
private final List<LocalUserSoundLevelListener> soundLevelListeners
= new Vector<LocalUserSoundLevelListener>();
/**
* Creates a new <tt>MediaStream</tt> instance which will use the specified
* <tt>MediaDevice</tt> for both capture and playback of media exchanged
@ -428,4 +435,66 @@ void start()
void stop()
{
}
/**
* Adds the given <tt>LocalUserSoundLevelListener</tt> to this operation set.
* @param l the <tt>LocalUserSoundLevelListener</tt> to add
*/
public void addLocalUserSoundLevelListener(LocalUserSoundLevelListener l)
{
synchronized(soundLevelListeners)
{
if (!soundLevelListeners.contains(l))
soundLevelListeners.add(l);
}
}
/**
* Removes the given <tt>LocalUserSoundLevelListener</tt> from this
* operation set.
* @param l the <tt>LocalUserSoundLevelListener</tt> to remove
*/
public void removeLocalUserSoundLevelListener(LocalUserSoundLevelListener l)
{
synchronized(soundLevelListeners)
{
soundLevelListeners.remove(l);
}
}
/**
* Creates and dispatches a <tt>LocalUserSoundLevelEvent</tt> notifying
* registered listeners that the local user sound level has changed.
*
* @param level the new level
*/
public void fireLocalUserSoundLevelEvent(int level)
{
LocalUserSoundLevelEvent soundLevelEvent
= new LocalUserSoundLevelEvent(this, level);
List<LocalUserSoundLevelListener> listeners;
synchronized (soundLevelListeners)
{
listeners =
new ArrayList<LocalUserSoundLevelListener>(soundLevelListeners);
}
for (Iterator<LocalUserSoundLevelListener> listenerIter
= listeners.iterator(); listenerIter.hasNext();)
{
LocalUserSoundLevelListener listener = listenerIter.next();
listener.localUserSoundLevelChanged(soundLevelEvent);
}
}
/**
* All the local sound level listeners.
* @return the soundLevelListeners interested in local sound level changes.
*/
public List<LocalUserSoundLevelListener> getLocalSoundLevelListeners()
{
return soundLevelListeners;
}
}

@ -0,0 +1,282 @@
/*
* 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.codec.audio;
import javax.media.*;
import javax.media.format.*;
/**
* An effect that calculates the power of the signal and fire an event
* with the current level.
*
* @author Damian Minkov
*/
public class SoundLevelIndicatorEffect
implements Effect
{
private Format[] supportedAudioFormats;
/**
* Input Format
*/
private AudioFormat inputFormat;
/**
* Output Format
*/
private AudioFormat outputFormat;
private double levelRatio;
private static int MAX_SOUND_LEVEL = Short.MAX_VALUE;
private static int MIN_SOUND_LEVEL = Short.MIN_VALUE;
private int lastLevel = 0;
private SoundLevelIndicatorListener listener = null;
/**
* The minimum and maximum values of the scale
* @param minLevel min level.
* @param maxLevel max lavel.
* @param listener the listener of the sound level changes.
*/
public SoundLevelIndicatorEffect(int minLevel, int maxLevel,
SoundLevelIndicatorListener listener)
{
this.listener = listener;
levelRatio = MAX_SOUND_LEVEL/(maxLevel - minLevel);
supportedAudioFormats = new Format[]{
new AudioFormat(
AudioFormat.LINEAR,
Format.NOT_SPECIFIED,
16,
1,
AudioFormat.LITTLE_ENDIAN,
AudioFormat.SIGNED,
16,
Format.NOT_SPECIFIED,
Format.byteArray)
};
}
/**
* Lists all of the input formats that this codec accepts.
* @return An array that contains the supported input <code>Formats</code>.
*/
public Format[] getSupportedInputFormats()
{
return supportedAudioFormats;
}
/**
* Lists the output formats that this codec can generate.
* @param input The <code>Format</code> of the data to be used
* as input to the plug-in.
* @return An array that contains the supported output <code>Formats</code>.
*/
public Format[] getSupportedOutputFormats(Format input)
{
return supportedAudioFormats;
}
/**
* Sets the format of the data to be input to this codec.
* @param format The <code>Format</code> to be set.
* @return The <code>Format</code> that was set.
*/
public Format setInputFormat(Format format)
{
this.inputFormat = (AudioFormat)format;
return inputFormat;
}
/**
* Sets the format for the data this codec outputs.
* @param format The <code>Format</code> to be set.
* @return The <code>Format</code> that was set.
*/
public Format setOutputFormat(Format format)
{
this.outputFormat = (AudioFormat)format;
return outputFormat;
}
/**
* Performs the media processing defined by this codec.
* @param inputBuffer The <code>Buffer</code> that contains the media data
* to be processed.
* @param outputBuffer The <code>Buffer</code> in which to store
* the processed media data.
* @return <CODE>BUFFER_PROCESSED_OK</CODE> if the processing is successful.
* @see PlugIn
*/
public int process(Buffer inputBuffer, Buffer outputBuffer)
{
byte[] b = new byte[inputBuffer.getLength()];
System.arraycopy(inputBuffer.getData(), inputBuffer.getOffset(), b, 0, b.length);
outputBuffer.setData(b);
outputBuffer.setData(b);
outputBuffer.setFormat(inputBuffer.getFormat());
outputBuffer.setLength(inputBuffer.getLength());
outputBuffer.setOffset(inputBuffer.getOffset());
outputBuffer.setHeader(inputBuffer.getHeader());
outputBuffer.setSequenceNumber(inputBuffer.getSequenceNumber());
outputBuffer.setTimeStamp(inputBuffer.getTimeStamp());
outputBuffer.setFlags(inputBuffer.getFlags());
outputBuffer.setDiscard(inputBuffer.isDiscard());
outputBuffer.setEOM(inputBuffer.isEOM());
outputBuffer.setDuration(inputBuffer.getDuration());
int newLevel = calculateCurrentSignalPower(
b, 0, b.length, levelRatio);
if(newLevel != lastLevel)
listener.soundLevelChanged(newLevel);
lastLevel = newLevel;
return BUFFER_PROCESSED_OK;
}
/**
* Estimates the signal power and use the levelRatio to
* scale it to the needed levels.
* @param buff the buffer with the data.
* @param offset the offset that data starts.
* @param len the length of the data
* @param levelRatio the ratio for scaling to the needed levels
* @return the power of the signal in dB SWL.
*/
public static int calculateCurrentSignalPower(
byte[] buff, int offset, int len, double levelRatio)
{
if(len == 0)
return 0;
int samplesNumber = len/2;
int absoluteMeanSoundLevel = 0;
// Do the processing
for (int i = 0; i < samplesNumber; i++)
{
int tempL = buff[offset++];
int tempH = buff[offset++];
int soundLevel = tempH << 8 | (tempL & 255);
if (soundLevel > MAX_SOUND_LEVEL)
{
soundLevel = MAX_SOUND_LEVEL;
} else if (soundLevel < MIN_SOUND_LEVEL) {
soundLevel = MIN_SOUND_LEVEL;
}
absoluteMeanSoundLevel += Math.abs(soundLevel);
}
return (int)(absoluteMeanSoundLevel/samplesNumber/levelRatio);
}
/**
* Gets the name of this plug-in as a human-readable string.
* @return A <code>String</code> that contains the descriptive name of the
* plug-in.
*/
public String getName()
{
return "SoundLevelIndicator Effect";
}
/**
* Opens this effect.
* @throws ResourceUnavailableException If all of the required resources
* cannot be acquired.
*/
public void open()
throws ResourceUnavailableException
{
}
/**
* Closes this effect.
*/
public void close()
{
}
/**
* Restes its state.
*/
public void reset()
{
}
/**
* Obtain the collection of objects that
* control the object that implements this interface.
* <p>
*
* If no controls are supported, a zero length
* array is returned.
*
* @return the collection of object controls
*/
public Object[] getControls()
{
return new Control[0];
}
/**
* Obtain the object that implements the specified
* <code>Class</code> or <code>Interface</code>
* The full class or interface name must be used.
* <p>
*
* If the control is not supported then <code>null</code>
* is returned.
*
* @param controlType the control type to return.
* @return the object that implements the control,
* or <code>null</code>.
*/
public Object getControl(String controlType)
{
try
{
Class<?> cls = Class.forName(controlType);
Object cs[] = getControls();
for(int i = 0; i < cs.length; i++)
{
if(cls.isInstance(cs[i]))
{
return cs[i];
}
}
return null;
}
catch (Exception e)
{
return null;
}
}
/**
* Lister for the changes in the sound level.
*/
public static interface SoundLevelIndicatorListener
{
/**
* Called when the sound level is changing.
* @param level the new level.
*/
public void soundLevelChanged(int level);
}
}

@ -17,9 +17,11 @@
import javax.media.rtp.*;
import net.java.sip.communicator.impl.neomedia.*;
import net.java.sip.communicator.impl.neomedia.codec.audio.*;
import net.java.sip.communicator.impl.neomedia.format.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.neomedia.device.*;
import net.java.sip.communicator.service.neomedia.event.*;
import net.java.sip.communicator.service.neomedia.format.*;
import net.java.sip.communicator.util.*;
@ -86,15 +88,15 @@ public class MediaDeviceSession
private ControllerListener playerControllerListener;
/**
* The <tt>Player</tt>s rendering <tt>ReceiveStream</tt>s on the
* The <tt>Processor</tt>s rendering <tt>ReceiveStream</tt>s on the
* <tt>MediaDevice</tt> represented by this instance. Associated with
* <tt>DataSource</tt> because different <tt>ReceiveStream</tt>s may be
* added with one and the same <tt>DataSource</tt> so it has to be clear
* when a new <tt>Player</tt> is to be created and when it is to be
* disposed.
* when a new <tt>Processor</tt> is to be created and when it is to be
* disposed. The <tt>Processor</tt> is used as a Player.
*/
private final Map<DataSource, Player> players
= new HashMap<DataSource, Player>();
private final Map<DataSource, Processor> players
= new HashMap<DataSource, Processor>();
/**
* The JMF <tt>Processor</tt> which transcodes {@link #captureDevice} into
@ -200,7 +202,7 @@ protected void addReceiveStream(
synchronized (players)
{
Player player = players.get(receiveStreamDataSource);
Processor player = players.get(receiveStreamDataSource);
if (player == null)
{
@ -208,7 +210,7 @@ protected void addReceiveStream(
try
{
player = Manager.createPlayer(receiveStreamDataSource);
player = Manager.createProcessor(receiveStreamDataSource);
}
catch (IOException ioe)
{
@ -227,29 +229,39 @@ protected void addReceiveStream(
exception);
else
{
if (playerControllerListener == null)
playerControllerListener = new ControllerListener()
{
/**
* Notifies this <tt>ControllerListener</tt> that
* the <tt>Controller</tt> which it is registered
* with has generated an event.
*
* @param event the <tt>ControllerEvent</tt>
* specifying the <tt>Controller</tt> which is the
* source of the event and the very type of the
* event
* @see ControllerListener#controllerUpdate(
* ControllerEvent)
*/
public void controllerUpdate(ControllerEvent event)
{
playerControllerUpdate(event);
}
};
player.addControllerListener(playerControllerListener);
player.realize();
waitForState(player, Processor.Configured);
// // here we add sound level indicator for every incoming
// //stream
// try
// {
// TrackControl tc[] = player.getTrackControls();
// if (tc != null)
// {
// for (int i = 0; i < tc.length; i++)
// {
// if (tc[i].getFormat() instanceof AudioFormat)
// {
// // Assume there is only one audio track
// tc[i].setCodecChain(new Codec[]{
// new SoundLevelIndicatorEffect()});
// break;
// }
// }
// }
// }
// catch (UnsupportedPlugInException ex)
// {
// logger.error("The processor does not support effects", ex);
// }
// to use the processor as player we must se its
// content descriptor to null
player.setContentDescriptor(null);
waitForState(player, Processor.Realized);
player.start();
realizeComplete(player);
if (logger.isTraceEnabled())
logger
@ -421,16 +433,17 @@ private void disconnectCaptureDevice()
}
/**
* Releases the resources allocated by a specific <tt>Player</tt> in the
* Releases the resources allocated by a specific <tt>Processor</tt> in the
* course of its execution and prepares it to be garbage collected.
* The <tt>Processor</tt> is used as a <tt>Player</tt>.
*
* @param player the <tt>Player</tt> to dispose of
* @param player the <tt>Processor</tt> to dispose of
*/
protected void disposePlayer(Player player)
protected void disposePlayer(Processor player)
{
synchronized (players)
{
Iterator<Map.Entry<DataSource, Player>> playerIter
Iterator<Map.Entry<DataSource, Processor>> playerIter
= players.entrySet().iterator();
while (playerIter.hasNext())
@ -456,7 +469,7 @@ private void disposePlayers()
{
synchronized (players)
{
for (Player player : getPlayers())
for (Processor player : getPlayers())
disposePlayer(player);
}
}
@ -638,20 +651,21 @@ public DataSource getOutputDataSource()
}
/**
* Gets the <tt>Player</tt>s rendering <tt>ReceiveStream</tt>s for this
* Gets the <tt>Processors</tt>s rendering <tt>ReceiveStream</tt>s for this
* instance on its associated <tt>MediaDevice</tt>. The returned
* <tt>List</tt> is a copy of the internal storage and, consequently,
* modifications to it do not affect this instance.
* The <tt>Processor</tt>s are used as a <tt>Player</tt>s.
*
* @return a new <tt>List</tt> of <tt>Player</tt>s rendering
* @return a new <tt>List</tt> of <tt>Processor</tt>s rendering
* <tt>ReceiveStream</tt>s for this instance on its associated
* <tt>MediaDevice</tt>
*/
protected List<Player> getPlayers()
protected List<Processor> getPlayers()
{
synchronized (players)
{
return new ArrayList<Player>(players.values());
return new ArrayList<Processor>(players.values());
}
}
@ -784,35 +798,6 @@ public List<MediaFormat> getSupportedFormats()
return supportedMediaFormats;
}
/**
* Gets notified about <tt>ControllerEvent</tt>s generated by the
* <tt>Player</tt> instances in {@link #players}.
*
* @param event the <tt>ControllerEvent</tt> specifying the
* <tt>Controller</tt> which is the source of the event and the very type of
* the event
*/
private void playerControllerUpdate(ControllerEvent event)
{
if (event instanceof RealizeCompleteEvent)
{
Player player = (Player) event.getSourceController();
if (player != null)
{
if (logger.isTraceEnabled())
logger
.trace(
"Realized Player with hashCode "
+ player.hashCode());
player.start();
realizeComplete(player);
}
}
}
/**
* Gets notified about <tt>ControllerEvent</tt>s generated by
* {@link #processor}.
@ -846,6 +831,33 @@ private void processorControllerUpdate(ControllerEvent event)
if (format != null)
setFormat(processor, format);
if(NeomediaActivator.getMediaServiceImpl()
.getLocalSoundLevelListeners().size() > 0)
{
// here we add sound level indicator for captured media
// from the microphone if there are interested listeners
try
{
TrackControl tc[] = processor.getTrackControls();
if (tc != null)
{
for (int i = 0; i < tc.length; i++)
{
if (tc[i].getFormat() instanceof AudioFormat)
{
addSpundLevelIndicator(tc[i]);
break;
}
}
}
}
catch (UnsupportedPlugInException ex)
{
logger.error(
"Unsupported sound level indicator effect", ex);
}
}
}
}
else if (event instanceof ControllerClosedEvent)
@ -865,14 +877,40 @@ else if (event instanceof ControllerClosedEvent)
}
/**
* Notifies this instance that a specific <tt>Player</tt> of remote content
* has generated a <tt>RealizeCompleteEvent</tt>. Allows extenders to carry
* out additional processing on the <tt>Player</tt>.
* Creates sound level indicator effect and add it to the
* codec chain of the <tt>TrackControl</tt> and
* assumes there is only one audio track.
* @param tc the track control.
* @throws UnsupportedPlugInException
*/
private void addSpundLevelIndicator(TrackControl tc)
throws UnsupportedPlugInException
{
SoundLevelIndicatorEffect slie = new SoundLevelIndicatorEffect(
LocalUserSoundLevelEvent.MIN_LEVEL,
LocalUserSoundLevelEvent.MAX_LEVEL,
new SoundLevelIndicatorEffect.SoundLevelIndicatorListener()
{
public void soundLevelChanged(int level)
{
NeomediaActivator.getMediaServiceImpl()
.fireLocalUserSoundLevelEvent(level);
}
});
// Assume there is only one audio track
tc.setCodecChain(new Codec[]{slie});
}
/**
* Notifies this instance that a specific <tt>Processor</tt> of
* remote content has generated a <tt>RealizeCompleteEvent</tt>.
* Allows extenders to carry out additional processing on the
* <tt>Processor</tt>. The <tt>Processor</tt> is used as a <tt>Player</tt>.
*
* @param player the <tt>Player</tt> which is the source of a
* @param player the <tt>Processor</tt> which is the source of a
* <tt>RealizeCompleteEvent</tt>
*/
protected void realizeComplete(Player player)
protected void realizeComplete(Processor player)
{
}
@ -893,7 +931,7 @@ public void removeReceiveStream(ReceiveStream receiveStream)
&& !receiveStreams.containsValue(receiveStreamDataSource))
synchronized (players)
{
Player player = players.get(receiveStreamDataSource);
Processor player = players.get(receiveStreamDataSource);
if (player != null)
disposePlayer(player);

@ -86,18 +86,19 @@ protected void checkDevice(AbstractMediaDevice device)
}
/**
* Releases the resources allocated by a specific <tt>Player</tt> in the
* Releases the resources allocated by a specific <tt>Processor</tt> in the
* course of its execution and prepares it to be garbage collected. If the
* specified <tt>Player</tt> is rendering video, notifies the
* specified <tt>Processor</tt> is rendering video, notifies the
* <tt>VideoListener</tt>s of this instance that its visual
* <tt>Component</tt> is to no longer be used by firing a
* {@link VideoEvent#VIDEO_REMOVED} <tt>VideoEvent</tt>.
*
* @param player the <tt>Player</tt> to dispose of
* @param player the <tt>Processor</tt> to dispose of,
* the processor is used as Player.
* @see MediaDeviceSession#disposePlayer(Player)
*/
@Override
protected void disposePlayer(Player player)
protected void disposePlayer(Processor player)
{
/*
@ -159,7 +160,7 @@ protected boolean fireVideoEvent(
*/
public Component getVisualComponent()
{
for (Player player : getPlayers())
for (Processor player : getPlayers())
{
Component visualComponent = getVisualComponent(player);
@ -170,17 +171,19 @@ public Component getVisualComponent()
}
/**
* Gets the visual <tt>Component</tt> of a specific <tt>Player</tt> if it
* Gets the visual <tt>Component</tt> of a specific <tt>Processor</tt> if it
* has one and ignores the failure to access it if the specified
* <tt>Player</tt> is unrealized.
* <tt>Processor</tt> is unrealized.
* The <tt>Processor</tt> is used as Player.
*
* @param player the <tt>Player</tt> to get the visual <tt>Component</tt> of
* if it has one
* @return the visual <tt>Component</tt> of the specified <tt>Player</tt> if
* it has one; <tt>null</tt> if the specified <tt>Player</tt> does not have
* a visual <tt>Component</tt> or the <tt>Player</tt> is unrealized
* it has one; <tt>null</tt> if the specified <tt>Processor</tt>
* does not have a visual <tt>Component</tt> or
* the <tt>Processor</tt> is unrealized.
*/
private static Component getVisualComponent(Player player)
private static Component getVisualComponent(Processor player)
{
Component visualComponent;
@ -204,15 +207,16 @@ private static Component getVisualComponent(Player player)
}
/**
* Notifies this instance that a specific <tt>Player</tt> of remote content
* has generated a <tt>RealizeCompleteEvent</tt>.
* Notifies this instance that a specific <tt>Processor</tt> of remote
* content has generated a <tt>RealizeCompleteEvent</tt>.
* The <tt>Processor</tt> is used as Player.
*
* @param player the <tt>Player</tt> which is the source of a
* <tt>RealizeCompleteEvent</tt>
* @param player the <tt>Processor</tt> which is the source of a
* <tt>RealizeCompleteEvent</tt>.
* @see MediaDeviceSession#realizeComplete(Player)
*/
@Override
protected void realizeComplete(Player player)
protected void realizeComplete(Processor player)
{
super.realizeComplete(player);

@ -82,19 +82,6 @@ public Call createConfCall(String[] callees)
telephonyOpSet.fireCallEvent(CallEvent.CALL_INITIATED, newCall);
final Random random = new Random();
Timer timer1 = new Timer(false);
timer1.scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
telephonyOpSet.fireLocalUserSoundLevelEvent(
protocolProvider,
random.nextInt(255));
}
}, 500, 100);
return newCall;
}

@ -20,7 +20,7 @@ public interface AudioMediaStream
/**
* Adds <tt>listener</tt> to the list of <tt>SoundLevelListener</tt>s
* registered to receive notifications for changes in the levels of
* conference participants that the remote party could be mixing.
* remote participant.
*
* @param listener the <tt>SoundLevelListener</tt> that we'd like to
* register.
@ -36,6 +36,27 @@ public interface AudioMediaStream
*/
public void removeSoundLevelListener(SoundLevelListener listener);
/**
* Adds <tt>listener</tt> to the list of <tt>SoundLevelListener</tt>s
* registered to receive notifications for changes in the levels of
* conference participants that the remote party could be mixing.
*
* @param listener the <tt>SoundLevelListener</tt> that we'd like to
* register.
*/
public void addConferenceMemberSoundLevelListener(
SoundLevelListener listener);
/**
* Removes <tt>listener</tt> from the list of <tt>SoundLevelListener</tt>s
* registered to receive notification events upon changes of the sound
* level.
*
* @param listener the listener that we'd like to unregister.
*/
public void removeConferenceMemberSoundLevelListener(
SoundLevelListener listener);
/**
* Starts sending the specified <tt>DTMFTone</tt> until the
* <tt>stopSendingDTMF()</tt> method is called. Callers should keep in mind

@ -9,6 +9,7 @@
import java.util.*;
import net.java.sip.communicator.service.neomedia.device.*;
import net.java.sip.communicator.service.neomedia.event.*;
import net.java.sip.communicator.service.neomedia.format.*;
/**
@ -87,4 +88,17 @@ public MediaStream createMediaStream(StreamConnector connector,
* with the <tt>MediaStream</tt>s created by this <tt>MediaService</tt>
*/
public MediaFormatFactory getFormatFactory();
/**
* Adds the given <tt>LocalUserSoundLevelListener</tt> to this operation set.
* @param l the <tt>LocalUserSoundLevelListener</tt> to add
*/
public void addLocalUserSoundLevelListener(LocalUserSoundLevelListener l);
/**
* Removes the given <tt>LocalUserSoundLevelListener</tt> from this
* operation set.
* @param l the <tt>LocalUserSoundLevelListener</tt> to remove
*/
public void removeLocalUserSoundLevelListener(LocalUserSoundLevelListener l);
}

@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.protocol.event;
package net.java.sip.communicator.service.neomedia.event;
import java.util.*;
@ -38,15 +38,13 @@ public class LocalUserSoundLevelEvent
/**
* Creates an <tt>StreamSoundLevelEvent</tt> for the given <tt>callPeer</tt>
* by indicating the current sound level of the audio stream.
*
* @param protocolProvider the <tt>ProtocolProviderService</tt>
*
* @param source the source of the new <tt>LocalUserSoundLevelEvent</tt>.
* @param level the current sound level of the audio stream
*/
public LocalUserSoundLevelEvent(
ProtocolProviderService protocolProvider, int level)
public LocalUserSoundLevelEvent(Object source, int level)
{
super(protocolProvider);
super(source);
this.level = level;
}

@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.protocol.event;
package net.java.sip.communicator.service.neomedia.event;
/**
* Notifies interested parties in sound level changes of the local user audio

@ -32,12 +32,6 @@ public abstract class AbstractOperationSetBasicTelephony
*/
private final List<CallListener> callListeners = new Vector<CallListener>();
/**
* A list of listeners registered for local user sound level events.
*/
private final List<LocalUserSoundLevelListener> soundLevelListeners
= new Vector<LocalUserSoundLevelListener>();
/**
* Registers <tt>listener</tt> with this provider so that it
* could be notified when incoming calls are received.
@ -127,63 +121,4 @@ public void setMute(CallPeer peer, boolean mute)
* this implementation takes inspiration from them.
*/
}
/**
* Adds the given <tt>LocalUserSoundLevelListener</tt> to this operation set.
* @param l the <tt>LocalUserSoundLevelListener</tt> to add
*/
public void addLocalUserSoundLevelListener(LocalUserSoundLevelListener l)
{
synchronized(soundLevelListeners)
{
if (!soundLevelListeners.contains(l))
soundLevelListeners.add(l);
}
}
/**
* Removes the given <tt>LocalUserSoundLevelListener</tt> from this
* operation set.
* @param l the <tt>LocalUserSoundLevelListener</tt> to remove
*/
public void removeLocalUserSoundLevelListener(LocalUserSoundLevelListener l)
{
synchronized(soundLevelListeners)
{
soundLevelListeners.remove(l);
}
}
/**
* Creates and dispatches a <tt>LocalUserSoundLevelEvent</tt> notifying
* registered listeners that the local user sound level has changed.
*
* @param protocolProvider the protocol provider for which the level is
* @param level the new level
*/
public void fireLocalUserSoundLevelEvent(
ProtocolProviderService protocolProvider, int level)
{
LocalUserSoundLevelEvent soundLevelEvent
= new LocalUserSoundLevelEvent(protocolProvider, level);
List<LocalUserSoundLevelListener> listeners;
synchronized (soundLevelListeners)
{
listeners = new ArrayList<LocalUserSoundLevelListener>(
soundLevelListeners);
}
logger.debug("Dispatching a LocalUserSoundLevelEvent to "
+ listeners.size()
+ " listeners. event is: " + soundLevelEvent);
for (Iterator<LocalUserSoundLevelListener> listenerIter
= listeners.iterator(); listenerIter.hasNext();)
{
LocalUserSoundLevelListener listener = listenerIter.next();
listener.localUserSoundLevelChanged(soundLevelEvent);
}
}
}

@ -149,17 +149,4 @@ public void hangupCallPeer(CallPeer peer)
* <tt>peer</tt>; otherwise, <tt>false</tt>
*/
public void setMute(CallPeer peer, boolean mute);
/**
* Adds the given <tt>LocalUserSoundLevelListener</tt> to this operation set.
* @param l the <tt>LocalUserSoundLevelListener</tt> to add
*/
public void addLocalUserSoundLevelListener(LocalUserSoundLevelListener l);
/**
* Removes the given <tt>LocalUserSoundLevelListener</tt> from this
* operation set.
* @param l the <tt>LocalUserSoundLevelListener</tt> to remove
*/
public void removeLocalUserSoundLevelListener(LocalUserSoundLevelListener l);
}

Loading…
Cancel
Save