/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.java.sip.communicator.service.protocol.media; import java.awt.*; import java.beans.*; import java.text.*; import java.util.List; import net.java.sip.communicator.service.protocol.*; import org.jitsi.service.neomedia.*; import org.jitsi.util.event.*; /** * Represents a default implementation of <tt>OperationSetVideoTelephony</tt> in * order to make it easier for implementers to provide complete solutions while * focusing on implementation-specific details. * * @param <T> the implementation specific telephony operation set class like for * example <tt>OperationSetBasicTelephonySipImpl</tt>. * @param <U> the implementation specific provider class like for example * <tt>ProtocolProviderServiceSipImpl</tt>. * @param <V> the <tt>MediaAwareCall</tt> implementation like * <tt>CallSipImpl</tt> or <tt>CallJabberImpl</tt>. * @param <W> the <tt>MediaAwarePeerCall</tt> implementation like * <tt>CallPeerSipImpl</tt> or <tt>CallPeerJabberImpl</tt>. * * @author Emil Ivov * @author Sebastien Vincent */ public abstract class AbstractOperationSetVideoTelephony< T extends OperationSetBasicTelephony<U>, U extends ProtocolProviderService, V extends MediaAwareCall<W, T, U>, W extends MediaAwareCallPeer<V, ?, U> > implements OperationSetVideoTelephony { /** * The SIP <tt>ProtocolProviderService</tt> implementation which created * this instance and for which telephony conferencing services are being * provided by this instance. */ protected final U parentProvider; /** * The telephony-related functionality this extension builds upon. */ protected final T basicTelephony; /** * Initializes a new <tt>AbstractOperationSetVideoTelephony</tt> instance * which builds upon the telephony-related functionality of a specific * <tt>OperationSetBasicTelephony</tt> implementation. * * @param basicTelephony the <tt>OperationSetBasicTelephony</tt> * the new extension should build upon */ public AbstractOperationSetVideoTelephony(T basicTelephony) { this.basicTelephony = basicTelephony; this.parentProvider = basicTelephony.getProtocolProvider(); } /** * Delegates to the <tt>CallPeerMediaHandler</tt> of the specified * <tt>CallPeer</tt> because the video is provided by it. Because other * <tt>OperationSetVideoTelephony</tt> implementations may not provide their * video through the <tt>CallPeerMediaHandler</tt>, this implementation * promotes itself as the provider of the video by replacing the * <tt>CallPeerMediaHandler</tt> in the <tt>VideoEvents</tt> it fires. * * @param peer the <tt>CallPeer</tt> that we will be registering * <tt>listener</tt> with. * @param listener the <tt>VideoListener</tt> that we'd like to register. */ @SuppressWarnings("unchecked") // work with MediaAware* in media package public void addVideoListener(CallPeer peer, VideoListener listener) { if (listener == null) throw new NullPointerException("listener"); ((W)peer).getMediaHandler().addVideoListener(listener); } /** * Implements * {@link OperationSetVideoTelephony#createLocalVisualComponent(CallPeer)}. * * @param peer the <tt>CallPeer</tt> that we are sending our local video to. * @return the <tt>Component</tt> containing the local video. * @throws OperationFailedException if we fail extracting the local video. */ @SuppressWarnings("unchecked") // work with MediaAware* in media package public Component getLocalVisualComponent(CallPeer peer) throws OperationFailedException { return ((W)peer).getMediaHandler().getLocalVisualComponent(); } /** * Gets the visual/video <tt>Component</tt> available in this telephony for * a specific <tt>CallPeer</tt>. * * @param peer the <tt>CallPeer</tt> whose video is to be retrieved * @return the visual/video <tt>Component</tt> available in this telephony * for the specified <tt>peer</tt> if any; otherwise, <tt>null</tt> */ @Deprecated public Component getVisualComponent(CallPeer peer) { List<Component> visualComponents = getVisualComponents(peer); return visualComponents.isEmpty() ? null : visualComponents.get(0); } /** * Gets the visual/video <tt>Component</tt>s available in this telephony for * a specific <tt>CallPeer</tt>. * * @param peer the <tt>CallPeer</tt> whose videos are to be retrieved * @return the visual/video <tt>Component</tt>s available in this telephony * for the specified <tt>peer</tt> */ @SuppressWarnings("unchecked") // work with MediaAware* in media package public List<Component> getVisualComponents(CallPeer peer) { return ((W)peer).getMediaHandler().getVisualComponents(); } /** * Returns the <tt>ConferenceMember</tt> corresponding to the given * <tt>visualComponent</tt>. * * @param peer the parent <tt>CallPeer</tt> * @param visualComponent the visual <tt>Component</tt>, which corresponding * <tt>ConferenceMember</tt> we're looking for * @return the <tt>ConferenceMember</tt> corresponding to the given * <tt>visualComponent</tt>. */ public ConferenceMember getConferenceMember(CallPeer peer, Component visualComponent) { @SuppressWarnings("unchecked") W w = (W) peer; VideoMediaStream videoStream = (VideoMediaStream) w.getMediaHandler().getStream(MediaType.VIDEO); if (videoStream != null) { for (ConferenceMember member : peer.getConferenceMembers()) { Component memberComponent = videoStream.getVisualComponent(member.getVideoSsrc()); if (visualComponent.equals(memberComponent)) return member; } } return null; } /** * Delegates to the <tt>CallPeerMediaHandler</tt> of the specified * <tt>CallPeer</tt> because the video is provided by it. * * @param peer the <tt>CallPeer</tt> that we'd like to unregister our * <tt>VideoListener</tt> from. * @param listener the <tt>VideoListener</tt> that we'd like to unregister. */ @SuppressWarnings("unchecked") // work with MediaAware* in media package public void removeVideoListener(CallPeer peer, VideoListener listener) { if (listener != null) ((W)peer).getMediaHandler().removeVideoListener(listener); } /** * Implements OperationSetVideoTelephony#setLocalVideoAllowed(Call, * boolean). Modifies the local media setup to reflect the requested setting * for the streaming of the local video and then re-invites all * CallPeers to re-negotiate the modified media setup. * * @param call the call where we'd like to allow sending local video. * @param allowed <tt>true</tt> if local video transmission is allowed and * <tt>false</tt> otherwise. * * @throws OperationFailedException if video initialization fails. */ public void setLocalVideoAllowed(Call call, boolean allowed) throws OperationFailedException { MediaAwareCall<?, ?, ?> mediaAwareCall = (MediaAwareCall<?, ?, ?>) call; MediaUseCase useCase = MediaUseCase.CALL; mediaAwareCall.setLocalVideoAllowed(allowed, useCase); } /** * Determines whether the streaming of local video in a specific * <tt>Call</tt> is currently allowed. The setting does not reflect * the availability of actual video capture devices, it just expresses the * desire of the user to have the local video streamed in the case the * system is actually able to do so. * * @param call the <tt>Call</tt> whose video transmission properties we are * interested in. * * @return <tt>true</tt> if the streaming of local video for the specified * <tt>Call</tt> is allowed; otherwise, <tt>false</tt> */ @SuppressWarnings("unchecked") // work with MediaAware* in media package public boolean isLocalVideoAllowed(Call call) { return ((V)call).isLocalVideoAllowed(MediaUseCase.CALL); } /** * Determines whether a specific <tt>Call</tt> is currently streaming the * local video (to a remote destination). * * @param call the <tt>Call</tt> whose video transmission we are interested * in. * * @return <tt>true</tt> if the specified <tt>Call</tt> is currently * streaming the local video (to a remote destination); otherwise, * <tt>false</tt> */ @SuppressWarnings("unchecked") // work with MediaAware* in media package public boolean isLocalVideoStreaming(Call call) { return ((V)call).isLocalVideoStreaming(); } /** * Adds a specific <tt>PropertyChangeListener</tt> to the list of * listeners which get notified when the properties (e.g. * {@link #LOCAL_VIDEO_STREAMING}) associated with a specific * <tt>Call</tt> change their values. * * @param call the <tt>Call</tt> to start listening to the changes of * the property values of * @param listener the <tt>PropertyChangeListener</tt> to be notified * when the properties associated with the specified <tt>Call</tt> change * their values */ @SuppressWarnings("unchecked") // work with MediaAware* in media package public void addPropertyChangeListener( Call call, PropertyChangeListener listener) { ((V)call).addVideoPropertyChangeListener(listener); } /** * Removes a specific <tt>PropertyChangeListener</tt> from the list of * listeners which get notified when the properties (e.g. * {@link #LOCAL_VIDEO_STREAMING}) associated with a specific * <tt>Call</tt> change their values. * * @param call the <tt>Call</tt> to stop listening to the changes of the * property values of * @param listener the <tt>PropertyChangeListener</tt> to no longer be * notified when the properties associated with the specified <tt>Call</tt> * change their values */ @SuppressWarnings("unchecked") // work with MediaAware* in media package public void removePropertyChangeListener( Call call, PropertyChangeListener listener) { ((V)call).removeVideoPropertyChangeListener(listener); } /** * Get the <tt>MediaUseCase</tt> of a video telephony operation set. * * @return <tt>MediaUseCase.CALL</tt> */ public MediaUseCase getMediaUseCase() { return MediaUseCase.CALL; } /** * Returns the quality control for video calls if any. * Return null so protocols who supports it to override it. * @param peer the peer which this control operates on. * @return the implemented quality control. */ public QualityControl getQualityControl(CallPeer peer) { return null; } /** * Create a new video call and invite the specified CallPeer to it with * initial video setting. * * @param uri the address of the callee that we should invite to a new * call. * @param qualityPreferences the quality preset we will use establishing * the video call, and we will expect from the other side. When establishing * call we don't have any indications whether remote part supports quality * presets, so this setting can be ignored. * @return CallPeer the CallPeer that will represented by the * specified uri. All following state change events will be delivered * through that call peer. The Call that this peer is a member * of could be retrieved from the CallParticipatn instance with the use * of the corresponding method. * @throws OperationFailedException with the corresponding code if we fail * to create the video call. * @throws java.text.ParseException if <tt>callee</tt> is not a valid sip address * string. */ public Call createVideoCall(String uri, QualityPreset qualityPreferences) throws OperationFailedException, ParseException { return createVideoCall(uri); } /** * Create a new video call and invite the specified CallPeer to it with * initial video setting. * * @param callee the address of the callee that we should invite to a new * call. * @param qualityPreferences the quality preset we will use establishing * the video call, and we will expect from the other side. When establishing * call we don't have any indications whether remote part supports quality * presets, so this setting can be ignored. * @return CallPeer the CallPeer that will represented by the * specified uri. All following state change events will be delivered * through that call peer. The Call that this peer is a member * of could be retrieved from the CallParticipatn instance with the use * of the corresponding method. * @throws OperationFailedException with the corresponding code if we fail * to create the video call. */ public Call createVideoCall( Contact callee, QualityPreset qualityPreferences) throws OperationFailedException { return createVideoCall(callee); } }