
org.jitsi.impl.neomedia.conference.AudioMixingPushBufferDataSource Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of libjitsi Show documentation
Show all versions of libjitsi Show documentation
libjitsi is an advanced Java media library for secure real-time audio/video
communication
The newest version!
/*
* 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.conference;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import javax.media.*;
import javax.media.control.*;
import javax.media.protocol.*;
import org.jitsi.impl.neomedia.control.*;
import org.jitsi.impl.neomedia.protocol.*;
import org.jitsi.service.neomedia.*;
import org.jitsi.utils.logging.*;
/**
* Represents a PushBufferDataSource which provides a single
* PushBufferStream containing the result of the audio mixing of
* DataSources.
*
* @author Lyubomir Marinov
*/
public class AudioMixingPushBufferDataSource
extends PushBufferDataSource
implements CaptureDevice,
MuteDataSource,
InbandDTMFDataSource
{
/**
* The Logger used by the AudioMixingPushBufferDataSource
* class and its instances for logging output.
*/
private static final Logger logger
= Logger.getLogger(AudioMixingPushBufferDataSource.class);
/**
* The AudioMixer performing the audio mixing, managing the input
* DataSources and pushing the data of this output
* PushBufferDataSource.
*/
final AudioMixer audioMixer;
/**
* The indicator which determines whether this DataSource is
* connected.
*/
private boolean connected;
/**
* The indicator which determines whether this DataSource is set
* to transmit "silence" instead of the actual media.
*/
private boolean mute = false;
/**
* The one and only PushBufferStream this
* PushBufferDataSource provides to its clients and containing the
* result of the audio mixing performed by audioMixer.
*/
private AudioMixingPushBufferStream outStream;
/**
* The indicator which determines whether this DataSource is
* started.
*/
private boolean started;
/**
* The tones to send via inband DTMF, if not empty.
*/
private final LinkedList tones
= new LinkedList();
/**
* Initializes a new AudioMixingPushBufferDataSource instance which
* gives access to the result of the audio mixing performed by a specific
* AudioMixer.
*
* @param audioMixer the AudioMixer performing audio mixing,
* managing the input DataSources and pushing the data of the new
* output PushBufferDataSource
*/
public AudioMixingPushBufferDataSource(AudioMixer audioMixer)
{
this.audioMixer = audioMixer;
}
/**
* Adds a new inband DTMF tone to send.
*
* @param tone the DTMF tone to send.
*/
public void addDTMF(DTMFInbandTone tone)
{
tones.add(tone);
}
/**
* Adds a new input DataSource to be mixed by the associated
* AudioMixer of this instance and to not have its audio
* contributions included in the mixing output represented by this
* DataSource.
*
* @param inDataSource a DataSource to be added for mixing to
* the AudioMixer associate with this instance and to not have its
* audio contributions included in the mixing output represented by this
* DataSource
*/
public void addInDataSource(DataSource inDataSource)
{
audioMixer.addInDataSource(inDataSource, this);
}
/**
* Implements {@link DataSource#connect()}. Lets the AudioMixer
* know that one of its output PushBufferDataSources has been
* connected and marks this DataSource as connected.
*
* @throws IOException if the AudioMixer fails to connect
*/
@Override
public synchronized void connect()
throws IOException
{
if (!connected)
{
audioMixer.connect();
connected = true;
}
}
/**
* Implements {@link DataSource#disconnect()}. Marks this
* DataSource as disconnected and notifies the AudioMixer
* that one of its output PushBufferDataSources has been
* disconnected.
*/
@Override
public synchronized void disconnect()
{
try
{
stop();
}
catch (IOException ioex)
{
throw new UndeclaredThrowableException(ioex);
}
if (connected)
{
outStream = null;
connected = false;
audioMixer.disconnect();
}
}
/**
* Gets the BufferControl available for this DataSource.
* Delegates to the AudioMixer because this instance is just a
* facet to it.
*
* @return the BufferControl available for this DataSource
*/
private BufferControl getBufferControl()
{
return audioMixer.getBufferControl();
}
/**
* Implements {@link CaptureDevice#getCaptureDeviceInfo()}. Delegates to the
* associated AudioMixer because it knows which
* CaptureDevice is being wrapped.
*
* @return the CaptureDeviceInfo of the CaptureDevice of
* the AudioMixer
*/
public CaptureDeviceInfo getCaptureDeviceInfo()
{
return audioMixer.getCaptureDeviceInfo();
}
/**
* Implements {@link DataSource#getContentType()}. Delegates to the
* associated AudioMixer because it manages the inputs and knows
* their characteristics.
*
* @return a String value which represents the type of the content
* being made available by this DataSource i.e. the associated
* AudioMixer
*/
@Override
public String getContentType()
{
return audioMixer.getContentType();
}
/**
* Implements {@link DataSource#getControl(String)}.
*
* @param controlType a String value which names the type of the
* control of this instance to be retrieved
* @return an Object which represents the control of this instance
* with the specified type if such a control is available; otherwise,
* null
*/
@Override
public Object getControl(String controlType)
{
return AbstractControls.getControl(this, controlType);
}
/**
* Implements {@link DataSource#getControls()}. Gets an array of
* Objects which represent the controls available for this
* DataSource.
*
* @return an array of Objects which represent the controls
* available for this DataSource
*/
@Override
public Object[] getControls()
{
BufferControl bufferControl = getBufferControl();
FormatControl[] formatControls = getFormatControls();
if (bufferControl == null)
return formatControls;
else if ((formatControls == null) || (formatControls.length < 1))
return new Object[] { bufferControl };
else
{
Object[] controls = new Object[1 + formatControls.length];
controls[0] = bufferControl;
System.arraycopy(
formatControls, 0,
controls, 1,
formatControls.length);
return controls;
}
}
/**
* Implements {@link DataSource#getDuration()}. Delegates to the associated
* AudioMixer because it manages the inputs and knows their
* characteristics.
*
* @return a Time value which represents the duration of the media
* being made available through this DataSource
*/
@Override
public Time getDuration()
{
return audioMixer.getDuration();
}
/**
* Implements {@link CaptureDevice#getFormatControls()}. Delegates to the
* associated AudioMixer because it knows which
* CaptureDevice is being wrapped.
*
* @return an array of FormatControls of the CaptureDevice
* of the associated AudioMixer
*/
public FormatControl[] getFormatControls()
{
return audioMixer.getFormatControls();
}
/**
* Gets the next inband DTMF tone signal.
*
* @param sampleRate The sampling frequency (codec clock rate) in Hz of the
* stream which will encapsulate this signal.
* @param sampleSizeInBits The size of each sample (8 for a byte, 16 for a
* short and 32 for an int)
* @return The data array containing the DTMF signal.
*/
public short[] getNextToneSignal(double sampleRate, int sampleSizeInBits)
{
return tones.poll().getAudioSamples(sampleRate, sampleSizeInBits);
}
/**
* Implements {@link PushBufferDataSource#getStreams()}. Gets a
* PushBufferStream which reads data from the associated
* AudioMixer and mixes its inputs.
*
* @return an array with a single PushBufferStream which reads data
* from the associated AudioMixer and mixes its inputs if this
* DataSource is connected; otherwise, an empty array
*/
@Override
public synchronized PushBufferStream[] getStreams()
{
if (connected && (outStream == null))
{
AudioMixerPushBufferStream audioMixerOutStream
= audioMixer.getOutStream();
if (audioMixerOutStream != null)
{
outStream
= new AudioMixingPushBufferStream(
audioMixerOutStream,
this);
if (started)
try
{
outStream.start();
}
catch (IOException ioex)
{
logger.error(
"Failed to start "
+ outStream.getClass().getSimpleName()
+ " with hashCode " + outStream.hashCode(),
ioex);
}
}
}
return
(outStream == null)
? new PushBufferStream[0]
: new PushBufferStream[] { outStream };
}
/**
* Determines whether this DataSource is mute.
*
* @return true if this DataSource is mute; otherwise,
* false
*/
public boolean isMute()
{
return mute;
}
/**
* Determines whether this DataSource sends a DTMF tone.
*
* @return true if this DataSource is sending a DTMF tone;
* otherwise, false.
*/
public boolean isSendingDTMF()
{
return !tones.isEmpty();
}
/**
* Sets the mute state of this DataSource.
*
* @param mute true to mute this DataSource; otherwise,
* false
*/
public void setMute(boolean mute)
{
this.mute = mute;
}
/**
* Implements {@link DataSource#start()}. Starts the output
* PushBufferStream of this DataSource (if it exists) and
* notifies the AudioMixer that one of its output
* PushBufferDataSources has been started.
*
* @throws IOException if anything wrong happens while starting the output
* PushBufferStream of this DataSource
*/
@Override
public synchronized void start()
throws IOException
{
if (!started)
{
started = true;
if (outStream != null)
outStream.start();
}
}
/**
* Implements {@link DataSource#stop()}. Notifies the AudioMixer
* that one of its output PushBufferDataSources has been stopped
* and stops the output PushBufferStream of this
* DataSource (if it exists).
*
* @throws IOException if anything wrong happens while stopping the output
* PushBufferStream of this DataSource
*/
@Override
public synchronized void stop()
throws IOException
{
if (started)
{
started = false;
if (outStream != null)
outStream.stop();
}
}
/**
* The input DataSource has been updated.
*
* @param inDataSource the DataSource that was updated.
*/
public void updateInDataSource(DataSource inDataSource)
{
// just update the input streams
audioMixer.getOutStream();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy