Moves code from call peer's sip implementation to a super class that would be shared with the jabber implementation

cusax-fix
Emil Ivov 16 years ago
parent 04cac3354c
commit 9bb144b9fa

@ -18,7 +18,7 @@
* @author Yana Stamcheva
*/
public class OperationSetBasicTelephonyGibberishImpl
extends AbstractOperationSetBasicTelephony
extends AbstractOperationSetBasicTelephony<ProtocolProviderServiceGibberishImpl>
implements CallChangeListener
{
private static final Logger logger
@ -271,4 +271,15 @@ else if (on)
gibberishPeer.setState(CallPeerState.ON_HOLD_LOCALLY);
}
}
/**
* Returns the protocol provider that this operation set belongs to.
*
* @return a reference to the <tt>ProtocolProviderService</tt> that created
* this operation set.
*/
public ProtocolProviderServiceGibberishImpl getProtocolProvider()
{
return protocolProvider;
}
}

@ -9,6 +9,7 @@
import org.jivesoftware.smack.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
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.*;

@ -0,0 +1,116 @@
/*
* 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.protocol.jabber;
import java.net.*;
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.netaddr.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.media.*;
/**
* @author Emil Ivov
*/
public class CallPeerMediaHandlerJabberImpl
extends CallPeerMediaHandler<CallPeerJabberImpl>
{
/**
* Creates a new handler that will be managing media streams for
* <tt>peer</tt>.
*
* @param peer that <tt>CallPeerSipImpl</tt> instance that we will be
* managing media for.
*/
public CallPeerMediaHandlerJabberImpl(CallPeerJabberImpl peer)
{
//TODO - callpeer jabber impl should implement otr listeenr
super(peer, null);
}
/**
* Should return a reference to the currently valid configuration service.
* We need this method in order to keep the protocol-media bundle as light
* as possible: we don't want it to have an activator and deal with a
* bundle context.
*
* @return a reference to the currently valid {@link ConfigurationService}
*/
@Override
protected ConfigurationService getConfigurationService()
{
return JabberActivator.getConfigurationService();
}
/**
* Returns a reference to the currently valid media service.
*
* @return a reference to the currently valid {@link MediaService}
*/
@Override
protected MediaService getMediaService()
{
return JabberActivator.getMediaService();
}
/**
* Returns a reference to the currently valid network address service.
*
* @return a reference to the currently valid {@link
* NetworkAddressManagerService}
*/
@Override
protected NetworkAddressManagerService getNetworkAddressManagerService()
{
return JabberActivator.getNetworkAddressManagerService();
}
/**
* Lets the underlying implementation take note of this error and only
* then throws it to the using bundles.
*
* @param message the message to be logged and then wrapped in a new
* <tt>OperationFailedException</tt>
* @param errorCode the error code to be assigned to the new
* <tt>OperationFailedException</tt>
* @param cause the <tt>Throwable</tt> that has caused the necessity to log
* an error and have a new <tt>OperationFailedException</tt> thrown
*
* @throws OperationFailedException the exception that we wanted this method
* to throw.
*/
@Override
protected void throwOperationFailedException(String message, int errorCode,
Throwable cause) throws OperationFailedException
{
// TODO Auto-generated method stub - implement
}
/**
* Returns the <tt>InetAddress</tt> that is most likely to be to be used
* as a next hop when contacting the specified <tt>destination</tt>. This is
* an utility method that is used whenever we have to choose one of our
* local addresses to put in the Via, Contact or (in the case of no
* registrar accounts) From headers.
*
* @param peer the CallPeer that we would contact.
*
* @return the <tt>InetAddress</tt> that is most likely to be to be used
* as a next hop when contacting the specified <tt>destination</tt>.
*
* @throws IllegalArgumentException if <tt>destination</tt> is not a valid
* host/ip/fqdn
*/
@Override
protected InetAddress getIntendedDestination(CallPeerJabberImpl peer)
{
/* TODO implement */
return null;
}
}

@ -11,6 +11,7 @@
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.netaddr.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.resources.*;
@ -47,6 +48,12 @@ public class JabberActivator
*/
private static MediaService mediaService = null;
/**
* A reference to the currently valid {@link NetworkAddressManagerService}.
*/
private static NetworkAddressManagerService
networkAddressManagerService = null;
/**
* The Jabber protocol provider factory.
*/
@ -246,4 +253,25 @@ public static MediaService getMediaService()
}
return mediaService;
}
/**
* Returns a reference to a NetworkAddressManagerService implementation
* currently registered in the bundle context or null if no such
* implementation was found.
*
* @return a currently valid implementation of the
* NetworkAddressManagerService .
*/
public static NetworkAddressManagerService getNetworkAddressManagerService()
{
if(networkAddressManagerService == null)
{
ServiceReference confReference
= bundleContext.getServiceReference(
NetworkAddressManagerService.class.getName());
networkAddressManagerService = (NetworkAddressManagerService)
bundleContext.getService(confReference);
}
return networkAddressManagerService;
}
}

@ -450,11 +450,11 @@ else if(action == JingleAction.SESSION_ACCEPT)
}
/**
* Returns a reference to the {@link ActiveCallsRepositoryJabberImpl} that we are
* currently using.
* Returns a reference to the {@link ActiveCallsRepositoryJabberImpl} that
* we are currently using.
*
* @return a reference to the {@link ActiveCallsRepositoryJabberImpl} that we are
* currently using.
* @return a reference to the {@link ActiveCallsRepositoryJabberImpl} that
* we are currently using.
*/
protected ActiveCallsRepositoryJabberImpl getActiveCallsRepository()
{

@ -19,7 +19,7 @@
* @author Damian Minkov
*/
public class MockOperationSetBasicTelephony
extends AbstractOperationSetBasicTelephony
extends AbstractOperationSetBasicTelephony<MockProvider>
implements CallChangeListener
{
private static final Logger logger
@ -240,4 +240,15 @@ public void callStateChanged(CallChangeEvent evt)
fireCallEvent(CallEvent.CALL_ENDED, sourceCall);
}
}
/**
* Returns the protocol provider that this operation set belongs to.
*
* @return a reference to the <tt>ProtocolProviderService</tt> that created
* this operation set.
*/
public MockProvider getProtocolProvider()
{
return protocolProvider;
}
}

@ -18,6 +18,7 @@
import net.java.sip.communicator.service.neomedia.event.SimpleAudioLevelListener;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.service.protocol.media.*;
import net.java.sip.communicator.util.*;
/**
@ -26,7 +27,9 @@
* @author Emil Ivov
*/
public class CallSipImpl
extends AbstractCall<CallPeerSipImpl, ProtocolProviderServiceSipImpl>
extends AbstractMediaAwareCall<CallPeerSipImpl,
OperationSetBasicTelephonySipImpl,
ProtocolProviderServiceSipImpl>
implements CallPeerListener
{
/**
@ -34,71 +37,12 @@ public class CallSipImpl
*/
private static final Logger logger = Logger.getLogger(CallSipImpl.class);
/**
* The <tt>MediaDevice</tt> which performs audio mixing for this
* <tt>Call</tt> and its <tt>CallPeer</tt>s when the local peer represented
* by this <tt>Call</tt> is acting as a conference focus i.e.
* {@link #conferenceFocus} is <tt>true</tt>.
*/
private MediaDevice conferenceAudioMixer;
/**
* The indicator which determines whether the local peer represented by this
* <tt>Call</tt> is acting as a conference focus and is thus specifying the
* &quot;isfocus&quot; parameter in the Contact headers of its outgoing SIP
* signaling.
*/
private boolean conferenceFocus = false;
/**
* Our video streaming policy.
*/
private boolean localVideoAllowed = false;
/**
* A reference to the <tt>SipMessageFactory</tt> instance that we should
* use when creating requests.
*/
private final SipMessageFactory messageFactory;
/**
* A reference to the <tt>OperationSetBasicTelephonySipImpl</tt> that
* created us;
*/
private final OperationSetBasicTelephonySipImpl parentOpSet;
/**
* Holds listeners registered for level changes in local audio.
*/
private final List<SoundLevelListener> localUserAudioLevelListeners
= new ArrayList<SoundLevelListener>();
/**
* The indicator which determines whether this <tt>Call</tt> is set
* to transmit "silence" instead of the actual media.
*/
private boolean mute = false;
/**
* Device used in call will be choosen according to <tt>MediaUseCase</tt>.
*/
MediaUseCase mediaUseCase = MediaUseCase.ANY;
/**
* The listener that would actually subscribe for level events from the
* media handler if there's at least one listener in
* <tt>localUserAudioLevelListeners</tt>.
*/
private final SimpleAudioLevelListener localAudioLevelDelegator
= new SimpleAudioLevelListener()
{
public void audioLevelChanged(int level)
{
fireLocalUserAudioLevelChangeEvent(level);
}
};
/**
* Crates a CallSipImpl instance belonging to <tt>sourceProvider</tt> and
* initiated by <tt>CallCreator</tt>.
@ -108,154 +52,15 @@ public void audioLevelChanged(int level)
*/
protected CallSipImpl(OperationSetBasicTelephonySipImpl parentOpSet)
{
super(parentOpSet.getProtocolProvider());
super(parentOpSet);
this.messageFactory = getProtocolProvider().getMessageFactory();
this.parentOpSet = parentOpSet;
//let's add ourselves to the calls repo. we are doing it ourselves just
//to make sure that no one ever forgets.
parentOpSet.getActiveCallsRepository().addCall(this);
}
/**
* Adds <tt>callPeer</tt> to the list of peers in this call.
* If the call peer is already included in the call, the method has
* no effect.
*
* @param callPeer the new <tt>CallPeer</tt>
*/
private void addCallPeer(CallPeerSipImpl callPeer)
{
if (getCallPeersVector().contains(callPeer))
return;
callPeer.addCallPeerListener(this);
synchronized(localUserAudioLevelListeners)
{
// if there's someone listening for audio level events then they'd
// also like to know about the new peer.
if(getCallPeersVector().size() == 0)
{
callPeer.getMediaHandler().setLocalUserAudioLevelListener(
localAudioLevelDelegator);
}
}
getCallPeersVector().add(callPeer);
fireCallPeerEvent(callPeer, CallPeerEvent.CALL_PEER_ADDED);
}
/**
* Removes <tt>callPeer</tt> from the list of peers in this
* call. The method has no effect if there was no such peer in the
* call.
*
* @param callPeer the <tt>CallPeer</tt> leaving the call;
*/
private void removeCallPeer(CallPeerSipImpl callPeer)
{
if (!getCallPeersVector().contains(callPeer))
return;
getCallPeersVector().remove(callPeer);
callPeer.removeCallPeerListener(this);
synchronized(localUserAudioLevelListeners)
{
// remove sound level listeners from the peer
callPeer.getMediaHandler().setLocalUserAudioLevelListener(null);
}
try
{
fireCallPeerEvent(callPeer,
CallPeerEvent.CALL_PEER_REMOVED);
}
finally
{
/*
* The peer should loose its state once it has finished
* firing its events in order to allow the listeners to undo.
*/
callPeer.setCall(null);
}
if (getCallPeersVector().size() == 0)
setCallState(CallState.CALL_ENDED);
}
/**
* Dummy implementation of a method (inherited from CallPeerListener)
* that we don't need.
*
* @param evt unused.
*/
public void peerImageChanged(CallPeerChangeEvent evt)
{
//does not concern us
}
/**
* Dummy implementation of a method (inherited from CallPeerListener)
* that we don't need.
*
* @param evt unused.
*/
public void peerAddressChanged(CallPeerChangeEvent evt)
{
//does not concern us
}
/**
* Dummy implementation of a method (inherited from CallPeerListener)
* that we don't need.
*
* @param evt unused.
*/
public void peerTransportAddressChanged(
CallPeerChangeEvent evt)
{
//does not concern us
}
/**
* Dummy implementation of a method (inherited from CallPeerListener)
* that we don't need.
*
* @param evt unused.
*/
public void peerDisplayNameChanged(CallPeerChangeEvent evt)
{
//does not concern us
}
/**
* Verifies whether the call peer has entered a state.
*
* @param evt The <tt>CallPeerChangeEvent</tt> instance containing
* the source event as well as its previous and its new status.
*/
public void peerStateChanged(CallPeerChangeEvent evt)
{
CallPeerState newState = (CallPeerState) evt.getNewValue();
if (CallPeerState.DISCONNECTED.equals(newState)
|| CallPeerState.FAILED.equals(newState))
{
removeCallPeer((CallPeerSipImpl) evt.getSourceCallPeer());
}
else if (CallPeerState.CONNECTED.equals(newState)
|| CallPeerState.CONNECTING_WITH_EARLY_MEDIA.equals(newState))
{
setCallState(CallState.CALL_IN_PROGRESS);
}
else if (CallPeerState.REFERRED.equals(newState))
{
setCallState(CallState.CALL_REFERRED);
}
}
/**
* Returns <tt>true</tt> if <tt>dialog</tt> matches the jain sip dialog
@ -324,18 +129,6 @@ public ProtocolProviderServiceSipImpl getProtocolProvider()
return super.getProtocolProvider();
}
/**
* Returns a reference to the <tt>OperationSetBasicTelephonySipImpl</tt>
* instance that created this call.
*
* @return a reference to the <tt>OperationSetBasicTelephonySipImpl</tt>
* instance that created this call.
*/
public OperationSetBasicTelephonySipImpl getParentOperationSet()
{
return parentOpSet;
}
/**
* Creates a <tt>CallPeerSipImpl</tt> from <tt>calleeAddress</tt> and sends
* them an invite request. The invite request will be initialized according
@ -434,7 +227,7 @@ private CallPeerSipImpl createCallPeerFor(
// new and we also need to notify everyone of its creation.
if(this.getCallPeerCount() == 1)
{
parentOpSet.fireCallEvent( (incomingCall
getParentOperationSet().fireCallEvent( (incomingCall
? CallEvent.CALL_RECEIVED
: CallEvent.CALL_INITIATED),
this);
@ -638,204 +431,4 @@ public void removeVideoPropertyChangeListener(
peer.removeVideoPropertyChangeListener(listener);
}
}
/**
* Gets the indicator which determines whether the local peer represented by
* this <tt>Call</tt> is acting as a conference focus and thus should send
* the &quot;isfocus&quot; parameter in the Contact headers of its outgoing
* SIP signaling.
*
* @return <tt>true</tt> if the local peer represented by this <tt>Call</tt>
* is acting as a conference focus; otherwise, <tt>false</tt>
*/
public boolean isConferenceFocus()
{
return conferenceFocus;
}
/**
* Sets the indicator which determines whether the local peer represented by
* this <tt>Call</tt> is acting as a conference focus and thus should send
* the &quot;isfocus&quot; parameter in the Contact headers of its outgoing
* SIP signaling
*
* @param conferenceFocus <tt>true</tt> if the local peer represented by
* this <tt>Call</tt> is to act as a conference focus; otherwise,
* <tt>false</tt>
*/
void setConferenceFocus(boolean conferenceFocus)
{
if (this.conferenceFocus != conferenceFocus)
{
this.conferenceFocus = conferenceFocus;
/*
* If this Call switches from being a conference focus to not being
* one, dispose of the audio mixer used when it was a conference
* focus.
*/
if (!this.conferenceFocus)
conferenceAudioMixer = null;
// fire that the focus property has changed
fireCallChangeEvent(
CallChangeEvent.CALL_FOCUS_CHANGE,
!this.conferenceFocus, this.conferenceFocus);
}
}
/**
* Gets a <tt>MediaDevice</tt> which is capable of capture and/or playback
* of media of the specified <tt>MediaType</tt>, is the default choice of
* the user for a <tt>MediaDevice</tt> with the specified <tt>MediaType</tt>
* and is appropriate for the current state of this <tt>Call</tt>.
* <p>
* For example, when the local peer represented by this <tt>Call</tt>
* instance is acting as a conference focus, the audio device must be a
* mixer.
* </p>
*
* @param mediaType the <tt>MediaType</tt> in which the retrieved
* <tt>MediaDevice</tt> is to capture and/or play back media
* @return a <tt>MediaDevice</tt> which is capable of capture and/or
* playback of media of the specified <tt>mediaType</tt>, is the default
* choice of the user for a <tt>MediaDevice</tt> with the specified
* <tt>mediaType</tt> and is appropriate for the current state of this
* <tt>Call</tt>
*/
MediaDevice getDefaultDevice(MediaType mediaType)
{
MediaService mediaService = SipActivator.getMediaService();
MediaDevice device = mediaService.getDefaultDevice(mediaType,
mediaUseCase);
if (MediaType.AUDIO.equals(mediaType) && isConferenceFocus())
{
if (conferenceAudioMixer == null)
{
if (device != null)
conferenceAudioMixer = mediaService.createMixer(device);
}
return conferenceAudioMixer;
}
return device;
}
/**
* Adds a specific <tt>SoundLevelListener</tt> to the list of
* listeners interested in and notified about changes in local sound level
* related information. When the first listener is being registered the
* method also registers its single listener with the call peer media
* handlers so that it would receive level change events and delegate them
* to the listeners that have registered with us.
*
* @param l the <tt>SoundLevelListener</tt> to add
*/
public void addLocalUserSoundLevelListener(SoundLevelListener l)
{
synchronized(localUserAudioLevelListeners)
{
if (localUserAudioLevelListeners.size() == 0)
{
//if this is the first listener that's being registered with
//us, we also need to register ourselves as an audio level
//listener with the media handler. we do this so that audio
//level would only be calculated if anyone is interested in
//receiving them.
Iterator<CallPeerSipImpl> cps = getCallPeers();
while (cps.hasNext())
{
CallPeerSipImpl callPeerSipImpl = cps.next();
callPeerSipImpl.getMediaHandler()
.setLocalUserAudioLevelListener(
localAudioLevelDelegator);
}
}
localUserAudioLevelListeners.add(l);
}
}
/**
* Removes a specific <tt>SoundLevelListener</tt> from the list of
* listeners interested in and notified about changes in local sound level
* related information. If <tt>l</tt> is the last listener that we had here
* we are also going to unregister our own level event delegator in order
* to stop level calculations.
*
* @param l the <tt>SoundLevelListener</tt> to remove
*/
public void removeLocalUserSoundLevelListener(SoundLevelListener l)
{
synchronized(localUserAudioLevelListeners)
{
localUserAudioLevelListeners.add(l);
if (localUserAudioLevelListeners.size() == 0)
{
//if this was the last listener that was registered with us then
//no long need to have a delegator registered with the call
//peer media handlers. We therefore remove it so that audio
//level calculations would be ceased.
Iterator<CallPeerSipImpl> cps = getCallPeers();
while (cps.hasNext())
{
CallPeerSipImpl callPeerSipImpl = cps.next();
callPeerSipImpl.getMediaHandler()
.setLocalUserAudioLevelListener(null);
}
}
}
}
/**
* Notified by its very majesty the media service about changes in the
* audio level of the local user, this listener generates the corresponding
* events and delivers them to the listeners that have registered here.
*
* @param newLevel the new audio level of the local user.
*/
private void fireLocalUserAudioLevelChangeEvent(int newLevel)
{
SoundLevelChangeEvent evt
= new SoundLevelChangeEvent(this, newLevel);
synchronized( localUserAudioLevelListeners )
{
for(SoundLevelListener listener : localUserAudioLevelListeners)
listener.soundLevelChanged(evt);
}
}
/**
* Determines whether this call is mute.
*
* @return <tt>true</tt> if an audio streams being sent to the call
* peers are currently muted; <tt>false</tt>, otherwise
*/
public boolean isMute()
{
return this.mute;
}
/**
* Sets the mute property for this call.
*
* @param newMuteValue the new value of the mute property for this call
*/
public void setMute(boolean newMuteValue)
{
if (this.mute != newMuteValue)
{
this.mute = newMuteValue;
Iterator<CallPeerSipImpl> peers = getCallPeers();
while (peers.hasNext())
{
CallPeerSipImpl peer = peers.next();
peer.setMute(newMuteValue);
}
}
}
}

