
org.jitsi.impl.neomedia.device.VideoTranslatorMediaDevice Maven / Gradle / Ivy
/*
* 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 org.jitsi.impl.neomedia.device;
import java.awt.*;
import java.util.*;
import java.util.List;
import javax.media.*;
import javax.media.protocol.*;
import org.jitsi.impl.neomedia.*;
import org.jitsi.impl.neomedia.format.*;
import org.jitsi.service.neomedia.*;
import org.jitsi.service.neomedia.codec.*;
import org.jitsi.service.neomedia.device.*;
import org.jitsi.service.neomedia.format.*;
import org.jitsi.util.event.*;
import org.jitsi.utils.*;
/**
* Implements a MediaDevice which is to be used in video conferencing
* implemented with an RTP translator.
*
* @author Lyubomir Marinov
* @author Hristo Terezov
* @author Boris Grozev
*/
public class VideoTranslatorMediaDevice
extends AbstractMediaDevice
implements MediaDeviceWrapper,
VideoListener
{
/**
* The MediaDevice which this instance enables to be used in a
* video conference implemented with an RTP translator.
*/
private final MediaDeviceImpl device;
/**
* The VideoMediaDeviceSession of {@link #device} the
* outputDataSource of which is the captureDevice of
* {@link #streamDeviceSessions}.
*/
private VideoMediaDeviceSession deviceSession;
/**
* The MediaStreamMediaDeviceSessions sharing the
* outputDataSource of {@link #device} as their
* captureDevice.
*/
private final List streamDeviceSessions
= new LinkedList();
/**
* Initializes a new VideoTranslatorMediaDevice which enables a
* specific MediaDevice to be used in video conferencing
* implemented with an RTP translator.
*
* @param device the MediaDevice which the new instance is to
* enable to be used in video conferencing implemented with an RTP
* translator
*/
public VideoTranslatorMediaDevice(MediaDeviceImpl device)
{
this.device = device;
}
/**
* Releases the resources allocated by this instance in the course of its
* execution and prepares it to be garbage collected when all
* {@link #streamDeviceSessions} have been closed.
*
* @param streamDeviceSession the MediaStreamMediaDeviceSession
* which has been closed
*/
private synchronized void close(
MediaStreamMediaDeviceSession streamDeviceSession)
{
streamDeviceSessions.remove(streamDeviceSession);
if(deviceSession != null)
{
deviceSession.removeRTCPFeedbackMessageCreateListner(
streamDeviceSession);
}
if (streamDeviceSessions.isEmpty())
{
if(deviceSession != null)
{
deviceSession.removeVideoListener(this);
deviceSession.close();
}
deviceSession = null;
}
else
updateDeviceSessionStartedDirection();
}
/**
* Creates a DataSource instance for this MediaDevice
* which gives access to the captured media.
*
* @return a DataSource instance which gives access to the media
* captured by this MediaDevice
* @see AbstractMediaDevice#createOutputDataSource()
*/
@Override
protected synchronized DataSource createOutputDataSource()
{
if (deviceSession == null)
{
MediaFormatImpl extends Format> format = null;
MediaDirection startedDirection = MediaDirection.INACTIVE;
for (MediaStreamMediaDeviceSession streamDeviceSession
: streamDeviceSessions)
{
MediaFormatImpl extends Format> streamFormat
= streamDeviceSession.getFormat();
if ((streamFormat != null) && (format == null))
format = streamFormat;
startedDirection
= startedDirection.or(
streamDeviceSession.getStartedDirection());
}
MediaDeviceSession newDeviceSession = device.createSession();
if(newDeviceSession instanceof VideoMediaDeviceSession)
{
deviceSession = (VideoMediaDeviceSession)newDeviceSession;
deviceSession.addVideoListener(this);
for (MediaStreamMediaDeviceSession streamDeviceSession
: streamDeviceSessions)
{
deviceSession.addRTCPFeedbackMessageCreateListner(
streamDeviceSession);
}
}
if (format != null)
deviceSession.setFormat(format);
deviceSession.start(startedDirection);
}
return
(deviceSession == null)
? null
: deviceSession.getOutputDataSource();
}
/**
* Creates a new MediaDeviceSession instance which is to represent
* the use of this MediaDevice by a MediaStream.
*
* @return a new MediaDeviceSession instance which is to represent
* the use of this MediaDevice by a MediaStream
* @see AbstractMediaDevice#createSession()
*/
@Override
public synchronized MediaDeviceSession createSession()
{
MediaStreamMediaDeviceSession streamDeviceSession
= new MediaStreamMediaDeviceSession();
streamDeviceSessions.add(streamDeviceSession);
return streamDeviceSession;
}
/**
* Returns the MediaDirection supported by this device.
*
* @return MediaDirection.SENDONLY if this is a read-only device,
* MediaDirection.RECVONLY if this is a write-only device and
* MediaDirection.SENDRECV if this MediaDevice can both
* capture and render media
* @see MediaDevice#getDirection()
*/
public MediaDirection getDirection()
{
return device.getDirection();
}
/**
* Returns the MediaFormat that this device is currently set to use
* when capturing data.
*
* @return the MediaFormat that this device is currently set to
* provide media in.
* @see MediaDevice#getFormat()
*/
public MediaFormat getFormat()
{
return device.getFormat();
}
/**
* Returns the MediaType that this device supports.
*
* @return MediaType.AUDIO if this is an audio device or
* MediaType.VIDEO in case of a video device
* @see MediaDevice#getMediaType()
*/
public MediaType getMediaType()
{
return device.getMediaType();
}
/**
* Returns a list of MediaFormat instances representing the media
* formats supported by this MediaDevice.
*
* @param localPreset the preset used to set the send format parameters,
* used for video and settings
* @param remotePreset the preset used to set the receive format parameters,
* used for video and settings
* @return the list of MediaFormats supported by this device
* @see MediaDevice#getSupportedFormats(QualityPreset, QualityPreset)
*/
public List getSupportedFormats(
QualityPreset localPreset,
QualityPreset remotePreset)
{
return device.getSupportedFormats(localPreset, remotePreset);
}
/**
* Returns a list of MediaFormat instances representing the media
* formats supported by this MediaDevice and enabled in
* encodingConfiguration..
*
* @param localPreset the preset used to set the send format parameters,
* used for video and settings
* @param remotePreset the preset used to set the receive format parameters,
* used for video and settings
* @param encodingConfiguration the EncodingConfiguration instance
* to use
* @return the list of MediaFormats supported by this device
* and enabled in encodingConfiguration.
* @see MediaDevice#getSupportedFormats(QualityPreset, QualityPreset,
* EncodingConfiguration)
*/
public List getSupportedFormats(
QualityPreset localPreset,
QualityPreset remotePreset,
EncodingConfiguration encodingConfiguration)
{
return device.getSupportedFormats(localPreset,
remotePreset,
encodingConfiguration);
}
/**
* Gets the actual MediaDevice which this MediaDevice is
* effectively built on top of and forwarding to.
*
* @return the actual MediaDevice which this MediaDevice
* is effectively built on top of and forwarding to
* @see MediaDeviceWrapper#getWrappedDevice()
*/
public MediaDevice getWrappedDevice()
{
return device;
}
/**
* Updates the value of the startedDirection property of
* {@link #deviceSession} to be in accord with the values of the property
* of {@link #streamDeviceSessions}.
*/
private synchronized void updateDeviceSessionStartedDirection()
{
if (deviceSession == null)
return;
MediaDirection startDirection = MediaDirection.INACTIVE;
for (MediaStreamMediaDeviceSession streamDeviceSession
: streamDeviceSessions)
{
startDirection
= startDirection.or(streamDeviceSession.getStartedDirection());
}
deviceSession.start(startDirection);
MediaDirection stopDirection = MediaDirection.INACTIVE;
if (!startDirection.allowsReceiving())
stopDirection = stopDirection.or(MediaDirection.RECVONLY);
if (!startDirection.allowsSending())
stopDirection = stopDirection.or(MediaDirection.SENDONLY);
deviceSession.stop(stopDirection);
}
/**
* {@inheritDoc}
*
* Forwards event, to each of the managed
* MediaStreamMediaDeviceSession instances. The event is expected
* to come from this.deviceSession, since this is
* registered there as a VideoListener.
*/
@Override
public void videoAdded(VideoEvent event)
{
for (MediaStreamMediaDeviceSession sds : streamDeviceSessions)
{
sds.fireVideoEvent(event, false);
}
}
/**
* {@inheritDoc}
*
* Forwards event, to each of the managed
* MediaStreamMediaDeviceSession instances. The event is expected
* to come from this.deviceSession, since this is
* registered there as a VideoListener.
*/
@Override
public void videoRemoved(VideoEvent event)
{
for (MediaStreamMediaDeviceSession sds : streamDeviceSessions)
{
sds.fireVideoEvent(event, false);
}
}
/**
* {@inheritDoc}
*
* Forwards event, to each of the managed
* MediaStreamMediaDeviceSession instances. The event is expected
* to come from this.deviceSession, since this is
* registered there as a VideoListener.
*/
@Override
public void videoUpdate(VideoEvent event)
{
for (MediaStreamMediaDeviceSession sds : streamDeviceSessions)
{
sds.fireVideoEvent(event, false);
}
}
/**
* Represents the use of this VideoTranslatorMediaDevice by a
* MediaStream.
*/
private class MediaStreamMediaDeviceSession
extends VideoMediaDeviceSession
{
/**
* Initializes a new MediaStreamMediaDeviceSession which is to
* represent the use of this VideoTranslatorMediaDevice by a
* MediaStream.
*/
public MediaStreamMediaDeviceSession()
{
super(VideoTranslatorMediaDevice.this);
}
/**
* Releases the resources allocated by this instance in the course of
* its execution and prepares it to be garbage collected.
*/
@Override
public void close()
{
super.close();
VideoTranslatorMediaDevice.this.close(this);
}
/**
* Creates the DataSource that this instance is to read
* captured media from.
*
* @return the DataSource that this instance is to read
* captured media from
* @see VideoMediaDeviceSession#createCaptureDevice()
*/
@Override
protected DataSource createCaptureDevice()
{
return VideoTranslatorMediaDevice.this.createOutputDataSource();
}
/**
* Initializes a new Player instance which is to provide the
* local visual/video Component. The new instance is
* initialized to render the media of a specific DataSource.
*
* @param captureDevice the DataSource which is to have its
* media rendered by the new instance as the local visual/video
* Component
* @return a new Player instance which is to provide the local
* visual/video Component
*/
@Override
protected Player createLocalPlayer(DataSource captureDevice)
{
synchronized (VideoTranslatorMediaDevice.this)
{
if (deviceSession != null)
captureDevice = deviceSession.getCaptureDevice();
}
return super.createLocalPlayer(captureDevice);
}
/**
* Initializes a new FMJ Processor which is to transcode
* {@link #captureDevice} into the format of this instance.
*
* @return a new FMJ Processor which is to transcode
* captureDevice into the format of this instance
*/
@Override
protected Processor createProcessor()
{
return null;
}
/**
* Gets the output DataSource of this instance which provides
* the captured (RTP) data to be sent by MediaStream to
* MediaStreamTarget.
*
* @return the output DataSource of this instance which
* provides the captured (RTP) data to be sent by MediaStream
* to MediaStreamTarget
* @see MediaDeviceSession#getOutputDataSource()
*/
@Override
public DataSource getOutputDataSource()
{
return getConnectedCaptureDevice();
}
/**
* Sets the RTPConnector that will be used to initialize some
* codec for RTCP feedback and adds the instance to
* RTCPFeedbackCreateListners of deviceSession.
*
* @param rtpConnector the RTP connector
*/
@Override
public void setConnector(AbstractRTPConnector rtpConnector)
{
super.setConnector(rtpConnector);
if(deviceSession != null)
deviceSession.addRTCPFeedbackMessageCreateListner(this);
}
/**
* Notifies this instance that the value of its
* startedDirection property has changed from a specific
* oldValue to a specific newValue.
*
* @param oldValue the MediaDirection which used to be the
* value of the startedDirection property of this instance
* @param newValue the MediaDirection which is the value of the
* startedDirection property of this instance
*/
@Override
protected void startedDirectionChanged(
MediaDirection oldValue,
MediaDirection newValue)
{
super.startedDirectionChanged(oldValue, newValue);
VideoTranslatorMediaDevice.this
.updateDeviceSessionStartedDirection();
}
/**
* {@inheritDoc}
* Returns the local visual Component for this
* MediaStreamMediaDeviceSession, which, if present, is
* maintained in this.deviceSession.
*/
@Override
public Component getLocalVisualComponent()
{
if (deviceSession != null)
return deviceSession.getLocalVisualComponent();
return null;
}
/**
* {@inheritDoc}
*
* Creates, if necessary, the local visual Component depicting
* the video being streamed from the local peer to a remote peer. The
* Component is provided by the single Player
* instance, which is maintained for this
* VideoTranslatorMediaDevice and is managed by
* this.deviceSession.
*/
@Override
protected Component createLocalVisualComponent()
{
if (deviceSession != null)
return deviceSession.createLocalVisualComponent();
return null;
}
/**
* {@inheritDoc}
*
* Returns the Player instance which provides the local
* visual/video Component. A single Player is
* maintained for this VideoTranslatorMediaDevice, and it is
* managed by this.deviceSession.
*/
@Override
protected Player getLocalPlayer()
{
if (deviceSession != null)
return deviceSession.getLocalPlayer();
return null;
}
/**
* {@inheritDoc}
*
* Does nothing, because there is no Player associated with
* this MediaStreamMediaDeviceSession and therefore nothing to
* dispose of.
* @param player the Player to dispose of.
*/
@Override
protected void disposeLocalPlayer(Player player){}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy