diff options
author | Lyubomir Marinov <lyubomir.marinov@jitsi.org> | 2008-07-29 03:57:32 +0000 |
---|---|---|
committer | Lyubomir Marinov <lyubomir.marinov@jitsi.org> | 2008-07-29 03:57:32 +0000 |
commit | 8589c49d206e35be1c4d549df1199a2746821a67 (patch) | |
tree | 05c1c4610b4bc74dc903484b44b4944191d1a137 /src/net/java/sip/communicator | |
parent | 022bc07d5622ce94b8aa2f35cd3ad7787c705e51 (diff) | |
download | jitsi-8589c49d206e35be1c4d549df1199a2746821a67.zip jitsi-8589c49d206e35be1c4d549df1199a2746821a67.tar.gz jitsi-8589c49d206e35be1c4d549df1199a2746821a67.tar.bz2 |
Introduces support for muting a call.
Diffstat (limited to 'src/net/java/sip/communicator')
16 files changed, 688 insertions, 219 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallParticipantPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/CallParticipantPanel.java index 0f50f21..b7da4f7 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallParticipantPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallParticipantPanel.java @@ -82,6 +82,10 @@ public class CallParticipantPanel Component holdButton = new HoldButton(this.callParticipant); holdButton.setBounds(0, 74, 36, 36); contactPanel.add(holdButton, new Integer(1)); + + Component muteButton = new MuteButton(this.callParticipant); + muteButton.setBounds(36, 74, 36, 36); + contactPanel.add(muteButton, new Integer(1)); dialButton = new DialButton(callManager, new ImageIcon(ImageLoader.getImage(ImageLoader.DIAL_BUTTON))); diff --git a/src/net/java/sip/communicator/impl/gui/main/call/MuteButton.java b/src/net/java/sip/communicator/impl/gui/main/call/MuteButton.java new file mode 100644 index 0000000..4e3a138 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/call/MuteButton.java @@ -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(); + } + } +} diff --git a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java index ee406c5..185a7a8 100644 --- a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java +++ b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java @@ -404,6 +404,11 @@ public class ImageLoader { = new ImageID("HOLD_BUTTON"); /** + * A mute button icon. The icon shown in the CallParticipant panel. + */ + public static final ImageID MUTE_BUTTON = new ImageID("MUTE_BUTTON"); + + /** * The image used, when a contact has no photo specified. */ public static final ImageID DEFAULT_USER_PHOTO diff --git a/src/net/java/sip/communicator/impl/gui/utils/images.properties b/src/net/java/sip/communicator/impl/gui/utils/images.properties index dee6334..928796a 100644 --- a/src/net/java/sip/communicator/impl/gui/utils/images.properties +++ b/src/net/java/sip/communicator/impl/gui/utils/images.properties @@ -58,6 +58,7 @@ TEXT_ITALIC_ROLLOVER_BUTTON=resources/images/impl/gui/buttons/textItalicRollover TEXT_UNDERLINED_ROLLOVER_BUTTON=resources/images/impl/gui/buttons/textUnderlinedRollover.png DIAL_BUTTON=resources/images/impl/gui/buttons/dialButton.png HOLD_BUTTON=resources/images/impl/gui/buttons/holdButton.png +MUTE_BUTTON=resources/images/impl/gui/buttons/muteButton.png INVITE_DIALOG_ICON=resources/images/impl/gui/common/inviteDialogIcon.png SEND_SMS_ICON=resources/images/impl/gui/common/gsm.png DIAL_BUTTON_BG=resources/images/impl/gui/buttons/dialButtonBg.png diff --git a/src/net/java/sip/communicator/impl/media/CallSessionImpl.java b/src/net/java/sip/communicator/impl/media/CallSessionImpl.java index ff28481..de7b45e 100644 --- a/src/net/java/sip/communicator/impl/media/CallSessionImpl.java +++ b/src/net/java/sip/communicator/impl/media/CallSessionImpl.java @@ -2370,4 +2370,25 @@ public class CallSessionImpl } } + /** + * Determines whether the audio of this session is (set to) mute. + * + * @return <tt>true</tt> if the audio of this session is (set to) mute; + * otherwise, <tt>false</tt> + */ + public boolean isMute() + { + return mediaServCallback.getMediaControl(getCall()).isMute(); + } + + /** + * Sets the mute state of the audio of this session. + * + * @param mute <tt>true</tt> to mute the audio of this session; otherwise, + * <tt>false</tt> + */ + public void setMute(boolean mute) + { + mediaServCallback.getMediaControl(getCall()).setMute(mute); + } } diff --git a/src/net/java/sip/communicator/impl/media/MediaControl.java b/src/net/java/sip/communicator/impl/media/MediaControl.java index 54f8129..1c22680 100644 --- a/src/net/java/sip/communicator/impl/media/MediaControl.java +++ b/src/net/java/sip/communicator/impl/media/MediaControl.java @@ -6,22 +6,20 @@ */ package net.java.sip.communicator.impl.media; +import java.awt.Dimension; import java.io.*; import java.net.*; +import java.util.*; import javax.media.*; +import javax.media.control.*; +import javax.media.format.*; import javax.media.protocol.*; +import javax.sdp.*; import net.java.sip.communicator.impl.media.device.*; -import net.java.sip.communicator.util.*; -import javax.sdp.*; -import net.java.sip.communicator.service.media.MediaException; -import java.util.*; import net.java.sip.communicator.service.configuration.*; -import javax.media.control.*; -import javax.media.format.*; -import javax.media.rtp.*; -import java.awt.Dimension; - +import net.java.sip.communicator.service.media.MediaException; +import net.java.sip.communicator.util.*; /** * This class is intended to provide a generic way to control media package. @@ -32,6 +30,7 @@ import java.awt.Dimension; * @author Jean Lorchat * @author Ryan Ricard * @author Ken Larson + * @author Lubomir Marinov */ public class MediaControl { @@ -58,6 +57,11 @@ public class MediaControl private DataSource avDataSource = null; /** + * The audio <tt>DataSource</tt> which provides mute support. + */ + private MutePushBufferDataSource muteAudioDataSource; + + /** * SDP Codes of all video formats that JMF supports. */ private String[] supportedVideoEncodings = new String[] @@ -172,8 +176,8 @@ public class MediaControl */ public MediaControl() { - } + /** * Returns the duration of the output data source. Usually this will be * DURATION_UNKNOWN, but if the current data source is set to an audio @@ -372,6 +376,13 @@ public class MediaControl { audioDataSource = createDataSource(audioDeviceInfo.getLocator()); audioCaptureDevice = (CaptureDevice) audioDataSource; + + /* Provide mute support for the audio (if possible). */ + if (audioDataSource instanceof PushBufferDataSource) + audioDataSource = + muteAudioDataSource = + new MutePushBufferDataSource( + (PushBufferDataSource) audioDataSource); } // video device @@ -1198,4 +1209,26 @@ public class MediaControl + currentPackagePrefix); } + /** + * Determines whether the audio of this instance is mute. + * + * @return <tt>true</tt> if the audio of this instance is mute; otherwise, + * <tt>false</tt> + */ + public boolean isMute() + { + return (muteAudioDataSource != null) && muteAudioDataSource.isMute(); + } + + /** + * Sets the mute state of the audio of this instance. + * + * @param mute <tt>true</tt> to mute the audio of this instance; + * <tt>false</tt>, otherwise + */ + public void setMute(boolean mute) + { + if (muteAudioDataSource != null) + muteAudioDataSource.setMute(mute); + } } diff --git a/src/net/java/sip/communicator/impl/media/MutePushBufferDataSource.java b/src/net/java/sip/communicator/impl/media/MutePushBufferDataSource.java new file mode 100644 index 0000000..fa14d42 --- /dev/null +++ b/src/net/java/sip/communicator/impl/media/MutePushBufferDataSource.java @@ -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); + } + } + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java index 8c14f80..6a61ff5 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicTelephonyJabberImpl.java @@ -30,8 +30,8 @@ import org.jivesoftware.smackx.packet.DiscoverInfo; * @author Symphorien Wanko */ public class OperationSetBasicTelephonyJabberImpl - implements OperationSetBasicTelephony, - RegistrationStateChangeListener, + extends AbstractOperationSetBasicTelephony + implements RegistrationStateChangeListener, JingleMediaListener, JingleTransportListener, JingleSessionRequestListener, @@ -53,11 +53,6 @@ public class OperationSetBasicTelephonyJabberImpl private ProtocolProviderServiceJabberImpl protocolProvider = null; /** - * A list of listeners registered for call events. - */ - private Vector callListeners = new Vector(); - - /** * Contains references for all currently active (non ended) calls. */ private ActiveCallsRepository activeCallsRepository @@ -135,21 +130,6 @@ public class OperationSetBasicTelephonyJabberImpl } /** - * 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); - } - } - - /** * Create a new call and invite the specified CallParticipant to it. * * @param callee the jabber address of the callee that we should invite to a @@ -296,40 +276,6 @@ public class OperationSetBasicTelephonyJabberImpl } /** - * 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. - */ - protected void fireCallEvent( int eventID, - CallJabberImpl 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); - } - } - - /** * Returns an iterator over all currently active calls. * * @return an iterator over all currently active calls. @@ -364,19 +310,6 @@ public class OperationSetBasicTelephonyJabberImpl } /** - * 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); - } - } - - /** * Implements method <tt>hangupCallParticipant</tt> * from <tt>OperationSetBasicTelephony</tt>. * diff --git a/src/net/java/sip/communicator/impl/protocol/mock/MockOperationSetBasicTelephony.java b/src/net/java/sip/communicator/impl/protocol/mock/MockOperationSetBasicTelephony.java index 43a2702..96b37d3 100644 --- a/src/net/java/sip/communicator/impl/protocol/mock/MockOperationSetBasicTelephony.java +++ b/src/net/java/sip/communicator/impl/protocol/mock/MockOperationSetBasicTelephony.java @@ -13,19 +13,13 @@ import net.java.sip.communicator.util.*; * @author Damian Minkov */ public class MockOperationSetBasicTelephony - implements OperationSetBasicTelephony, - CallChangeListener + extends AbstractOperationSetBasicTelephony + implements CallChangeListener { private static final Logger logger = Logger.getLogger(MockOperationSetBasicTelephony.class); /** - * A list of listeners registered for - * <tt>CallEvent</tt>s. - */ - private Vector callListeners = new Vector(); - - /** * A reference to the <tt>ProtocolProviderServiceSipImpl</tt> instance * that created us. */ @@ -43,19 +37,6 @@ public class MockOperationSetBasicTelephony } /** - * Registers the specified CallListener 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){ - callListeners.add(listener); - } - } - - /** * Indicates a user request to answer an incoming call from the specified * CallParticipant. * @@ -193,18 +174,6 @@ public class MockOperationSetBasicTelephony { } - /** - * Removes the specified listener from the list of call listeners. - * - * @param listener the listener to unregister. - */ - public void removeCallListener(CallListener listener) - { - synchronized(callListeners){ - callListeners.remove(listener); - } - } - public Call receiveCall(String fromAddress) throws Exception { @@ -230,38 +199,6 @@ public class MockOperationSetBasicTelephony return newCall; } - /** - * 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. - */ - protected 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 = 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); - } - } - public CallParticipant addNewCallParticipant(Call call, String address) { MockCallParticipant callPArt = new MockCallParticipant(address, (MockCall)call); diff --git a/src/net/java/sip/communicator/impl/protocol/sip/CallParticipantSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/CallParticipantSipImpl.java index 73b08d1..87b9a7a 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/CallParticipantSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/CallParticipantSipImpl.java @@ -10,6 +10,7 @@ import java.text.*; import java.util.*; import javax.sip.address.*; +import net.java.sip.communicator.service.media.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; @@ -488,4 +489,25 @@ public class CallParticipantSipImpl { this.callControlURL = callControlURL; } + + /** + * Determines whether the audio stream (if any) being sent to this + * participant is mute. + * + * @return <tt>true</tt> if an audio stream is being sent to this + * participant and it is currently mute; <tt>false</tt>, otherwise + */ + public boolean isMute() + { + CallSipImpl call = this.call; + + if (call != null) + { + CallSession callSession = call.getMediaCallSession(); + + if (callSession != null) + return callSession.isMute(); + } + return false; + } } diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java index 6eca61e..f4b85a4 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetBasicTelephonySipImpl.java @@ -27,8 +27,8 @@ import net.java.sip.communicator.util.*; * @author Lubomir Marinov */ public class OperationSetBasicTelephonySipImpl - implements OperationSetBasicTelephony - , SipListener + extends AbstractOperationSetBasicTelephony + implements SipListener { private static final Logger logger = Logger.getLogger(OperationSetBasicTelephonySipImpl.class); @@ -40,11 +40,6 @@ public class OperationSetBasicTelephonySipImpl private ProtocolProviderServiceSipImpl protocolProvider = null; /** - * A liste of listeners registered for call events. - */ - private Vector callListeners = new Vector(); - - /** * Contains references for all currently active (non ended) calls. */ private ActiveCallsRepository activeCallsRepository @@ -80,21 +75,6 @@ public class OperationSetBasicTelephonySipImpl } /** - * 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); - } - } - - /** * Create a new call and invite the specified CallParticipant to it. * * @param callee the sip address of the callee that we should invite to a @@ -309,42 +289,6 @@ public class OperationSetBasicTelephonySipImpl } /** - * 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. - */ - protected void fireCallEvent( int eventID, - CallSipImpl 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); - } - } - - /** * Returns an iterator over all currently active calls. * * @return an iterator over all currently active calls. @@ -535,19 +479,6 @@ public class OperationSetBasicTelephonySipImpl } /** - * 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); - } - } - - /** * Processes a Request received on a SipProvider upon which this SipListener * is registered. * <p> @@ -2456,4 +2387,22 @@ public class OperationSetBasicTelephonySipImpl } } } + + /** + * Sets the mute state of the audio stream being sent to a specific + * <tt>CallParticipant</tt>. + * <p> + * The implementation sends silence through the audio stream. + * </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) + { + ((CallSipImpl) participant.getCall()).getMediaCallSession().setMute( + mute); + } } diff --git a/src/net/java/sip/communicator/service/media/CallSession.java b/src/net/java/sip/communicator/service/media/CallSession.java index b83bd88..b388521 100644 --- a/src/net/java/sip/communicator/service/media/CallSession.java +++ b/src/net/java/sip/communicator/service/media/CallSession.java @@ -168,4 +168,20 @@ public interface CallSession * URL is available. */ public URL getCallInfoURL(); + + /** + * Determines whether the audio of this session is (set to) mute. + * + * @return <tt>true</tt> if the audio of this session is (set to) mute; + * otherwise, <tt>false</tt> + */ + public boolean isMute(); + + /** + * Sets the mute state of the audio of this session. + * + * @param mute <tt>true</tt> to mute the audio of this session; otherwise, + * <tt>false</tt> + */ + public void setMute(boolean mute); } diff --git a/src/net/java/sip/communicator/service/protocol/AbstractCallParticipant.java b/src/net/java/sip/communicator/service/protocol/AbstractCallParticipant.java index d38ab5c..b59d7e9 100644 --- a/src/net/java/sip/communicator/service/protocol/AbstractCallParticipant.java +++ b/src/net/java/sip/communicator/service/protocol/AbstractCallParticipant.java @@ -17,7 +17,6 @@ import net.java.sip.communicator.util.*; * The DefaultCallParticipant provides a default implementation for most of the * CallParticpant methods with the purpose of only leaving custom protocol * development to clients using the PhoneUI service. - * <p> </p> * * @author Emil Ivov */ @@ -160,4 +159,19 @@ public abstract class AbstractCallParticipant //they should override this method return null; } + + /** + * Determines whether the audio stream (if any) being sent to this + * participant is mute. + * <p> + * The default implementation returns <tt>false</tt>. + * </p> + * + * @return <tt>true</tt> if an audio stream is being sent to this + * participant and it is currently mute; <tt>false</tt>, otherwise + */ + public boolean isMute() + { + return false; + } } diff --git a/src/net/java/sip/communicator/service/protocol/AbstractOperationSetBasicTelephony.java b/src/net/java/sip/communicator/service/protocol/AbstractOperationSetBasicTelephony.java new file mode 100644 index 0000000..810a0ed --- /dev/null +++ b/src/net/java/sip/communicator/service/protocol/AbstractOperationSetBasicTelephony.java @@ -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. + */ + } +} diff --git a/src/net/java/sip/communicator/service/protocol/CallParticipant.java b/src/net/java/sip/communicator/service/protocol/CallParticipant.java index 0c18065..21b01e2 100644 --- a/src/net/java/sip/communicator/service/protocol/CallParticipant.java +++ b/src/net/java/sip/communicator/service/protocol/CallParticipant.java @@ -132,4 +132,13 @@ public interface CallParticipant * is available. */ public URL getCallInfoURL(); + + /** + * Determines whether the audio stream (if any) being sent to this + * participant is mute. + * + * @return <tt>true</tt> if an audio stream is being sent to this + * participant and it is currently mute; <tt>false</tt>, otherwise + */ + public boolean isMute(); } diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetBasicTelephony.java b/src/net/java/sip/communicator/service/protocol/OperationSetBasicTelephony.java index 34c4ff7..c8bba6b 100644 --- a/src/net/java/sip/communicator/service/protocol/OperationSetBasicTelephony.java +++ b/src/net/java/sip/communicator/service/protocol/OperationSetBasicTelephony.java @@ -14,9 +14,10 @@ import java.text.*; * An Operation Set defining all basic telephony operations such as conducting * simple calls and etc. Note that video is not considered as a part of a * supplementary operation set and if included in the service should be available - * behind the basic telephoy set. + * behind the basic telephony set. * * @author Emil Ivov + * @author Lubomir Marinov */ public interface OperationSetBasicTelephony extends OperationSet @@ -74,7 +75,7 @@ public interface OperationSetBasicTelephony /** * Indicates a user request to answer an incoming call from the specified * CallParticipant. - * @param participant the call participant that we'd like to anwer. + * @param participant the call participant that we'd like to answer. * @throws OperationFailedException with the corresponding code if we * encounter an error while performing this operation. */ @@ -106,7 +107,7 @@ public interface OperationSetBasicTelephony /** * Indicates a user request to end a call with the specified call - * particiapnt. + * participant. * @param participant the participant that we'd like to hang up on. * @throws OperationFailedException with the corresponding code if we * encounter an error while performing this operation. @@ -119,4 +120,19 @@ public interface OperationSetBasicTelephony * @return Iterator */ public Iterator getActiveCalls(); + + /** + * Sets the mute state of the audio stream being sent to a specific + * <tt>CallParticipant</tt>. + * <p> + * Muting an audio stream is implementation specific and one of the possible + * approaches to it is sending silence. + * </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); } |