@ -32,7 +32,7 @@
* @author Emanuel Onica
*/
public class OperationSetBasicTelephonySipImpl
extends AbstractOperationSetBasicTelephony
extends AbstractOperationSetBasicTelephony<ProtocolProviderServiceSipImpl>
implements MethodProcessor,
OperationSetAdvancedTelephony,
OperationSetSecureTelephony

@ -12,6 +12,12 @@
* Provides implementations for some of the methods in the <tt>Call</tt>
* abstract class to facilitate implementations.
*
* @param <T> the peer extension class like for example <tt>CallPeerSipImpl</tt>
* or <tt>CallPeerJabberImpl</tt>
* @param <U> the provider extension class like for example
* <tt>ProtocolProviderServiceSipImpl</tt> or
* <tt>ProtocolProviderServiceJabberImpl</tt>
*
* @author Emil Ivov
*/
public abstract class AbstractCall<T extends CallPeer,

@ -16,11 +16,15 @@
* order to make it easier for implementers to provide complete solutions while
* focusing on implementation-specific details.
*
* @param <T> the implementation specific provider class like for example
* <tt>ProtocolProviderServiceSipImpl</tt>.
*
* @author Lubomir Marinov
* @author Emil Ivov
*/
public abstract class AbstractOperationSetBasicTelephony
implements OperationSetBasicTelephony
<T extends ProtocolProviderService>
implements OperationSetBasicTelephony<T>
{
/**
* Our class logger

@ -16,10 +16,14 @@
* supplementary operation set and if included in the service should be available
* behind the basic telephony set.
*
* @param <T> the provider extension class like for example
* <tt>ProtocolProviderServiceSipImpl</tt> or
* <tt>ProtocolProviderServiceJabberImpl</tt>
*
* @author Emil Ivov
* @author Lubomir Marinov
*/
public interface OperationSetBasicTelephony
public interface OperationSetBasicTelephony<T extends ProtocolProviderService>
extends OperationSet
{
/**
@ -147,4 +151,12 @@ public void hangupCallPeer(CallPeer peer)
* <tt>peers</tt>; otherwise, <tt>false</tt>
*/
public void setMute(Call call, boolean mute);
/**
* Returns the protocol provider that this operation set belongs to.
*
* @return a reference to the <tt>ProtocolProviderService</tt> that created
* this operation set.
*/
public T getProtocolProvider();
}

@ -0,0 +1,457 @@
/*
* 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.service.protocol.media;
import java.util.*;
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.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
/**
*
* @param <T> the peer extension class like for example <tt>CallPeerSipImpl</tt>
* or <tt>CallPeerJabberImpl</tt>
* @param <U> the provider extension class like for example
* <tt>OperationSetBasicTelephonySipImpl</tt> or
* <tt>OperationSetBasicTelephonySipImpl</tt>
* @param <V> the provider extension class like for example
* <tt>ProtocolProviderServiceSipImpl</tt> or
* <tt>ProtocolProviderServiceJabberImpl</tt>
*
* @author Emil Ivov
*/
public abstract class AbstractMediaAwareCall<T extends CallPeer,
U extends OperationSetBasicTelephony<V>,
V extends ProtocolProviderService>
extends AbstractCall<T, V>
implements CallPeerListener
{
/**
* The <tt>MediaDevice</tt> which performs audio mixing for this
* <tt>Call</tt> and its <tt>CallPeer</tt>s when the local peer represented
* by this <tt>Call</tt> is acting as a conference focus i.e.
* {@link #conferenceFocus} is <tt>true</tt>.
*/
private MediaDevice conferenceAudioMixer;
/**
* The indicator which determines whether the local peer represented by this
* <tt>Call</tt> is acting as a conference focus and is thus specifying the
* &quot;isfocus&quot; parameter in the Contact headers of its outgoing SIP
* signaling.
*/
private boolean conferenceFocus = false;
/**
* Our video streaming policy.
*/
protected boolean localVideoAllowed = false;
/**
* A reference to the <tt>OperationSetBasicTelephonySipImpl</tt> that
* created us;
*/
private final U parentOpSet;
/**
* Holds listeners registered for level changes in local audio.
*/
private final List<SoundLevelListener> localUserAudioLevelListeners
= new ArrayList<SoundLevelListener>();
/**
* The indicator which determines whether this <tt>Call</tt> is set
* to transmit "silence" instead of the actual media.
*/
private boolean mute = false;
/**
* Device used in call will be chosen according to <tt>MediaUseCase</tt>.
*/
protected MediaUseCase mediaUseCase = MediaUseCase.ANY;
/**
* The listener that would actually subscribe for level events from the
* media handler if there's at least one listener in
* <tt>localUserAudioLevelListeners</tt>.
*/
private final SimpleAudioLevelListener localAudioLevelDelegator
= new SimpleAudioLevelListener()
{
public void audioLevelChanged(int level)
{
fireLocalUserAudioLevelChangeEvent(level);
}
};
/**
* Crates a CallSipImpl instance belonging to <tt>sourceProvider</tt> and
* initiated by <tt>CallCreator</tt>.
*
* @param parentOpSet a reference to the operation set that's creating us
* and that we would be able to use for even dispatching.
*/
protected AbstractMediaAwareCall(U parentOpSet)
{
super(parentOpSet.getProtocolProvider());
}
/**
* Adds <tt>callPeer</tt> to the list of peers in this call.
* If the call peer is already included in the call, the method has
* no effect.
*
* @param callPeer the new <tt>CallPeer</tt>
*/
protected void addCallPeer(T callPeer)
{
if (getCallPeersVector().contains(callPeer))
return;
callPeer.addCallPeerListener(this);
synchronized(localUserAudioLevelListeners)
{
// if there's someone listening for audio level events then they'd
// also like to know about the new peer.
if(getCallPeersVector().size() == 0)
{
callPeer.getMediaHandler().setLocalUserAudioLevelListener(
localAudioLevelDelegator);
}
}
getCallPeersVector().add(callPeer);
fireCallPeerEvent(callPeer, CallPeerEvent.CALL_PEER_ADDED);
}
/**
* Removes <tt>callPeer</tt> from the list of peers in this
* call. The method has no effect if there was no such peer in the
* call.
*
* @param callPeer the <tt>CallPeer</tt> leaving the call;
*/
private void removeCallPeer(T callPeer)
{
if (!getCallPeersVector().contains(callPeer))
return;
getCallPeersVector().remove(callPeer);
callPeer.removeCallPeerListener(this);
synchronized(localUserAudioLevelListeners)
{
// remove sound level listeners from the peer
callPeer.getMediaHandler().setLocalUserAudioLevelListener(null);
}
try
{
fireCallPeerEvent(callPeer,
CallPeerEvent.CALL_PEER_REMOVED);
}
finally
{
/*
* The peer should loose its state once it has finished
* firing its events in order to allow the listeners to undo.
*/
callPeer.setCall(null);
}
if (getCallPeersVector().size() == 0)
setCallState(CallState.CALL_ENDED);
}
/**
* Dummy implementation of a method (inherited from CallPeerListener)
* that we don't need.
*
* @param evt unused.
*/
public void peerImageChanged(CallPeerChangeEvent evt)
{
//does not concern us
}
/**
* Dummy implementation of a method (inherited from CallPeerListener)
* that we don't need.
*
* @param evt unused.
*/
public void peerAddressChanged(CallPeerChangeEvent evt)
{
//does not concern us
}
/**
* Dummy implementation of a method (inherited from CallPeerListener)
* that we don't need.
*
* @param evt unused.
*/
public void peerTransportAddressChanged(
CallPeerChangeEvent evt)
{
//does not concern us
}
/**
* Dummy implementation of a method (inherited from CallPeerListener)
* that we don't need.
*
* @param evt unused.
*/
public void peerDisplayNameChanged(CallPeerChangeEvent evt)
{
//does not concern us
}
/**
* Verifies whether the call peer has entered a state.
*
* @param evt The <tt>CallPeerChangeEvent</tt> instance containing
* the source event as well as its previous and its new status.
*/
public void peerStateChanged(CallPeerChangeEvent evt)
{
CallPeerState newState = (CallPeerState) evt.getNewValue();
if (CallPeerState.DISCONNECTED.equals(newState)
|| CallPeerState.FAILED.equals(newState))
{
removeCallPeer((T) evt.getSourceCallPeer());
}
else if (CallPeerState.CONNECTED.equals(newState)
|| CallPeerState.CONNECTING_WITH_EARLY_MEDIA.equals(newState))
{
setCallState(CallState.CALL_IN_PROGRESS);
}
else if (CallPeerState.REFERRED.equals(newState))
{
setCallState(CallState.CALL_REFERRED);
}
}
/**
* Returns a reference to the <tt>OperationSetBasicTelephony</tt>
* implementation instance that created this call.
*
* @return a reference to the <tt>OperationSetBasicTelephonySipImpl</tt>
* instance that created this call.
*/
public U getParentOperationSet()
{
return parentOpSet;
}
/**
* Gets the indicator which determines whether the local peer represented by
* this <tt>Call</tt> is acting as a conference focus and thus should send
* the &quot;isfocus&quot; parameter in the Contact headers of its outgoing
* SIP signaling.
*
* @return <tt>true</tt> if the local peer represented by this <tt>Call</tt>
* is acting as a conference focus; otherwise, <tt>false</tt>
*/
public boolean isConferenceFocus()
{
return conferenceFocus;
}
/**
* Sets the indicator which determines whether the local peer represented by
* this <tt>Call</tt> is acting as a conference focus and thus should send
* the &quot;isfocus&quot; parameter in the Contact headers of its outgoing
* SIP signaling
*
* @param conferenceFocus <tt>true</tt> if the local peer represented by
* this <tt>Call</tt> is to act as a conference focus; otherwise,
* <tt>false</tt>
*/
void setConferenceFocus(boolean conferenceFocus)
{
if (this.conferenceFocus != conferenceFocus)
{
this.conferenceFocus = conferenceFocus;
/*
* If this Call switches from being a conference focus to not being
* one, dispose of the audio mixer used when it was a conference
* focus.
*/
if (!this.conferenceFocus)
conferenceAudioMixer = null;
// fire that the focus property has changed
fireCallChangeEvent(
CallChangeEvent.CALL_FOCUS_CHANGE,
!this.conferenceFocus, this.conferenceFocus);
}
}
/**
* Gets a <tt>MediaDevice</tt> which is capable of capture and/or playback
* of media of the specified <tt>MediaType</tt>, is the default choice of
* the user for a <tt>MediaDevice</tt> with the specified <tt>MediaType</tt>
* and is appropriate for the current state of this <tt>Call</tt>.
* <p>
* For example, when the local peer represented by this <tt>Call</tt>
* instance is acting as a conference focus, the audio device must be a
* mixer.
* </p>
*
* @param mediaType the <tt>MediaType</tt> in which the retrieved
* <tt>MediaDevice</tt> is to capture and/or play back media
* @return a <tt>MediaDevice</tt> which is capable of capture and/or
* playback of media of the specified <tt>mediaType</tt>, is the default
* choice of the user for a <tt>MediaDevice</tt> with the specified
* <tt>mediaType</tt> and is appropriate for the current state of this
* <tt>Call</tt>
*/
MediaDevice getDefaultDevice(MediaType mediaType)
{
MediaService mediaService = SipActivator.getMediaService();
MediaDevice device = mediaService.getDefaultDevice(mediaType,
mediaUseCase);
if (MediaType.AUDIO.equals(mediaType) && isConferenceFocus())
{
if (conferenceAudioMixer == null)
{
if (device != null)
conferenceAudioMixer = mediaService.createMixer(device);
}
return conferenceAudioMixer;
}
return device;
}
/**
* Adds a specific <tt>SoundLevelListener</tt> to the list of
* listeners interested in and notified about changes in local sound level
* related information. When the first listener is being registered the
* method also registers its single listener with the call peer media
* handlers so that it would receive level change events and delegate them
* to the listeners that have registered with us.
*
* @param l the <tt>SoundLevelListener</tt> to add
*/
public void addLocalUserSoundLevelListener(SoundLevelListener l)
{
synchronized(localUserAudioLevelListeners)
{
if (localUserAudioLevelListeners.size() == 0)
{
//if this is the first listener that's being registered with
//us, we also need to register ourselves as an audio level
//listener with the media handler. we do this so that audio
//level would only be calculated if anyone is interested in
//receiving them.
Iterator<CallPeerSipImpl> cps = getCallPeers();
while (cps.hasNext())
{
CallPeerSipImpl callPeerSipImpl = cps.next();
callPeerSipImpl.getMediaHandler()
.setLocalUserAudioLevelListener(
localAudioLevelDelegator);
}
}
localUserAudioLevelListeners.add(l);
}
}
/**
* Removes a specific <tt>SoundLevelListener</tt> from the list of
* listeners interested in and notified about changes in local sound level
* related information. If <tt>l</tt> is the last listener that we had here
* we are also going to unregister our own level event delegator in order
* to stop level calculations.
*
* @param l the <tt>SoundLevelListener</tt> to remove
*/
public void removeLocalUserSoundLevelListener(SoundLevelListener l)
{
synchronized(localUserAudioLevelListeners)
{
localUserAudioLevelListeners.add(l);
if (localUserAudioLevelListeners.size() == 0)
{
//if this was the last listener that was registered with us then
//no long need to have a delegator registered with the call
//peer media handlers. We therefore remove it so that audio
//level calculations would be ceased.
Iterator<T> cps = getCallPeers();
while (cps.hasNext())
{
T callPeerSipImpl = cps.next();
callPeerSipImpl.getMediaHandler()
.setLocalUserAudioLevelListener(null);
}
}
}
}
/**
* Notified by its very majesty the media service about changes in the
* audio level of the local user, this listener generates the corresponding
* events and delivers them to the listeners that have registered here.
*
* @param newLevel the new audio level of the local user.
*/
private void fireLocalUserAudioLevelChangeEvent(int newLevel)
{
SoundLevelChangeEvent evt
= new SoundLevelChangeEvent(this, newLevel);
synchronized( localUserAudioLevelListeners )
{
for(SoundLevelListener listener : localUserAudioLevelListeners)
listener.soundLevelChanged(evt);
}
}
/**
* Determines whether this call is mute.
*
* @return <tt>true</tt> if an audio streams being sent to the call
* peers are currently muted; <tt>false</tt>, otherwise
*/
public boolean isMute()
{
return this.mute;
}
/**
* Sets the mute property for this call.
*
* @param newMuteValue the new value of the mute property for this call
*/
public void setMute(boolean newMuteValue)
{
if (this.mute != newMuteValue)
{
this.mute = newMuteValue;
Iterator<T> peers = getCallPeers();
while (peers.hasNext())
{
T peer = peers.next();
peer.setMute(newMuteValue);
}
}
}
}
Loading…
Cancel
Save