diff options
author | Damian Minkov <damencho@jitsi.org> | 2012-02-01 12:38:14 +0000 |
---|---|---|
committer | Damian Minkov <damencho@jitsi.org> | 2012-02-01 12:38:14 +0000 |
commit | 8e66e5a9db51c6f68d04575c9bafb9648be63f2d (patch) | |
tree | e43b59a71e4baa51c4cae3b96d1b527102dd5b91 | |
parent | ee69f66fe49880758a639a3336df1b32e7175c5d (diff) | |
download | jitsi-8e66e5a9db51c6f68d04575c9bafb9648be63f2d.zip jitsi-8e66e5a9db51c6f68d04575c9bafb9648be63f2d.tar.gz jitsi-8e66e5a9db51c6f68d04575c9bafb9648be63f2d.tar.bz2 |
Implements receiving of sip INFO dtmf tones.
8 files changed, 431 insertions, 2 deletions
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 c8ad9d9..9bd2878 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDTMFSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDTMFSipImpl.java @@ -134,4 +134,13 @@ public class OperationSetDTMFSipImpl return false; } + + /** + * Returns DTMFInfo mode implementation. + * @return DTMFInfo mode implementation. + */ + DTMFInfo getDtmfModeInfo() + { + return dtmfModeInfo; + } } diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetIncomingDTMFSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetIncomingDTMFSipImpl.java new file mode 100644 index 0000000..506ecbb --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetIncomingDTMFSipImpl.java @@ -0,0 +1,63 @@ +/* + * 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.sip; + +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; + +/** + * An <tt>OperationSet</tt> that allows us to receive DMF tones through + * this protocol provider. + * + * @author Damian Minkov + */ +public class OperationSetIncomingDTMFSipImpl + implements OperationSetIncomingDTMF +{ + /** + * The parent provider. + */ + private ProtocolProviderServiceSipImpl provider; + + /** + * The send DTMF operation set holding dtmf implementations. + */ + private OperationSetDTMFSipImpl opsetDTMFSip; + + /** + * Creates operation set. + * @param provider the parent provider + * @param opsetDTMFSip the dtmf implementation. + */ + OperationSetIncomingDTMFSipImpl(ProtocolProviderServiceSipImpl provider, + OperationSetDTMFSipImpl opsetDTMFSip) + { + this.provider = provider; + + this.opsetDTMFSip = opsetDTMFSip; + } + + /** + * Registers the specified DTMFListener with this provider so that it could + * be notified when incoming DTMF tone is received. + * @param listener the listener to register with this provider. + * + */ + public void addDTMFListener(DTMFListener listener) + { + this.opsetDTMFSip.getDtmfModeInfo().addDTMFListener(listener); + } + + /** + * Removes the specified listener from the list of DTMF listeners. + * @param listener the listener to unregister. + */ + public void removeDTMFListener(DTMFListener listener) + { + this.opsetDTMFSip.getDtmfModeInfo().removeDTMFListener(listener); + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java index c4e224d..4eeadf7 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java @@ -443,9 +443,15 @@ public class ProtocolProviderServiceSipImpl new OperationSetTelephonyConferencingSipImpl(this)); // init DTMF (from JM Heitz) + OperationSetDTMFSipImpl operationSetDTMFSip + = new OperationSetDTMFSipImpl(this); addSupportedOperationSet( - OperationSetDTMF.class, - new OperationSetDTMFSipImpl(this)); + OperationSetDTMF.class, operationSetDTMFSip); + + addSupportedOperationSet( + OperationSetIncomingDTMF.class, + new OperationSetIncomingDTMFSipImpl( + this, operationSetDTMFSip)); boolean isDesktopStreamingDisabled = SipActivator.getConfigurationService() 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 1c29751..612030f 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 @@ -8,6 +8,7 @@ package net.java.sip.communicator.impl.protocol.sip.dtmf; import gov.nist.javax.sip.header.*; +import java.io.*; import java.text.*; import java.util.*; @@ -17,6 +18,7 @@ import javax.sip.message.*; import net.java.sip.communicator.impl.protocol.sip.*; import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; /** @@ -59,6 +61,12 @@ public class DTMFInfo private final ProtocolProviderServiceSipImpl pps; /** + * A list of listeners registered for dtmf tone events. + */ + private final List<DTMFListener> dtmfListeners = + new LinkedList<DTMFListener>(); + + /** * Constructor * * @param pps the SIP Protocol provider service @@ -277,4 +285,174 @@ public class DTMFInfo } return processed; } + + /* + * Receives dtmf info requests. + */ + public boolean processRequest(RequestEvent requestEvent) + { + Request request = requestEvent.getRequest(); + + ContentTypeHeader contentTypeHeader + = (ContentTypeHeader) + request.getHeader(ContentTypeHeader.NAME); + + if ((contentTypeHeader != null) + && CONTENT_TYPE.equalsIgnoreCase( + contentTypeHeader.getContentType()) + && CONTENT_SUB_TYPE.equalsIgnoreCase( + contentTypeHeader.getContentSubType())) + { + try + { + byte[] value; + Object valueObj = request.getContent(); + + if(valueObj instanceof String) + value = ((String)valueObj).getBytes("UTF-8"); + else if(valueObj instanceof byte[]) + value = (byte[])valueObj; + else + { + logger.error("Unknown content type"); + return false; + } + + Properties prop = new Properties(); + prop.load(new ByteArrayInputStream(value)); + + String signal = prop.getProperty("Signal"); + String durationStr = prop.getProperty("Duration"); + + DTMFTone tone = DTMFTone.getDTMFTone(signal); + + if(tone == null) + { + logger.warn("Unknown tone received: " + tone); + return false; + } + + long duration = 0; + try + { + duration = Long.parseLong(durationStr); + } + catch(NumberFormatException ex) + { + logger.warn("Error parsing duration:" + durationStr, ex); + } + + // fire event + fireToneEvent(tone, duration); + } + catch(IOException ioe) + {} + + Response responseOK; + + try + { + responseOK = pps.getMessageFactory().createResponse( + Response.OK, requestEvent.getRequest()); + } + catch (ParseException ex) + { + //What else could we do apart from logging? + logger.warn("Failed to create OK for incoming INFO request", ex); + return false; + } + + try + { + SipStackSharing.getOrCreateServerTransaction(requestEvent). + sendResponse(responseOK); + } + catch(TransactionUnavailableException ex) + { + if (logger.isInfoEnabled()) + logger.info("Failed to respond to an incoming " + +"transactionless INFO request"); + if (logger.isTraceEnabled()) + logger.trace("Exception was:", ex); + return false; + } + catch (InvalidArgumentException ex) + { + //What else could we do apart from logging? + logger.warn("Failed to send OK for incoming INFO request", ex); + return false; + } + catch (SipException ex) + { + //What else could we do apart from logging? + logger.warn("Failed to send OK for incoming INFO request", ex); + return false; + } + + return true; + } + + return false; + } + + /** + * Fire event to interested listeners. + * @param tone to go into event. + * @param duration of the tone. + */ + private void fireToneEvent(DTMFTone tone, long duration) + { + Collection<DTMFListener> listeners; + synchronized (this.dtmfListeners) + { + listeners = new ArrayList<DTMFListener>(this.dtmfListeners); + } + + DTMFReceivedEvent evt = new DTMFReceivedEvent(pps, tone, duration); + + if (logger.isDebugEnabled()) + logger.debug("Dispatching DTMFTone Listeners=" + listeners.size() + + " evt=" + evt); + + try + { + for (DTMFListener listener : listeners) + { + listener.toneReceived(evt); + } + } + catch (Throwable e) + { + logger.error("Error delivering dtmf tone", e); + } + } + + /** + * Registers the specified DTMFListener with this provider so that it could + * be notified when incoming DTMF tone is received. + * @param listener the listener to register with this provider. + * + */ + public void addDTMFListener(DTMFListener listener) + { + synchronized (dtmfListeners) + { + if (!dtmfListeners.contains(listener)) + { + dtmfListeners.add(listener); + } + } + } + + /** + * Removes the specified listener from the list of DTMF listeners. + * @param listener the listener to unregister. + */ + public void removeDTMFListener(DTMFListener listener) + { + synchronized (dtmfListeners) + { + dtmfListeners.remove(listener); + } + } } diff --git a/src/net/java/sip/communicator/service/protocol/DTMFTone.java b/src/net/java/sip/communicator/service/protocol/DTMFTone.java index 9f414d3..9a1a69c 100644 --- a/src/net/java/sip/communicator/service/protocol/DTMFTone.java +++ b/src/net/java/sip/communicator/service/protocol/DTMFTone.java @@ -153,4 +153,49 @@ public final class DTMFTone return getValue().hashCode(); } + /** + * Parses input <tt>value</tt> and return the corresponding tone. + * If unknown will return null; + * @param value the input value. + * @return the corresponding tone, <tt>null</tt> for unknown. + */ + public static DTMFTone getDTMFTone(String value) + { + if(value == null) + return null; + else if(value.equals(DTMF_0.getValue())) + return DTMF_0; + else if(value.equals(DTMF_1.getValue())) + return DTMF_1; + else if(value.equals(DTMF_2.getValue())) + return DTMF_2; + else if(value.equals(DTMF_3.getValue())) + return DTMF_3; + else if(value.equals(DTMF_4.getValue())) + return DTMF_4; + else if(value.equals(DTMF_5.getValue())) + return DTMF_5; + else if(value.equals(DTMF_6.getValue())) + return DTMF_6; + else if(value.equals(DTMF_7.getValue())) + return DTMF_7; + else if(value.equals(DTMF_8.getValue())) + return DTMF_8; + else if(value.equals(DTMF_9.getValue())) + return DTMF_9; + else if(value.equals(DTMF_A.getValue())) + return DTMF_A; + else if(value.equals(DTMF_B.getValue())) + return DTMF_B; + else if(value.equals(DTMF_C.getValue())) + return DTMF_C; + else if(value.equals(DTMF_D.getValue())) + return DTMF_D; + else if(value.equals(DTMF_SHARP.getValue())) + return DTMF_SHARP; + else if(value.equals(DTMF_STAR.getValue())) + return DTMF_STAR; + else + return null; + } } diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetIncomingDTMF.java b/src/net/java/sip/communicator/service/protocol/OperationSetIncomingDTMF.java new file mode 100644 index 0000000..8218e86 --- /dev/null +++ b/src/net/java/sip/communicator/service/protocol/OperationSetIncomingDTMF.java @@ -0,0 +1,33 @@ +/* + * 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.service.protocol; + +import net.java.sip.communicator.service.protocol.event.*; + +/** + * An <tt>OperationSet</tt> that allows us to receive DTMF tones through + * this protocol provider. + * + * @author Damian Minkov + */ +public interface OperationSetIncomingDTMF + extends OperationSet +{ + /** + * Registers the specified DTMFListener with this provider so that it could + * be notified when incoming DTMF tone is received. + * @param listener the listener to register with this provider. + * + */ + public void addDTMFListener(DTMFListener listener); + + /** + * Removes the specified listener from the list of DTMF listeners. + * @param listener the listener to unregister. + */ + public void removeDTMFListener(DTMFListener listener); +} diff --git a/src/net/java/sip/communicator/service/protocol/event/DTMFListener.java b/src/net/java/sip/communicator/service/protocol/event/DTMFListener.java new file mode 100644 index 0000000..be870d6 --- /dev/null +++ b/src/net/java/sip/communicator/service/protocol/event/DTMFListener.java @@ -0,0 +1,25 @@ +/* + * 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.service.protocol.event; + +import java.util.*; + +/** + * A listener that would notify for incoming DTMF tones. + * + * @author Damian Minkov + */ +public interface DTMFListener + extends EventListener +{ + /** + * Called when a new incoming <tt>DTMFTone</tt> has been received. + * @param evt the <tt>DTMFReceivedEvent</tt> containing the newly + * received tone. + */ + public void toneReceived(DTMFReceivedEvent evt); +} diff --git a/src/net/java/sip/communicator/service/protocol/event/DTMFReceivedEvent.java b/src/net/java/sip/communicator/service/protocol/event/DTMFReceivedEvent.java new file mode 100644 index 0000000..3fb27d4 --- /dev/null +++ b/src/net/java/sip/communicator/service/protocol/event/DTMFReceivedEvent.java @@ -0,0 +1,70 @@ +/* + * 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.service.protocol.event; + +import net.java.sip.communicator.service.protocol.*; + +import java.util.*; + +/** + * <tt>DTMFReceivedEvent</tt>s indicate reception of a DTMF tone. + * + * @author Damian Minkov + */ +public class DTMFReceivedEvent + extends EventObject +{ + /** + * Serial version UID. + */ + private static final long serialVersionUID = 0L; + + /** + * The tone. + */ + private DTMFTone value = null; + + /** + * The duration. + */ + private long duration; + + /** + * Creates a <tt>MessageReceivedEvent</tt> representing reception of the + * <tt>source</tt> message received from the specified <tt>from</tt> + * contact. + * + * @param source the <tt>Message</tt> whose reception this event represents. + */ + public DTMFReceivedEvent(ProtocolProviderService source, + DTMFTone value, + long duration) + { + super(source); + + this.value = value; + this.duration = duration; + } + + /** + * Returns the tone this event is indicating of. + * @return the tone this event is indicating of. + */ + public DTMFTone getValue() + { + return value; + } + + /** + * Returns the tone duration for this event. + * @return the tone duration for this event. + */ + public long getDuration() + { + return duration; + } +} |