mirror of https://github.com/sipwise/jitsi.git
Moves code from call peer's sip implementation to a super class that would be shared with the jabber implementation
parent
04cac3354c
commit
9bb144b9fa
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
* "isfocus" 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 "isfocus" 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 "isfocus" 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…
Reference in new issue