mirror of https://github.com/sipwise/jitsi.git
parent
022bc07d56
commit
8589c49d20
|
After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.gui.main.call;
|
||||
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import net.java.sip.communicator.impl.gui.utils.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* Represents an UI means to mute the audio stream sent to an associated
|
||||
* <tt>CallPariticant</tt>.
|
||||
*
|
||||
* @author Lubomir Marinov
|
||||
*/
|
||||
public class MuteButton
|
||||
extends JToggleButton
|
||||
{
|
||||
|
||||
/**
|
||||
* Initializes a new <tt>MuteButton</tt> instance which is to mute the audio
|
||||
* stream to a specific <tt>CallParticipant</tt>.
|
||||
*
|
||||
* @param callParticipant the <tt>CallParticipant</tt> to be associated with
|
||||
* the new instance and to have the audio stream sent to muted
|
||||
*/
|
||||
public MuteButton(CallParticipant callParticipant)
|
||||
{
|
||||
super(new ImageIcon(ImageLoader.getImage(ImageLoader.MUTE_BUTTON)));
|
||||
|
||||
setModel(new MuteButtonModel(callParticipant));
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the model of a toggle button that mutes the audio stream sent
|
||||
* to a specific <tt>CallParticipant</tt>.
|
||||
*/
|
||||
private static class MuteButtonModel
|
||||
extends ToggleButtonModel
|
||||
{
|
||||
|
||||
/**
|
||||
* The <tt>CallParticipant</tt> whose state is being adapted for the
|
||||
* purposes of depicting as a toggle button.
|
||||
*/
|
||||
private final CallParticipant callParticipant;
|
||||
|
||||
/**
|
||||
* Initializes a new <tt>MuteButtonModel</tt> instance to represent the
|
||||
* state of a specific <tt>CallParticipant</tt> as a toggle button.
|
||||
*
|
||||
* @param callParticipant the <tt>CallParticipant</tt> whose state is to
|
||||
* be represented as a toggle button
|
||||
*/
|
||||
public MuteButtonModel(CallParticipant callParticipant)
|
||||
{
|
||||
this.callParticipant = callParticipant;
|
||||
|
||||
addActionListener(new ActionListener()
|
||||
{
|
||||
|
||||
/**
|
||||
* Invoked when an action occurs.
|
||||
*
|
||||
* @param evt the <tt>ActionEvent</tt> instance containing the
|
||||
* data associated with the action and the act of its
|
||||
* performing
|
||||
*/
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
MuteButtonModel.this.actionPerformed(this, evt);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles actions performed on this model on behalf of a specific
|
||||
* <tt>ActionListener</tt>.
|
||||
*
|
||||
* @param listener the <tt>ActionListener</tt> notified about the
|
||||
* performing of the action
|
||||
* @param evt the <tt>ActionEvent</tt> containing the data associated
|
||||
* with the action and the act of its performing
|
||||
*/
|
||||
private void actionPerformed(ActionListener listener, ActionEvent evt)
|
||||
{
|
||||
Call call = callParticipant.getCall();
|
||||
|
||||
if (call != null)
|
||||
{
|
||||
OperationSetBasicTelephony telephony =
|
||||
(OperationSetBasicTelephony) call.getProtocolProvider()
|
||||
.getOperationSet(OperationSetBasicTelephony.class);
|
||||
|
||||
telephony.setMute(callParticipant, !callParticipant.isMute());
|
||||
|
||||
fireItemStateChanged(new ItemEvent(this,
|
||||
ItemEvent.ITEM_STATE_CHANGED, this,
|
||||
isSelected() ? ItemEvent.SELECTED : ItemEvent.DESELECTED));
|
||||
fireStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this model represents a state which should be
|
||||
* visualized by the currently depicting toggle button as selected.
|
||||
*/
|
||||
public boolean isSelected()
|
||||
{
|
||||
return callParticipant.isMute();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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.media;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import javax.media.*;
|
||||
import javax.media.control.*;
|
||||
import javax.media.protocol.*;
|
||||
|
||||
/**
|
||||
* Implements a <tt>PushBufferDataSource</tt> wrapper which provides mute
|
||||
* support for the wrapped instance.
|
||||
* <p>
|
||||
* Because the class wouldn't work for our use case without it,
|
||||
* <tt>CaptureDevice</tt> is implemented and is being delegated to the wrapped
|
||||
* <tt>DataSource</tt> (if it supports the interface in question).
|
||||
* </p>
|
||||
*
|
||||
* @author Lubomir Marinov
|
||||
*/
|
||||
public class MutePushBufferDataSource
|
||||
extends PushBufferDataSource
|
||||
implements CaptureDevice
|
||||
{
|
||||
|
||||
/**
|
||||
* The wrapped <tt>DataSource</tt> this instance provides mute support for.
|
||||
*/
|
||||
private final PushBufferDataSource dataSource;
|
||||
|
||||
/**
|
||||
* The indicator which determines whether this <tt>DataSource</tt> is mute.
|
||||
*/
|
||||
private boolean mute;
|
||||
|
||||
/**
|
||||
* Initializes a new <tt>MutePushBufferDataSource</tt> instance which is to
|
||||
* provide mute support for a specific <tt>PushBufferDataSource</tt>.
|
||||
*
|
||||
* @param dataSource the <tt>PushBufferDataSource</tt> the new instance is
|
||||
* to provide mute support for
|
||||
*/
|
||||
public MutePushBufferDataSource(PushBufferDataSource dataSource)
|
||||
{
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
public void connect() throws IOException
|
||||
{
|
||||
dataSource.connect();
|
||||
}
|
||||
|
||||
public void disconnect()
|
||||
{
|
||||
dataSource.disconnect();
|
||||
}
|
||||
|
||||
public CaptureDeviceInfo getCaptureDeviceInfo()
|
||||
{
|
||||
CaptureDeviceInfo captureDeviceInfo;
|
||||
|
||||
if (dataSource instanceof CaptureDevice)
|
||||
captureDeviceInfo =
|
||||
((CaptureDevice) dataSource).getCaptureDeviceInfo();
|
||||
else
|
||||
captureDeviceInfo = null;
|
||||
return captureDeviceInfo;
|
||||
}
|
||||
|
||||
public String getContentType()
|
||||
{
|
||||
return dataSource.getContentType();
|
||||
}
|
||||
|
||||
public Object getControl(String controlType)
|
||||
{
|
||||
return dataSource.getControl(controlType);
|
||||
}
|
||||
|
||||
public Object[] getControls()
|
||||
{
|
||||
return dataSource.getControls();
|
||||
}
|
||||
|
||||
public Time getDuration()
|
||||
{
|
||||
return dataSource.getDuration();
|
||||
}
|
||||
|
||||
public FormatControl[] getFormatControls()
|
||||
{
|
||||
FormatControl[] formatControls;
|
||||
|
||||
if (dataSource instanceof CaptureDevice)
|
||||
formatControls = ((CaptureDevice) dataSource).getFormatControls();
|
||||
else
|
||||
formatControls = new FormatControl[0];
|
||||
return formatControls;
|
||||
}
|
||||
|
||||
public PushBufferStream[] getStreams()
|
||||
{
|
||||
PushBufferStream[] streams = dataSource.getStreams();
|
||||
|
||||
if (streams != null)
|
||||
for (int streamIndex = 0; streamIndex < streams.length; streamIndex++)
|
||||
streams[streamIndex] =
|
||||
new MutePushBufferStream(streams[streamIndex]);
|
||||
return streams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this <tt>DataSource</tt> is mute.
|
||||
*
|
||||
* @return <tt>true</tt> if this <tt>DataSource</tt> is mute; otherwise,
|
||||
* <tt>false</tt>
|
||||
*/
|
||||
public synchronized boolean isMute()
|
||||
{
|
||||
return mute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mute state of this <tt>DataSource</tt>.
|
||||
*
|
||||
* @param mute <tt>true</tt> to mute this <tt>DataSource</tt>; otherwise,
|
||||
* <tt>false</tt>
|
||||
*/
|
||||
public synchronized void setMute(boolean mute)
|
||||
{
|
||||
this.mute = mute;
|
||||
}
|
||||
|
||||
public void start() throws IOException
|
||||
{
|
||||
dataSource.start();
|
||||
}
|
||||
|
||||
public void stop() throws IOException
|
||||
{
|
||||
dataSource.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a <tt>PushBufferStream</tt> wrapper which provides mute
|
||||
* support for the wrapped instance.
|
||||
*/
|
||||
private class MutePushBufferStream
|
||||
implements PushBufferStream
|
||||
{
|
||||
|
||||
/**
|
||||
* The wrapped stream this instance provides mute support for.
|
||||
*/
|
||||
private final PushBufferStream stream;
|
||||
|
||||
/**
|
||||
* Initializes a new <tt>MutePushBufferStream</tt> instance which is to
|
||||
* provide mute support for a specific <tt>PushBufferStream</tt>.
|
||||
*
|
||||
* @param stream the <tt>PushBufferStream</tt> the new instance is to
|
||||
* provide mute support for
|
||||
*/
|
||||
public MutePushBufferStream(PushBufferStream stream)
|
||||
{
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public ContentDescriptor getContentDescriptor()
|
||||
{
|
||||
return stream.getContentDescriptor();
|
||||
}
|
||||
|
||||
public long getContentLength()
|
||||
{
|
||||
return stream.getContentLength();
|
||||
}
|
||||
|
||||
public Object getControl(String controlType)
|
||||
{
|
||||
return stream.getControl(controlType);
|
||||
}
|
||||
|
||||
public Object[] getControls()
|
||||
{
|
||||
return stream.getControls();
|
||||
}
|
||||
|
||||
public Format getFormat()
|
||||
{
|
||||
return stream.getFormat();
|
||||
}
|
||||
|
||||
public boolean endOfStream()
|
||||
{
|
||||
return stream.endOfStream();
|
||||
}
|
||||
|
||||
public void read(Buffer buffer) throws IOException
|
||||
{
|
||||
stream.read(buffer);
|
||||
|
||||
if (isMute())
|
||||
{
|
||||
Object data = buffer.getData();
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
Class dataClass = data.getClass();
|
||||
final int fromIndex = buffer.getOffset();
|
||||
final int toIndex = fromIndex + buffer.getLength();
|
||||
|
||||
if (Format.byteArray.equals(dataClass))
|
||||
Arrays
|
||||
.fill((byte[]) data, fromIndex, toIndex, (byte) 0);
|
||||
else if (Format.intArray.equals(dataClass))
|
||||
Arrays.fill((int[]) data, fromIndex, toIndex, 0);
|
||||
else if (Format.shortArray.equals(dataClass))
|
||||
Arrays.fill((short[]) data, fromIndex, toIndex,
|
||||
(short) 0);
|
||||
|
||||
buffer.setData(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setTransferHandler(BufferTransferHandler transferHandler)
|
||||
{
|
||||
stream.setTransferHandler((transferHandler == null) ? null
|
||||
: new MuteBufferTransferHandler(transferHandler));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a <tt>BufferTransferHandler</tt> wrapper which doesn't
|
||||
* expose a wrapped <tt>PushBufferStream</tt> but rather its wrapper in
|
||||
* order to give full control to the
|
||||
* {@link PushBufferStream#read(Buffer)} method of the wrapper.
|
||||
*/
|
||||
public class MuteBufferTransferHandler
|
||||
implements BufferTransferHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* The wrapped <tt>BufferTransferHandler</tt> which receives the
|
||||
* actual events from the wrapped <tt>PushBufferStream</tt>.
|
||||
*/
|
||||
private final BufferTransferHandler transferHandler;
|
||||
|
||||
/**
|
||||
* Initializes a new <tt>MuteBufferTransferHandler</tt> instance
|
||||
* which is to overwrite the source <tt>PushBufferStream</tt> of a
|
||||
* specific <tt>BufferTransferHandler</tt>.
|
||||
*
|
||||
* @param transferHandler the <tt>BufferTransferHandler</tt> the new
|
||||
* instance is to overwrite the source
|
||||
* <tt>PushBufferStream</tt> of
|
||||
*/
|
||||
public MuteBufferTransferHandler(
|
||||
BufferTransferHandler transferHandler)
|
||||
{
|
||||
this.transferHandler = transferHandler;
|
||||
}
|
||||
|
||||
public void transferData(PushBufferStream stream)
|
||||
{
|
||||
transferHandler.transferData(MutePushBufferStream.this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Represents a default implementation of <tt>OperationSetBasicTelephony</tt> in
|
||||
* order to make it easier for implementers to provide complete solutions while
|
||||
* focusing on implementation-specific details.
|
||||
*
|
||||
* @author Lubomir Marinov
|
||||
*/
|
||||
public abstract class AbstractOperationSetBasicTelephony
|
||||
implements OperationSetBasicTelephony
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(AbstractOperationSetBasicTelephony.class);
|
||||
|
||||
/**
|
||||
* A list of listeners registered for call events.
|
||||
*/
|
||||
private final List callListeners = new Vector();
|
||||
|
||||
/**
|
||||
* Registers <tt>listener</tt> with this provider so that it
|
||||
* could be notified when incoming calls are received.
|
||||
*
|
||||
* @param listener the listener to register with this provider.
|
||||
*/
|
||||
public void addCallListener(CallListener listener)
|
||||
{
|
||||
synchronized(callListeners)
|
||||
{
|
||||
if (!callListeners.contains(listener))
|
||||
callListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and dispatches a <tt>CallEvent</tt> notifying registered
|
||||
* listeners that an event with id <tt>eventID</tt> has occurred on
|
||||
* <tt>sourceCall</tt>.
|
||||
*
|
||||
* @param eventID the ID of the event to dispatch
|
||||
* @param sourceCall the call on which the event has occurred.
|
||||
*/
|
||||
public void fireCallEvent(int eventID, Call sourceCall)
|
||||
{
|
||||
CallEvent cEvent = new CallEvent(sourceCall, eventID);
|
||||
|
||||
logger.debug("Dispatching a CallEvent to " + callListeners.size()
|
||||
+ " listeners. event is: " + cEvent.toString());
|
||||
|
||||
Iterator listeners = null;
|
||||
synchronized (callListeners)
|
||||
{
|
||||
listeners = new ArrayList(callListeners).iterator();
|
||||
}
|
||||
|
||||
while (listeners.hasNext())
|
||||
{
|
||||
CallListener listener = (CallListener) listeners.next();
|
||||
|
||||
if (eventID == CallEvent.CALL_INITIATED)
|
||||
listener.outgoingCallCreated(cEvent);
|
||||
else if (eventID == CallEvent.CALL_RECEIVED)
|
||||
listener.incomingCallReceived(cEvent);
|
||||
else if (eventID == CallEvent.CALL_ENDED)
|
||||
listener.callEnded(cEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the <tt>listener</tt> from the list of call listeners.
|
||||
*
|
||||
* @param listener the listener to unregister.
|
||||
*/
|
||||
public void removeCallListener(CallListener listener)
|
||||
{
|
||||
synchronized(callListeners)
|
||||
{
|
||||
callListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mute state of the audio stream being sent to a specific
|
||||
* <tt>CallParticipant</tt>.
|
||||
* <p>
|
||||
* The default implementation does nothing.
|
||||
* </p>
|
||||
*
|
||||
* @param participant the <tt>CallParticipant</tt> who receives the audio
|
||||
* stream to have its mute state set
|
||||
* @param mute <tt>true</tt> to mute the audio stream being sent to
|
||||
* <tt>participant</tt>; otherwise, <tt>false</tt>
|
||||
*/
|
||||
public void setMute(CallParticipant participant, boolean mute)
|
||||
{
|
||||
|
||||
/*
|
||||
* While throwing UnsupportedOperationException may be a possible
|
||||
* approach, putOnHold/putOffHold just do nothing when not supported so
|
||||
* this implementation takes inspiration from them.
|
||||
*/
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue