/*
* 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.sip;
import java.awt.*;
import net.java.sip.communicator.service.media.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
/**
* Implements <code>OperationSetVideoTelephony</code> in order to give access to
* video-specific functionality in the SIP protocol implementation such as
* visual <code>Component</code>s displaying video and listening to dynamic
* availability of such <code>Component</code>s. Because the video in the SIP
* protocol implementation is provided by the <code>CallSession</code>, this
* <code>OperationSetVideoTelephony</code> just delegates to the
* <code>CallSession</code> while hiding the <code>CallSession</code> as the
* provider of the video and pretending this
* <code>OperationSetVideoTelephony</code> is the provider because other
* implementation may not provider their video through the
* <code>CallSession</code>.
*
* @author Lubomir Marinov
*/
public class OperationSetVideoTelephonySipImpl
implements OperationSetVideoTelephony
{
/*
* Delegates to the CallSession of the Call of the specified CallParticipant
* because the video is provided by the CallSession in the SIP protocol
* implementation. Because other OperationSetVideoTelephony implementations
* may not provide their video through the CallSession, this implementation
* promotes itself as the provider of the video by replacing the CallSession
* in the VideoEvents it fires.
*/
public void addVideoListener(CallParticipant participant,
VideoListener listener)
{
if (listener == null)
throw new NullPointerException("listener");
((CallSipImpl) participant.getCall()).getMediaCallSession()
.addVideoListener(
new InternalVideoListener(this, participant, listener));
}
public Component createLocalVisualComponent(CallParticipant participant,
VideoListener listener) throws OperationFailedException
{
CallSession callSession =
((CallSipImpl) participant.getCall()).getMediaCallSession();
if (callSession != null)
{
try
{
return callSession.createLocalVisualComponent(listener);
}
catch (MediaException ex)
{
throw new OperationFailedException(
"Failed to create visual Component for local video (capture).",
OperationFailedException.INTERNAL_ERROR, ex);
}
}
return null;
}
public void disposeLocalVisualComponent(CallParticipant participant,
Component component)
{
CallSession callSession =
((CallSipImpl) participant.getCall()).getMediaCallSession();
if (callSession != null)
{
callSession.disposeLocalVisualComponent(component);
}
}
/*
* Delegates to the CallSession of the Call of the specified CallParticipant
* because the video is provided by the CallSession in the SIP protocol
* implementation.
*/
public Component[] getVisualComponents(CallParticipant participant)
{
CallSession callSession =
((CallSipImpl) participant.getCall()).getMediaCallSession();
return (callSession != null) ? callSession.getVisualComponents()
: new Component[0];
}
/*
* Delegates to the CallSession of the Call of the specified CallParticipant
* because the video is provided by the CallSession in the SIP protocol
* implementation. Because other OperationSetVideoTelephony implementations
* may not provide their video through the CallSession, this implementation
* promotes itself as the provider of the video by replacing the CallSession
* in the VideoEvents it fires.
*/
public void removeVideoListener(CallParticipant participant,
VideoListener listener)
{
if (listener != null)
{
((CallSipImpl) participant.getCall()).getMediaCallSession()
.removeVideoListener(
new InternalVideoListener(this, participant, listener));
}
}
/**
* Represents a <code>VideoListener</code> which forwards notifications to a
* specific delegate <code>VideoListener</code> and hides the original
* <code>VideoEvent</code> sender from it by pretending the sender is a
* specific <code>OperationSetVideoTelephony</code>. It's necessary in order
* to hide from the <code>VideoListener</code>s the fact that the video of
* the SIP protocol implementation is managed by <code>CallSession</code>.
*/
private static class InternalVideoListener
implements VideoListener
{
/**
* The <code>VideoListener</code> this implementation hides the original
* <code>VideoEvent</code> source from.
*/
private final VideoListener delegate;
/**
* The <code>CallParticipant</code> whose videos {@link #delegate} is
* interested in.
*/
private final CallParticipant participant;
/**
* The <code>OperationSetVideoTelephony</code> which is to be presented
* as the source of the <code>VideoEvents</code> forwarded to
* {@link #delegate}.
*/
private final OperationSetVideoTelephony telephony;
/**
* Initializes a new <code>InternalVideoListener</code> which is to
* impersonate the sources of <code>VideoEvents</code> with a specific
* <code>OperationSetVideoTelephony</code> for a specific
* <code>VideoListener</code> interested in the videos of a specific
* <code>CallParticipant</code>.
*
* @param telephony the <code>OperationSetVideoTelephony</code> which is
* to be stated as the source of the <code>VideoEvent</code>
* sent to the specified delegate <code>VideoListener</code>
* @param participant the <code>CallParticipant</code> whose videos the
* specified delegate <code>VideoListener</code> is
* interested in
* @param delegate the <code>VideoListener</code> which shouldn't know
* that the videos in the SIP protocol implementation is
* managed by the CallSession and not by the specified
* <code>telephony</code>
*/
public InternalVideoListener(OperationSetVideoTelephony telephony,
CallParticipant participant, VideoListener delegate)
{
if (participant == null)
throw new NullPointerException("participant");
this.telephony = telephony;
this.participant = participant;
this.delegate = delegate;
}
/*
* Two InternalVideoListeners are equal if they impersonate the sources
* of VideoEvents with equal OperationSetVideoTelephonies for equal
* delegate VideoListeners added to equal CallParticipants.
*/
public boolean equals(Object other)
{
if (other == this)
return true;
if ((other == null) || !other.getClass().equals(getClass()))
return false;
InternalVideoListener otherListener = (InternalVideoListener) other;
return otherListener.telephony.equals(telephony)
&& otherListener.participant.equals(participant)
&& otherListener.delegate.equals(delegate);
}
public int hashCode()
{
return (telephony.hashCode() << 16) + (delegate.hashCode() >> 16);
}
/*
* Upon receiving a VideoEvent, sends to delegate a new VideoEvent of
* the same type and with the same visual Component but with the source
* of the event being set to #telephony. Thus the fact that the
* CallSession is the original source is hidden from the clients of
* OperationSetVideoTelephony.
*/
public void videoAdded(VideoEvent event)
{
delegate.videoAdded(new VideoEvent(this, event.getType(), event
.getVisualComponent(), event.getOrigin()));
}
/*
* Upon receiving a VideoEvent, sends to delegate a new VideoEvent of
* the same type and with the same visual Component but with the source
* of the event being set to #telephony. Thus the fact that the
* CallSession is the original source is hidden from the clients of
* OperationSetVideoTelephony.
*/
public void videoRemoved(VideoEvent event)
{
delegate.videoAdded(new VideoEvent(this, event.getType(), event
.getVisualComponent(), event.getOrigin()));
}
}
}