diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java
index 65597171c..fe4f4f7b4 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallJabberImpl.java
@@ -1401,4 +1401,32 @@ && getConference().isJitsiVideobridge())
}
return this.jitsiVideobridge;
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * Implements
+ * {@link net.java.sip.communicator.service.protocol.event.DTMFListener#toneReceived(net.java.sip.communicator.service.protocol.event.DTMFReceivedEvent)}
+ *
+ * Forwards DTMF events to the IncomingDTMF operation set, setting
+ * this Call as the source.
+ */
+ @Override
+ public void toneReceived(DTMFReceivedEvent evt)
+ {
+ OperationSetIncomingDTMF opSet
+ = getProtocolProvider()
+ .getOperationSet(OperationSetIncomingDTMF.class);
+
+ if (opSet != null && opSet instanceof OperationSetIncomingDTMFJabberImpl)
+ {
+ // Re-fire the event using this Call as the source.
+ ((OperationSetIncomingDTMFJabberImpl) opSet).toneReceived(
+ new DTMFReceivedEvent(
+ this,
+ evt.getValue(),
+ evt.getDuration(),
+ evt.getStart()));
+ }
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetIncomingDTMFJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetIncomingDTMFJabberImpl.java
new file mode 100644
index 000000000..ba2fff020
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetIncomingDTMFJabberImpl.java
@@ -0,0 +1,61 @@
+/*
+ * Jitsi, 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.protocol.jabber;
+
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+
+import java.util.*;
+
+/**
+ * Implements OperationSetIncomingDTMF for the jabber protocol.
+ *
+ * @author Boris Grozev
+ */
+public class OperationSetIncomingDTMFJabberImpl
+ implements OperationSetIncomingDTMF,
+ DTMFListener
+{
+ private final Set listeners = new HashSet();
+
+ /**
+ * {@inheritDoc}
+ *
+ * Implements
+ * {@link net.java.sip.communicator.service.protocol.OperationSetIncomingDTMF#addDTMFListener(net.java.sip.communicator.service.protocol.event.DTMFListener)}
+ */
+ @Override
+ public void addDTMFListener(DTMFListener listener)
+ {
+ listeners.add(listener);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Implements
+ * {@link net.java.sip.communicator.service.protocol.OperationSetIncomingDTMF#removeDTMFListener(net.java.sip.communicator.service.protocol.event.DTMFListener)}
+ */
+ @Override
+ public void removeDTMFListener(DTMFListener listener)
+ {
+ listeners.remove(listener);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Implements
+ * {@link net.java.sip.communicator.service.protocol.event.DTMFListener#toneReceived(net.java.sip.communicator.service.protocol.event.DTMFReceivedEvent)}
+ */
+ @Override
+ public void toneReceived(DTMFReceivedEvent evt)
+ {
+ for (DTMFListener listener : listeners)
+ listener.toneReceived(evt);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
index 3d6587095..589929b51 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
@@ -1831,10 +1831,14 @@ protected void initialize(String screenname,
}
// init DTMF
- OperationSetDTMFJabberImpl operationSetDTMFSip
+ OperationSetDTMFJabberImpl operationSetDTMF
= new OperationSetDTMFJabberImpl(this);
addSupportedOperationSet(
- OperationSetDTMF.class, operationSetDTMFSip);
+ OperationSetDTMF.class, operationSetDTMF);
+
+ addSupportedOperationSet(
+ OperationSetIncomingDTMF.class,
+ new OperationSetIncomingDTMFJabberImpl());
addJingleFeatures();
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDTMFSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDTMFSipImpl.java
index b04b4c848..07887daa1 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDTMFSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDTMFSipImpl.java
@@ -101,11 +101,11 @@ public synchronized void startSendingDTMF(CallPeer callPeer, DTMFTone tone)
}
// If the account is configured to use RTP DTMF method and the call
- // does not manage telephone events. Then, we log it for futur
+ // does not manage telephone events. Then, we log it for future
// debugging.
if(this.dtmfMethod == DTMFMethod.RTP_DTMF && !isRFC4733Active(cp))
{
- logger.debug("RTP DTMF used without telephon-event capacities");
+ logger.debug("RTP DTMF used without telephone-event capacity");
}
((AudioMediaStream)cp.getMediaHandler().getStream(MediaType.AUDIO))
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetIncomingDTMFSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetIncomingDTMFSipImpl.java
index 4cb651b1b..af16cfb2a 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetIncomingDTMFSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetIncomingDTMFSipImpl.java
@@ -10,8 +10,8 @@
import net.java.sip.communicator.service.protocol.event.*;
/**
- * An OperationSet that allows us to receive DMF tones through
- * this protocol provider.
+ * An OperationSet that allows us to receive DTMF tones through
+ * this protocol provider. Only supports SIP INFO.
*
* @author Damian Minkov
*/
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/dtmf/DTMFInfo.java b/src/net/java/sip/communicator/impl/protocol/sip/dtmf/DTMFInfo.java
index bb08186b7..f695d8574 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/dtmf/DTMFInfo.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/dtmf/DTMFInfo.java
@@ -289,7 +289,7 @@ public boolean processResponse(ResponseEvent responseEvent)
return processed;
}
- /*
+ /**
* Receives dtmf info requests.
*/
@Override
diff --git a/src/net/java/sip/communicator/service/protocol/event/DTMFReceivedEvent.java b/src/net/java/sip/communicator/service/protocol/event/DTMFReceivedEvent.java
index 84cac5eaa..c07febec4 100644
--- a/src/net/java/sip/communicator/service/protocol/event/DTMFReceivedEvent.java
+++ b/src/net/java/sip/communicator/service/protocol/event/DTMFReceivedEvent.java
@@ -8,14 +8,13 @@
import java.util.*;
-import net.java.sip.communicator.service.protocol.*;
-
import org.jitsi.service.protocol.*;
/**
* DTMFReceivedEvents indicate reception of a DTMF tone.
*
* @author Damian Minkov
+ * @author Boris Grozev
*/
public class DTMFReceivedEvent
extends EventObject
@@ -28,30 +27,77 @@ public class DTMFReceivedEvent
/**
* The tone.
*/
- private DTMFTone value = null;
+ private final DTMFTone value;
/**
* The duration.
*/
- private long duration;
+ private final long duration;
+
+ /**
+ * Whether this DTMFReceivedEvent represents the start of reception
+ * of a tone (if true), the end of reception of a tone (if
+ * false), or the reception of a tone with a given duration (if
+ * null).
+ */
+ private final Boolean start;
/**
* Creates a MessageReceivedEvent representing reception of the
* source message received from the specified from
* contact.
*
- * @param source the Message whose reception this event represents.
- * @param value dmtf tone value
- * @param duration duration of the DTMF tone
+ * @param source the source of the event.
+ * @param value dmtf tone value.
+ * @param start whether this event represents the start of reception (if
+ * true), the end of reception (if false) or the reception
+ * of a tone with a given direction (if null).
*/
- public DTMFReceivedEvent(ProtocolProviderService source,
+ public DTMFReceivedEvent(Object source,
+ DTMFTone value,
+ boolean start)
+ {
+ this(source, value, -1, start);
+ }
+
+ /**
+ * Creates a MessageReceivedEvent representing reception of the
+ * source message received from the specified from
+ * contact.
+ *
+ * @param source the source of the event.
+ * @param value dmtf tone value.
+ * @param duration duration of the DTMF tone.
+ */
+ public DTMFReceivedEvent(Object source,
DTMFTone value,
long duration)
+ {
+ this(source, value, duration, null);
+ }
+
+ /**
+ * Creates a MessageReceivedEvent representing reception of the
+ * source message received from the specified from
+ * contact.
+ *
+ * @param source the source of the event.
+ * @param value dmtf tone value.
+ * @param duration duration of the DTMF tone.
+ * @param start whether this event represents the start of reception (if
+ * true), the end of reception (if false) or the reception
+ * of a tone with a given direction (if null).
+ */
+ public DTMFReceivedEvent(Object source,
+ DTMFTone value,
+ long duration,
+ Boolean start)
{
super(source);
this.value = value;
this.duration = duration;
+ this.start = start;
}
/**
@@ -71,4 +117,16 @@ public long getDuration()
{
return duration;
}
+
+ /**
+ * Returns the value of the start attribute of this
+ * DTMFReceivedEvent, which indicates whether this
+ * DTMFReceivedEvent represents the start of reception of a tone
+ * (if true), the end of reception of a tone (if false),
+ * or the reception of a tone with a given duration (if null).
+ */
+ public Boolean getStart()
+ {
+ return start;
+ }
}
diff --git a/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java b/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java
index d1995718e..c55703ee9 100644
--- a/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java
+++ b/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java
@@ -27,7 +27,7 @@
* A utility class implementing media control code shared between current
* telephony implementations. This class is only meant for use by protocol
* implementations and should not be accessed by bundles that are simply using
- * the telephony functionalities.
+ * the telephony functionality.
*
* @param the peer extension class like for example CallPeerSipImpl
* or CallPeerJabberImpl
@@ -1806,6 +1806,11 @@ public void setMediaHandler(MediaHandler mediaHandler)
if (srtpListener != null)
this.mediaHandler.removeSrtpListener(srtpListener);
this.mediaHandler.removeVideoListener(videoStreamVideoListener);
+
+ // We intentionally do not remove our Call from the list of
+ // DTMF listeners. It should stay there as long as the
+ // MediaHandler is used by at least one CallPeer/CPMH.
+ //this.mediaHandler.removeDtmfListener(getPeer().getCall());
}
this.mediaHandler = mediaHandler;
@@ -1843,6 +1848,7 @@ public void setMediaHandler(MediaHandler mediaHandler)
if (srtpListener != null)
this.mediaHandler.addSrtpListener(srtpListener);
this.mediaHandler.addVideoListener(videoStreamVideoListener);
+ this.mediaHandler.addDtmfListener(getPeer().getCall());
}
}
}
diff --git a/src/net/java/sip/communicator/service/protocol/media/MediaAwareCall.java b/src/net/java/sip/communicator/service/protocol/media/MediaAwareCall.java
index ba32c597a..34af55d3f 100644
--- a/src/net/java/sip/communicator/service/protocol/media/MediaAwareCall.java
+++ b/src/net/java/sip/communicator/service/protocol/media/MediaAwareCall.java
@@ -12,6 +12,7 @@
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.service.protocol.event.DTMFListener;
import org.jitsi.service.neomedia.*;
import org.jitsi.service.neomedia.device.*;
import org.jitsi.service.neomedia.event.*;
@@ -41,7 +42,8 @@ public abstract class MediaAwareCall<
V extends ProtocolProviderService>
extends AbstractCall
implements CallPeerListener,
- PropertyChangeListener
+ PropertyChangeListener,
+ DTMFListener
{
/**
* The name of the property of MediaAwareCall the value of which
@@ -960,4 +962,16 @@ public void setConference(CallConference conference)
{
super.setConference(conference);
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * Implements
+ * {@link net.java.sip.communicator.service.protocol.event.DTMFListener#toneReceived(net.java.sip.communicator.service.protocol.event.DTMFReceivedEvent)}
+ */
+ @Override
+ public void toneReceived(DTMFReceivedEvent evt)
+ {
+ // Stub
+ }
}
diff --git a/src/net/java/sip/communicator/service/protocol/media/MediaHandler.java b/src/net/java/sip/communicator/service/protocol/media/MediaHandler.java
index e4de1dfb6..42e5db975 100644
--- a/src/net/java/sip/communicator/service/protocol/media/MediaHandler.java
+++ b/src/net/java/sip/communicator/service/protocol/media/MediaHandler.java
@@ -11,7 +11,9 @@
import java.util.*;
import java.util.List;
-import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.OperationFailedException;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.service.protocol.event.DTMFListener;
import net.java.sip.communicator.util.*;
import org.jitsi.service.neomedia.*;
@@ -19,6 +21,7 @@
import org.jitsi.service.neomedia.device.*;
import org.jitsi.service.neomedia.event.*;
import org.jitsi.service.neomedia.format.*;
+import org.jitsi.service.protocol.*;
import org.jitsi.util.event.*;
/**
@@ -184,6 +187,18 @@ public void securityTurnedOn(
private final List srtpListeners
= new LinkedList();
+ /**
+ * The set of listeners in the application (Jitsi) which are to
+ * be notified of DTMF events.
+ */
+ private final Set dtmfListeners
+ = new HashSet();
+
+ /**
+ * The listener registered to receive DTMF events from {@link #audioStream}.
+ */
+ private final MyDTMFListener dtmfListener = new MyDTMFListener();
+
/**
* The SimpleAudioLeveListener that this instance sets on its
* {@link #audioStream} if {@link #streamAudioLevelListeners} is not empty
@@ -444,6 +459,27 @@ void addSrtpListener(SrtpListener listener)
}
}
+ /**
+ * Adds a DTMFListener which will be notified when DTMF events
+ * are received from the MediaHandler's audio stream.
+ * @param listener the listener to add.
+ */
+ void addDtmfListener(DTMFListener listener)
+ {
+ if (listener != null)
+ dtmfListeners.add(listener);
+ }
+
+ /**
+ * Removes a DTMFListener from the set of listeners to be notified
+ * for DTMF events from this MediaHandler's audio steam.
+ * @param listener the listener to remove.
+ */
+ void removeDtmfListener(DTMFListener listener)
+ {
+ dtmfListeners.remove(listener);
+ }
+
/**
* Adds a specific SimpleAudioLevelListener to the list of
* SimpleAudioLevelListeners to be notified about changes in the
@@ -1201,6 +1237,8 @@ private void setAudioStream(AudioMediaStream audioStream)
this.audioStream.removePropertyChangeListener(
streamPropertyChangeListener);
+ this.audioStream.removeDTMFListener(dtmfListener);
+
this.audioStream.close();
}
@@ -1240,6 +1278,8 @@ private void setAudioStream(AudioMediaStream audioStream)
streamAudioLevelListener);
}
}
+
+ this.audioStream.addDTMFListener(dtmfListener);
}
else
{
@@ -1495,4 +1535,53 @@ private void setVideoStream(VideoMediaStream videoStream)
}
}
}
+
+ /**
+ * Implements a libjitsi DTMFListener, which receives
+ * events from an AudioMediaStream, translate them into
+ * Jitsi events (DTMFReceivedEvents) and forward them to
+ * any registered listeners.
+ */
+ private class MyDTMFListener
+ implements org.jitsi.service.neomedia.event.DTMFListener
+ {
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void dtmfToneReceptionStarted(DTMFToneEvent dtmfToneEvent)
+ {
+ fireEvent(
+ new DTMFReceivedEvent(
+ this,
+ DTMFTone.getDTMFTone(dtmfToneEvent.getDtmfTone().getValue()),
+ true));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void dtmfToneReceptionEnded(DTMFToneEvent dtmfToneEvent)
+ {
+ fireEvent(
+ new DTMFReceivedEvent(
+ this,
+ DTMFTone.getDTMFTone(dtmfToneEvent.getDtmfTone().getValue()),
+ false));
+ }
+
+ /**
+ * Sends an DTMFReceivedEvent to all listeners.
+ * @param event the event to send.
+ */
+ private void fireEvent(DTMFReceivedEvent event)
+ {
+ for (net.java.sip.communicator.service.protocol.event.DTMFListener
+ listener : dtmfListeners)
+ {
+ listener.toneReceived(event);
+ }
+ }
+ }
}