diff options
author | Vincent Lucas <chenzo@jitsi.org> | 2012-02-07 10:00:54 +0000 |
---|---|---|
committer | Vincent Lucas <chenzo@jitsi.org> | 2012-02-07 10:00:54 +0000 |
commit | e0e1cc30dcb44a66630569aff98092b729dae807 (patch) | |
tree | c63a09ce2821858a5168279eb541881ab291d3d0 /src/net/java/sip | |
parent | a72eb6baf4e054f868d6d065487d9c5d16106cc3 (diff) | |
download | jitsi-e0e1cc30dcb44a66630569aff98092b729dae807.zip jitsi-e0e1cc30dcb44a66630569aff98092b729dae807.tar.gz jitsi-e0e1cc30dcb44a66630569aff98092b729dae807.tar.bz2 |
Adds in-band DTMF functionality.
Diffstat (limited to 'src/net/java/sip')
17 files changed, 985 insertions, 169 deletions
diff --git a/src/net/java/sip/communicator/impl/neomedia/AudioMediaStreamImpl.java b/src/net/java/sip/communicator/impl/neomedia/AudioMediaStreamImpl.java index c37e47b..1f2079a 100644 --- a/src/net/java/sip/communicator/impl/neomedia/AudioMediaStreamImpl.java +++ b/src/net/java/sip/communicator/impl/neomedia/AudioMediaStreamImpl.java @@ -291,6 +291,21 @@ public class AudioMediaStreamImpl } /** + * Adds a new inband DTMF tone to send. + * + * @param tone the DTMF tone to send. + */ + public void addInbandDTMF(DTMFInbandTone tone) + { + MediaDeviceSession deviceSession = getDeviceSession(); + + if (deviceSession != null) + { + deviceSession.addDTMF(tone); + } + } + + /** * In addition to calling * {@link MediaStreamImpl#addRTPExtension(byte, RTPExtension)} * this method enables sending of CSRC audio levels. The reason we are @@ -419,7 +434,6 @@ public class AudioMediaStreamImpl if(dtmfTransfrmEngine != null) { - dtmfTransfrmEngine.stop(); dtmfTransfrmEngine = null; } } diff --git a/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java b/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java index 2ab59e3..3cf6627 100644 --- a/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java +++ b/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java @@ -1287,9 +1287,10 @@ public class MediaServiceImpl (VideoMediaDeviceSession)dev.getSession(); DataSource ds = session.getCaptureDevice(); - if(ds instanceof MutePullBufferDataSource) + if(ds instanceof RewritablePullBufferDataSource) { - MutePullBufferDataSource ds2 = (MutePullBufferDataSource)ds; + RewritablePullBufferDataSource ds2 = + (RewritablePullBufferDataSource)ds; ds = ds2.getWrappedDataSource(); } diff --git a/src/net/java/sip/communicator/impl/neomedia/conference/AudioMixerPushBufferStream.java b/src/net/java/sip/communicator/impl/neomedia/conference/AudioMixerPushBufferStream.java index 25635f1..08aaf95 100644 --- a/src/net/java/sip/communicator/impl/neomedia/conference/AudioMixerPushBufferStream.java +++ b/src/net/java/sip/communicator/impl/neomedia/conference/AudioMixerPushBufferStream.java @@ -1001,7 +1001,31 @@ class AudioMixerPushBufferStream { InputStreamDesc inputStreamDesc = inputStreams[i]; - if (outputDataSource.equals(inputStreamDesc.getOutputDataSource()) + if(audioMixer.captureDevice instanceof + AudioMixingPushBufferDataSource + && inputStreamDesc.inputDataSourceDesc.inputDataSource == + audioMixer.captureDevice + && outputDataSource.isSendingDTMF()) + { + PushBufferStream inputStream + = (PushBufferStream) inputStreamDesc.getInputStream(); + AudioFormat inputStreamFormat + = (AudioFormat) inputStream.getFormat(); + + double samplingFrequency = inputStreamFormat.getSampleRate(); + int sampleSizeInBits = inputStreamFormat.getSampleSizeInBits(); + + // Generates the inband DTMF signal. + inputSamples[i] = outputDataSource.getNextToneSignal( + samplingFrequency, + sampleSizeInBits); + if(maxInputSampleCount < inputSamples[i].length) + { + maxInputSampleCount = inputSamples[i].length; + } + } + else if (outputDataSource.equals( + inputStreamDesc.getOutputDataSource()) || (outputDataSourceIsMute && (inputStreamDesc .inputDataSourceDesc diff --git a/src/net/java/sip/communicator/impl/neomedia/conference/AudioMixingPushBufferDataSource.java b/src/net/java/sip/communicator/impl/neomedia/conference/AudioMixingPushBufferDataSource.java index f94f451..b7587c6 100644 --- a/src/net/java/sip/communicator/impl/neomedia/conference/AudioMixingPushBufferDataSource.java +++ b/src/net/java/sip/communicator/impl/neomedia/conference/AudioMixingPushBufferDataSource.java @@ -8,6 +8,7 @@ package net.java.sip.communicator.impl.neomedia.conference; import java.io.*; import java.lang.reflect.*; +import java.util.*; import javax.media.*; import javax.media.control.*; @@ -15,6 +16,7 @@ import javax.media.protocol.*; import net.java.sip.communicator.impl.neomedia.control.*; import net.java.sip.communicator.impl.neomedia.protocol.*; +import net.java.sip.communicator.service.neomedia.*; import net.java.sip.communicator.util.*; /** @@ -27,7 +29,8 @@ import net.java.sip.communicator.util.*; public class AudioMixingPushBufferDataSource extends PushBufferDataSource implements CaptureDevice, - MuteDataSource + MuteDataSource, + InbandDTMFDataSource { /** @@ -70,6 +73,11 @@ public class AudioMixingPushBufferDataSource private boolean mute = false; /** + * The tones to send via inband DTMF, if not empty. + */ + private LinkedList<DTMFInbandTone> tones = new LinkedList<DTMFInbandTone>(); + + /** * Initializes a new <tt>AudioMixingPushBufferDataSource</tt> instance which * gives access to the result of the audio mixing performed by a specific * <tt>AudioMixer</tt>. @@ -363,4 +371,43 @@ public class AudioMixingPushBufferDataSource this.mute = mute; } } + + /** + * Adds a new inband DTMF tone to send. + * + * @param tone the DTMF tone to send. + */ + public void addDTMF(DTMFInbandTone tone) + { + this.tones.add(tone); + } + + /** + * Determines whether this <tt>DataSource</tt> sends a DTMF tone. + * + * @return <tt>true</tt> if this <tt>DataSource</tt> is sending a DTMF tone; + * otherwise, <tt>false</tt>. + */ + public boolean isSendingDTMF() + { + return !this.tones.isEmpty(); + } + + /** + * Gets the next inband DTMF tone signal. + * + * @param samplingFrequency 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 int[] getNextToneSignal( + double samplingFrequency, + int sampleSizeInBits) + { + DTMFInbandTone tone = tones.poll(); + return tone.getAudioSamples(samplingFrequency, sampleSizeInBits); + } } diff --git a/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java b/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java index d906509..a95b4f4 100644 --- a/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java +++ b/src/net/java/sip/communicator/impl/neomedia/device/MediaDeviceSession.java @@ -390,13 +390,13 @@ public class MediaDeviceSession if (captureDevice instanceof PushBufferDataSource) { captureDevice - = new MutePushBufferDataSource( + = new RewritablePushBufferDataSource( (PushBufferDataSource) captureDevice); } else if (captureDevice instanceof PullBufferDataSource) { captureDevice - = new MutePullBufferDataSource( + = new RewritablePullBufferDataSource( (PullBufferDataSource) captureDevice); } } @@ -1600,6 +1600,21 @@ public class MediaDeviceSession } /** + * Adds a new inband DTMF tone to send. + * + * @param tone the DTMF tone to send. + */ + public void addDTMF(DTMFInbandTone tone) + { + DataSource captureDevice = this.captureDevice; + + if (captureDevice instanceof InbandDTMFDataSource) + { + ((InbandDTMFDataSource) captureDevice).addDTMF(tone); + } + } + + /** * Adds a specific <tt>DataSource</tt> to the list of playbacks of * <tt>ReceiveStream</tt>s and/or <tt>DataSource</tt>s performed by * respective <tt>Player</tt>s on the <tt>MediaDevice</tt> represented by diff --git a/src/net/java/sip/communicator/impl/neomedia/protocol/InbandDTMFDataSource.java b/src/net/java/sip/communicator/impl/neomedia/protocol/InbandDTMFDataSource.java new file mode 100644 index 0000000..ae0f08c --- /dev/null +++ b/src/net/java/sip/communicator/impl/neomedia/protocol/InbandDTMFDataSource.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.impl.neomedia.protocol; + +import net.java.sip.communicator.service.neomedia.*; + +/** + * All datasources that support inband DTMF functionalities implement + * <tt>InbandDTMFDataSource</tt>. + * + * @author Vincent Lucas + */ +public interface InbandDTMFDataSource +{ + /** + * Adds a new inband DTMF tone to send. + * + * @param tone the DTMF tone to send. + */ + public void addDTMF(DTMFInbandTone tone); +} diff --git a/src/net/java/sip/communicator/impl/neomedia/protocol/MutePullBufferDataSource.java b/src/net/java/sip/communicator/impl/neomedia/protocol/RewritablePullBufferDataSource.java index 0a689ad..a5ac6cf 100644 --- a/src/net/java/sip/communicator/impl/neomedia/protocol/MutePullBufferDataSource.java +++ b/src/net/java/sip/communicator/impl/neomedia/protocol/RewritablePullBufferDataSource.java @@ -7,10 +7,13 @@ package net.java.sip.communicator.impl.neomedia.protocol; import java.io.*; +import java.util.*; import javax.media.*; import javax.media.protocol.*; +import net.java.sip.communicator.service.neomedia.*; + /** * Implements a <tt>PullBufferDataSource</tt> wrapper which provides mute * support for the wrapped instance. @@ -23,9 +26,10 @@ import javax.media.protocol.*; * @author Damian Minkov * @author Lubomir Marinov */ -public class MutePullBufferDataSource +public class RewritablePullBufferDataSource extends PullBufferDataSourceDelegate<PullBufferDataSource> - implements MuteDataSource + implements MuteDataSource, + InbandDTMFDataSource { /** * The indicator which determines whether this <tt>DataSource</tt> is mute. @@ -33,13 +37,18 @@ public class MutePullBufferDataSource private boolean mute; /** - * Initializes a new <tt>MutePullBufferDataSource</tt> instance which is to - * provide mute support for a specific <tt>PullBufferDataSource</tt>. + * The tones to send via inband DTMF, if not empty. + */ + private LinkedList<DTMFInbandTone> tones = new LinkedList<DTMFInbandTone>(); + + /** + * Initializes a new <tt>RewritablePullBufferDataSource</tt> instance which + * is to provide mute support for a specific <tt>PullBufferDataSource</tt>. * * @param dataSource the <tt>PullBufferDataSource</tt> the new instance is * to provide mute support for */ - public MutePullBufferDataSource(PullBufferDataSource dataSource) + public RewritablePullBufferDataSource(PullBufferDataSource dataSource) { super(dataSource); } @@ -67,6 +76,27 @@ public class MutePullBufferDataSource } /** + * Adds a new inband DTMF tone to send. + * + * @param tone the DTMF tone to send. + */ + public void addDTMF(DTMFInbandTone tone) + { + this.tones.add(tone); + } + + /** + * Determines whether this <tt>DataSource</tt> sends a DTMF tone. + * + * @return <tt>true</tt> if this <tt>DataSource</tt> is sending a DTMF tone; + * otherwise, <tt>false</tt>. + */ + public boolean isSendingDTMF() + { + return !this.tones.isEmpty(); + } + + /** * Get wrapped DataSource. * * @return wrapped DataSource @@ -130,18 +160,24 @@ public class MutePullBufferDataSource /** * Implements PullBufferStream#read(Buffer). If this instance is muted - * (through its owning MutePullBufferDataSource), overwrites the data - * read from the wrapped PullBufferStream with silence data. - * @param buffer which data will be filled. - * @throws IOException Thrown if an error occurs while reading. + * (through its owning RewritablePullBufferDataSource), overwrites the + * data read from the wrapped PullBufferStream with silence data. + * @param buffer which data will be filled. @throws IOException Thrown + * if an error occurs while reading. */ public void read(Buffer buffer) throws IOException { stream.read(buffer); - if (isMute()) - MutePushBufferDataSource.mute(buffer); + if (isSendingDTMF()) + { + RewritablePushBufferDataSource.sendDTMF(buffer, tones.poll()); + } + else if (isMute()) + { + RewritablePushBufferDataSource.mute(buffer); + } } /** diff --git a/src/net/java/sip/communicator/impl/neomedia/protocol/MutePushBufferDataSource.java b/src/net/java/sip/communicator/impl/neomedia/protocol/RewritablePushBufferDataSource.java index c604c99..57fc4ed 100644 --- a/src/net/java/sip/communicator/impl/neomedia/protocol/MutePushBufferDataSource.java +++ b/src/net/java/sip/communicator/impl/neomedia/protocol/RewritablePushBufferDataSource.java @@ -7,11 +7,17 @@ package net.java.sip.communicator.impl.neomedia.protocol; import java.io.*; +import java.nio.ByteBuffer; // disambiguation. +import java.nio.ByteOrder; // disambiguation. +import java.nio.IntBuffer; // disambiguation. import java.util.*; import javax.media.*; +import javax.media.format.*; import javax.media.protocol.*; +import net.java.sip.communicator.service.neomedia.*; + /** * Implements a <tt>PushBufferDataSource</tt> wrapper which provides mute * support for the wrapped instance. @@ -23,9 +29,10 @@ import javax.media.protocol.*; * * @author Lyubomir Marinov */ -public class MutePushBufferDataSource +public class RewritablePushBufferDataSource extends PushBufferDataSourceDelegate<PushBufferDataSource> - implements MuteDataSource + implements MuteDataSource, + InbandDTMFDataSource { /** @@ -34,13 +41,18 @@ public class MutePushBufferDataSource private boolean mute; /** - * Initializes a new <tt>MutePushBufferDataSource</tt> instance which is to - * provide mute support for a specific <tt>PushBufferDataSource</tt>. + * The tones to send via inband DTMF, if not empty. + */ + private LinkedList<DTMFInbandTone> tones = new LinkedList<DTMFInbandTone>(); + + /** + * Initializes a new <tt>RewritablePushBufferDataSource</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) + public RewritablePushBufferDataSource(PushBufferDataSource dataSource) { super(dataSource); } @@ -124,6 +136,141 @@ public class MutePushBufferDataSource } /** + * Adds a new inband DTMF tone to send. + * + * @param tone the DTMF tone to send. + */ + public void addDTMF(DTMFInbandTone tone) + { + this.tones.add(tone); + } + + /** + * Determines whether this <tt>DataSource</tt> sends a DTMF tone. + * + * @return <tt>true</tt> if this <tt>DataSource</tt> is sending a DTMF tone; + * otherwise, <tt>false</tt>. + */ + public boolean isSendingDTMF() + { + return !this.tones.isEmpty(); + } + + /** + * Replaces the media data contained in a specific <tt>Buffer</tt> with an + * inband DTMF tone signal. + * + * @param buffer the <tt>Buffer</tt> the data contained in which is to be + * replaced with the DTMF tone + * @param tone the <tt>DMFTTone</tt> to send via inband DTMF signal. + */ + public static void sendDTMF( + Buffer buffer, + DTMFInbandTone tone) + { + Object data = buffer.getData(); + + // Send the inband DTMF tone only if the buffer contains audio data. + if (data != null && (buffer.getFormat() instanceof AudioFormat)) + { + Class<?> dataClass = data.getClass(); + double audioSample; + double amplitudeCoefficient; + int fromIndex = buffer.getOffset(); + + AudioFormat audioFormat = (AudioFormat) buffer.getFormat(); + double samplingFrequency = audioFormat.getSampleRate(); + int sampleSizeInBits = audioFormat.getSampleSizeInBits(); + + // Generates the inband DTMF signal. + int[] sampleData = tone.getAudioSamples( + samplingFrequency, + sampleSizeInBits); + IntBuffer sampleDataIntBuffer = IntBuffer.wrap(sampleData); + + int toIndex = fromIndex + + sampleData.length * (sampleSizeInBits / 8); + ByteBuffer newData = ByteBuffer.allocate(toIndex); + + // Prepares newData to be endian compliant with original buffer + // data. + if(audioFormat.getEndian() == AudioFormat.BIG_ENDIAN) + { + newData.order(ByteOrder.BIG_ENDIAN); + } + else + { + newData.order(ByteOrder.LITTLE_ENDIAN); + } + + // Keeps data unchanged if storeed before the original buffer offset + // index. + // Takes care of original data array type (byte, short or int). + if (Format.byteArray.equals(dataClass)) + { + newData.put(((byte[]) data), 0, fromIndex); + } + else if (Format.shortArray.equals(dataClass)) + { + for(int i = 0; i < fromIndex; ++i) + { + newData.putShort(((short[]) data)[i]); + } + } + else if (Format.intArray.equals(dataClass)) + { + for(int i = 0; i < fromIndex; ++i) + { + newData.putInt(((int[]) data)[i]); + } + } + + // Copies inband DTMF singal into newData. + // Takes care of audio format encryption data type (byte, short or + // int). + switch (sampleSizeInBits) + { + case 8: + for(int i = 0; i < sampleData.length; ++i) + { + newData.put(((byte) sampleData[i])); + } + break; + case 16: + for(int i = 0; i < sampleData.length; ++i) + { + newData.putShort(((short) sampleData[i])); + } + break; + case 32: + for(int i = 0; i < sampleData.length; ++i) + { + newData.putInt(sampleData[i]); + } + break; + } + + // Copies newData up to date into the original buffer. + // Takes care of original data array type (byte, short or int). + if (Format.byteArray.equals(dataClass)) + { + buffer.setData(newData.array()); + } + else if (Format.shortArray.equals(dataClass)) + { + buffer.setData(newData.asShortBuffer().array()); + } + else if (Format.intArray.equals(dataClass)) + { + buffer.setData(newData.asIntBuffer().array()); + } + + // Updates the buffer length. + buffer.setLength(toIndex - fromIndex); + } + } + + /** * Implements a <tt>PushBufferStream</tt> wrapper which provides mute * support for the wrapped instance. */ @@ -157,7 +304,7 @@ public class MutePushBufferDataSource /** * Implements {@link PushBufferStream#read(Buffer)}. If this instance is - * muted (through its owning <tt>MutePushBufferDataSource</tt>), + * muted (through its owning <tt>RewritablePushBufferDataSource</tt>), * overwrites the data read from the wrapped <tt>PushBufferStream</tt> * with silence data. * @@ -171,8 +318,14 @@ public class MutePushBufferDataSource { stream.read(buffer); - if (isMute()) + if (isSendingDTMF()) + { + sendDTMF(buffer, tones.poll()); + } + else if (isMute()) + { mute(buffer); + } } /** diff --git a/src/net/java/sip/communicator/impl/neomedia/transform/dtmf/DtmfTransformEngine.java b/src/net/java/sip/communicator/impl/neomedia/transform/dtmf/DtmfTransformEngine.java index 6728c2f..510d7c3 100644 --- a/src/net/java/sip/communicator/impl/neomedia/transform/dtmf/DtmfTransformEngine.java +++ b/src/net/java/sip/communicator/impl/neomedia/transform/dtmf/DtmfTransformEngine.java @@ -81,11 +81,6 @@ public class DtmfTransformEngine DTMFTone.DTMF_SHARP, DTMFTone.DTMF_STAR}; /** - * The dispatcher that is delivering tones to the media steam. - */ - private DTMFDispatcher dtmfDispatcher = null; - - /** * The status that this engine is currently in. */ private ToneTransmissionState toneTransmissionState @@ -186,13 +181,7 @@ public class DtmfTransformEngine if(currentDtmfPayload == pkt.getPayloadType()) { DtmfRawPacket p = new DtmfRawPacket(pkt); - - if (dtmfDispatcher == null) - { - dtmfDispatcher = new DTMFDispatcher(); - new Thread(dtmfDispatcher).start(); - } - dtmfDispatcher.addTonePacket(p); + this.addTonePacket(p); // ignore received dtmf packets // if jmf receive change in rtp payload stops reception @@ -327,133 +316,33 @@ public class DtmfTransformEngine } /** - * Stops threads that this transform engine is using for even delivery. + * A packet that we should convert to tone and deliver + * to our media stream and its listeners in a separate thread. + * + * @param p the packet we will convert and deliver. */ - public void stop() + private void addTonePacket(DtmfRawPacket p) { - if(dtmfDispatcher != null) - dtmfDispatcher.stop(); + DTMFTone tone = getToneFromPacket(p); + boolean toEnd = p.isEnd(); + + mediaStream.fireDTMFEvent(tone, toEnd); } /** - * A simple thread that waits for new tones to be reported from incoming - * RTP packets and then delivers them to the <tt>AudioMediaStream</tt> - * associated with this engine. The reason we need to do this in a separate - * thread is of course the time sensitive nature of incoming RTP packets. + * Maps DTMF packet codes to our DTMFTone objects. + * @param p the packet + * @return the corresponding tone. */ - private class DTMFDispatcher - implements Runnable + private DTMFTone getToneFromPacket(DtmfRawPacket p) { - /** Indicates whether this thread is supposed to be running */ - private boolean isRunning = false; - - /** The tone that we last received from the reverseTransform thread*/ - private DTMFTone lastReceivedTone = null; - - /** The tone that we last received from the reverseTransform thread*/ - private DTMFTone lastReportedTone = null; - - /** - * Have we received end of the currently started tone. - */ - private boolean toEnd = false; - - /** - * Waits for new tone to be reported via the <tt>addTonePacket()</tt> - * method and then delivers them to the <tt>AudioMediaStream</tt> that - * we are associated with. - */ - public void run() - { - isRunning = true; - - DTMFTone temp = null; - - while(isRunning) - { - synchronized(this) - { - if(lastReceivedTone == null) - { - try - { - wait(); - } - catch (InterruptedException ie) {} - } - - temp = lastReceivedTone; - // make lastReportedLevels to null - // so we will wait for the next tone on next iteration - lastReceivedTone = null; - } - - if(temp != null - && ((lastReportedTone == null && !toEnd) - || (lastReportedTone != null && toEnd))) - { - //now notify our listener - if (mediaStream != null) - { - mediaStream.fireDTMFEvent(temp, toEnd); - if(toEnd) - lastReportedTone = null; - else - lastReportedTone = temp; - toEnd = false; - } - } - } - } - - /** - * A packet that we should convert to tone and deliver - * to our media stream and its listeners in a separate thread. - * - * @param p the packet we will convert and deliver. - */ - public void addTonePacket(DtmfRawPacket p) + for (int i = 0; i < supportedTones.length; i++) { - synchronized(this) - { - this.lastReceivedTone = getToneFromPacket(p); - this.toEnd = p.isEnd(); - - notifyAll(); - } + DTMFTone t = supportedTones[i]; + if(t.getCode() == p.getCode()) + return t; } - /** - * Causes our run method to exit so that this thread would stop - * handling levels. - */ - public void stop() - { - synchronized(this) - { - this.lastReceivedTone = null; - isRunning = false; - - notifyAll(); - } - } - - /** - * Maps DTMF packet codes to our DTMFTone objects. - * @param p the packet - * @return the corresponding tone. - */ - private DTMFTone getToneFromPacket(DtmfRawPacket p) - { - for (int i = 0; i < supportedTones.length; i++) - { - DTMFTone t = supportedTones[i]; - if(t.getCode() == p.getCode()) - return t; - } - - return null; - } + return null; } - } 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 9bd2878..92773d6 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDTMFSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetDTMFSipImpl.java @@ -24,6 +24,11 @@ public class OperationSetDTMFSipImpl implements OperationSetDTMF { /** + * The DTMF method used to send tones. + */ + private String dtmfMethod = null; + + /** * DTMF mode sending DTMF as sip info. */ private final DTMFInfo dtmfModeInfo; @@ -34,14 +39,27 @@ public class OperationSetDTMFSipImpl private final DTMF4733 dtmfModeRFC4733; /** + * DTMF sending inband tones into the audio stream. + */ + private final DTMFInband dtmfModeInband; + + /** * Constructor. * * @param pps the SIP Protocol provider service */ public OperationSetDTMFSipImpl(ProtocolProviderServiceSipImpl pps) { + AccountID accountID = pps.getAccountID(); + this.dtmfMethod = accountID.getAccountPropertyString("DTMF_METHOD"); + if(dtmfMethod == null) + { + accountID.putAccountProperty("DTMF_METHOD", "RFC4733 / SIP-INFO"); + } + dtmfModeInfo = new DTMFInfo(pps); dtmfModeRFC4733 = new DTMF4733(); + dtmfModeInband = new DTMFInband(); } /** @@ -72,16 +90,27 @@ public class OperationSetDTMFSipImpl CallPeerSipImpl cp = (CallPeerSipImpl) (callPeer); - if(isRFC4733Active(cp)) + if(this.dtmfMethod == null || + this.dtmfMethod.equals("RFC4733 / SIP-INFO")) { - dtmfModeRFC4733.startSendingDTMF( - ((AudioMediaStream)cp.getMediaHandler() - .getStream(MediaType.AUDIO)), - tone); + if(isRFC4733Active(cp)) + { + dtmfModeRFC4733.startSendingDTMF( + ((AudioMediaStream)cp.getMediaHandler() + .getStream(MediaType.AUDIO)), + tone); + } + else + { + dtmfModeInfo.startSendingDTMF(cp, tone); + } } else { - dtmfModeInfo.startSendingDTMF(cp, tone); + dtmfModeInband.addInbandDTMF( + ((AudioMediaStream)cp.getMediaHandler() + .getStream(MediaType.AUDIO)), + tone); } } @@ -103,15 +132,19 @@ public class OperationSetDTMFSipImpl CallPeerSipImpl cp = (CallPeerSipImpl) (callPeer); - if(isRFC4733Active(cp)) - { - dtmfModeRFC4733.stopSendingDTMF( - ((AudioMediaStream)cp.getMediaHandler() - .getStream(MediaType.AUDIO))); - } - else + if(this.dtmfMethod == null || + this.dtmfMethod.equals("RFC4733 / SIP-INFO")) { - dtmfModeInfo.stopSendingDTMF(cp); + if(isRFC4733Active(cp)) + { + dtmfModeRFC4733.stopSendingDTMF( + ((AudioMediaStream)cp.getMediaHandler() + .getStream(MediaType.AUDIO))); + } + else + { + dtmfModeInfo.stopSendingDTMF(cp); + } } } diff --git a/src/net/java/sip/communicator/impl/protocol/sip/dtmf/DTMFInband.java b/src/net/java/sip/communicator/impl/protocol/sip/dtmf/DTMFInband.java new file mode 100644 index 0000000..f3c7533 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/sip/dtmf/DTMFInband.java @@ -0,0 +1,30 @@ +/* + * 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.dtmf; + +import net.java.sip.communicator.service.neomedia.*; + +/** + * Sending DTMFs inband into the audio stream. + * + * @author Vincent Lucas + */ +public class DTMFInband +{ + /** + * Adds a new inband DTMF tone to send. + * + * @param audioStream The stream of this call. + * @param tone The tone (audio signal) to send via the audioStream. + */ + public void addInbandDTMF( + AudioMediaStream audioStream, + net.java.sip.communicator.service.protocol.DTMFTone tone) + { + audioStream.addInbandDTMF(DTMFInbandTone.mapTone(tone)); + } +} diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/ConnectionPanel.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/ConnectionPanel.java index c1c3b21..c18e140 100644 --- a/src/net/java/sip/communicator/plugin/sipaccregwizz/ConnectionPanel.java +++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/ConnectionPanel.java @@ -54,6 +54,13 @@ public class ConnectionPanel private JTextField keepAliveIntervalValue = new JTextField(); + private JComboBox dtmfMethodBox + = new JComboBox(new Object [] + { + "RFC4733 / SIP-INFO", + "INBAND" + }); + private boolean isServerOverridden = false; private SIPAccountRegistrationForm regform; @@ -195,8 +202,12 @@ public class ConnectionPanel voicemailField.setText(regform.getRegistration().getVoicemailURI()); mainPanel.add(Box.createVerticalStrut(5)); + mainPanel.add(createDTMFPanel()); + + mainPanel.add(Box.createVerticalStrut(5)); mainPanel.add(voicemailPanel); + this.add(mainPanel, BorderLayout.NORTH); } @@ -309,6 +320,24 @@ public class ConnectionPanel } /** + * Creates the DTMF panel. + * @return the created DTMF panel + */ + private Component createDTMFPanel() + { + JPanel dtmfPanel = new TransparentPanel(new BorderLayout(10, 10)); + JLabel dtmfMethodLabel = new JLabel( + Resources.getString("plugin.sipaccregwizz.DTMF_METHOD")); + dtmfPanel.add(dtmfMethodLabel, BorderLayout.WEST); + + dtmfMethodBox.setSelectedItem( + regform.getRegistration().getDefaultDTMFMethod()); + dtmfPanel.add(dtmfMethodBox, BorderLayout.CENTER); + + return dtmfPanel; + } + + /** * Returns the server address. * @return the server address */ @@ -491,6 +520,36 @@ public class ConnectionPanel } /** + * Returns the DTMF method. + * @return the DTMF method + */ + String getDTMFMethod() + { + Object selItem = dtmfMethodBox.getSelectedItem(); + + if(selItem != null) + return selItem.toString(); + else + return null; + } + + /** + * Sets the DTMF method. + * @param dtmfMethod the DTMF method + */ + void setDTMFMethod(String dtmfMethod) + { + if(dtmfMethod == null) + { + dtmfMethodBox.setSelectedItem(0); + } + else + { + dtmfMethodBox.setSelectedItem(dtmfMethod); + } + } + + /** * Returns the voicemail URI. * @return the voicemail URI. */ diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java index a35ceac..85b6d6a 100644 --- a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java +++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java @@ -26,6 +26,8 @@ public class SIPAccountRegistration public static String DEFAULT_KEEP_ALIVE_INTERVAL = "25"; + private String defaultDTMFMethod = "RFC4733 / SIP-INFO"; + private String id; private String password; @@ -74,6 +76,8 @@ public class SIPAccountRegistration private String keepAliveInterval = DEFAULT_KEEP_ALIVE_INTERVAL; + private String dtmfMethod = null; + private String defaultDomain = null; private boolean xCapEnable = false; @@ -431,6 +435,26 @@ public class SIPAccountRegistration } /** + * Returns the DTMF method. + * + * @return the DTMF method. + */ + public String getDTMFMethod() + { + return dtmfMethod; + } + + /** + * Sets the DTMF method. + * + * @param dtmfMethod the DTMF method to set + */ + public void setDTMFMethod(String dtmfMethod) + { + this.dtmfMethod = dtmfMethod; + } + + /** * If default call encryption is enabled * * @return If default call encryption is enabled @@ -538,6 +562,22 @@ public class SIPAccountRegistration } /** + * @return the defaultDTMFMethod + */ + public String getDefaultDTMFMethod() + { + return defaultDTMFMethod; + } + + /** + * @param defaultDTMFMethod the defaultDTMFMethod to set + */ + public void setDefaultDTMFMethod(String defaultDTMFMethod) + { + this.defaultDTMFMethod = defaultDTMFMethod; + } + + /** * @return the defaultTransport */ public String getDefaultTransport() diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java index e8c8eb9..43091c2 100644 --- a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java +++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java @@ -278,6 +278,9 @@ public class SIPAccountRegistrationForm registration.setKeepAliveInterval( connectionPanel.getKeepAliveInterval()); + registration.setDTMFMethod( + connectionPanel.getDTMFMethod()); + SIPAccRegWizzActivator.getUIService().getAccountRegWizardContainer() .setBackButtonEnabled(true); @@ -362,6 +365,9 @@ public class SIPAccountRegistrationForm accountID.getAccountPropertyString( ProtocolProviderFactory.KEEP_ALIVE_INTERVAL); + String dtmfMethod = + accountID.getAccountPropertyString("DTMF_METHOD"); + String voicemailURI = accountID.getAccountPropertyString( ProtocolProviderFactory.VOICEMAIL_URI); @@ -424,6 +430,8 @@ public class SIPAccountRegistrationForm connectionPanel.setKeepAliveMethod(keepAliveMethod); connectionPanel.setKeepAliveInterval(keepAliveInterval); + connectionPanel.setDTMFMethod(dtmfMethod); + if (voicemailURI != null && voicemailURI.length() > 0) connectionPanel.setVoicemailURI(voicemailURI); diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationWizard.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationWizard.java index 20eb967..b019797 100644 --- a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationWizard.java +++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationWizard.java @@ -262,6 +262,10 @@ public class SIPAccountRegistrationWizard Resources.getString("plugin.sipaccregwizz.KEEP_ALIVE_INTERVAL"), registration.getKeepAliveInterval()); + summaryTable.put( + Resources.getString("plugin.sipaccregwizz.DTMF_METHOD"), + registration.getDTMFMethod()); + if (registration.isXCapEnable() || registration.isXiVOEnable()) { summaryTable.put("XCAP " + Resources.getString( @@ -485,6 +489,13 @@ public class SIPAccountRegistrationWizard accountProperties.put(ProtocolProviderFactory.KEEP_ALIVE_INTERVAL, registration.getKeepAliveInterval()); + if(registration.getDTMFMethod() != null) + accountProperties.put("DTMF_METHOD", + registration.getDTMFMethod()); + else + accountProperties.put("DTMF_METHOD", + registration.getDefaultDTMFMethod()); + accountProperties.put("XIVO_ENABLE", Boolean.toString(registration.isXiVOEnable())); accountProperties.put("XCAP_ENABLE", diff --git a/src/net/java/sip/communicator/service/neomedia/AudioMediaStream.java b/src/net/java/sip/communicator/service/neomedia/AudioMediaStream.java index 17dfdf5..841aaa5 100644 --- a/src/net/java/sip/communicator/service/neomedia/AudioMediaStream.java +++ b/src/net/java/sip/communicator/service/neomedia/AudioMediaStream.java @@ -85,4 +85,11 @@ public interface AudioMediaStream * @param listener the listener that we'd like to unregister */ public void removeDTMFListener(DTMFListener listener); + + /** + * Adds a new inband DTMF tone to send. + * + * @param tone the DTMF tone to send. + */ + public void addInbandDTMF(DTMFInbandTone tone); } diff --git a/src/net/java/sip/communicator/service/neomedia/DTMFInbandTone.java b/src/net/java/sip/communicator/service/neomedia/DTMFInbandTone.java new file mode 100644 index 0000000..c265563 --- /dev/null +++ b/src/net/java/sip/communicator/service/neomedia/DTMFInbandTone.java @@ -0,0 +1,424 @@ +/* + * 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.neomedia; + +/** + * Manages the geneation of the inband DMTF signal. A signal is identified by a + * value (1, 2, 3, 4, 5, 6, 7, 8, 9, *, #, A, B, C and D) and each signal is + * producted by the composition of 2 frequencies (as defined below). + * (cf. ITU recommendation Q.23) + * + * +------------------------------------------------+ + * | | 1209 Hz | 1336 Hz | 1477 Hz | 1633 Hz | + * +------------------------------------------------+ + * | 697 Hz | 1 | 2 | 3 | A | + * | 770 Hz | 4 | 5 | 6 | B | + * | 852 Hz | 7 | 8 | 9 | C | + * | 941 Hz | * | 0 | # | D | + * +------------------------------------------------+ + * + * @author Vincent Lucas + */ + +public class DTMFInbandTone +{ + /** + * The first set of frequencies in Hz which composes an inband DTMF. + */ + private static final double[] frequencyList1 = + new double[] + { + 697.0, 770.0, 852.0, 941.0 + }; + + /** + * The second set of frequencies in Hz which composes an inband DTMF. + */ + private static final double[] frequencyList2 = + new double[] + { + 1209.0, 1336.0, 1477.0, 1633.0 + }; + + /** + * The "0" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_0 = new DTMFInbandTone("0", + frequencyList1[3], + frequencyList2[1]); + + /** + * The "1" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_1 = new DTMFInbandTone("1", + frequencyList1[0], + frequencyList2[0]); + + /** + * The "2" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_2 = new DTMFInbandTone("2", + frequencyList1[0], + frequencyList2[1]); + + /** + * The "3" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_3 = new DTMFInbandTone("3", + frequencyList1[0], + frequencyList2[2]); + + /** + * The "4" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_4 = new DTMFInbandTone("4", + frequencyList1[1], + frequencyList2[0]); + + /** + * The "5" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_5 = new DTMFInbandTone("5", + frequencyList1[1], + frequencyList2[1]); + + /** + * The "6" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_6 = new DTMFInbandTone("6", + frequencyList1[1], + frequencyList2[2]); + + /** + * The "7" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_7 = new DTMFInbandTone("7", + frequencyList1[2], + frequencyList2[0]); + + /** + * The "8" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_8 = new DTMFInbandTone("8", + frequencyList1[2], + frequencyList2[1]); + + /** + * The "9" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_9 = new DTMFInbandTone("9", + frequencyList1[2], + frequencyList2[2]); + + /** + * The "*" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_STAR = + new DTMFInbandTone("*", + frequencyList1[3], + frequencyList2[0]); + + /** + * The "#" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_SHARP = + new DTMFInbandTone("#", + frequencyList1[3], + frequencyList2[2]); + + /** + * The "A" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_A = new DTMFInbandTone("A", + frequencyList1[0], + frequencyList2[3]); + + /** + * The "B" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_B = new DTMFInbandTone("B", + frequencyList1[1], + frequencyList2[3]); + + /** + * The "C" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_C = new DTMFInbandTone("C", + frequencyList1[2], + frequencyList2[3]); + + /** + * The "D" DTMF Inband Tone. + */ + public static final DTMFInbandTone DTMF_INBAND_D = new DTMFInbandTone("D", + frequencyList1[3], + frequencyList2[3]); + + /** + * The default duration of an inband DTMF tone in ms. + * 50 ms c.f. + * http://nemesis.lonestar.org/reference/telecom/signaling/dtmf.html + * which cites the norm ANSI T1.401-1988 (but anavailable for me). + * But when testing it at 50 ms, the asterisk servers miss some DTMF tone + * impulses. Thus, set it up 150 ms. + */ + private static final int toneDuration = 150; + + /** + * The default duration of an inband DTMF tone in ms. + * 45 ms c.f. + * http://nemesis.lonestar.org/reference/telecom/signaling/dtmf.html + * which cites the norm ANSI T1.401-1988 (but anavailable for me). + * Moreover the minimum duty cycle (signal tone + silence) for + * ANSI-compliance shall be greater or equal to 100 ms. + */ + private static final int interDigitInterval = 45; + + /** + * The value which identifies the current inband tone. Available values are + * (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, *, #, A, B, C and D). + */ + private String value; + + /** + * The first frequency which composes the current inband tone. + */ + private double frequency1; + + /** + * The second frequency which composes the current inband tone. + */ + private double frequency2; + + /** + * Creates a new instance of an inband tone. The value given is the main + * identifier which determines which are the two freequencies to used to + * generate this tone. + * + * @param value The identifier of the tone. Available values are (0, 1, 2, + * 3, 4, 5, 6, 7, 8, 9, *, #, A, B, C and D). + * @param frequency1 The first frequence which composes the tone. Available + * values corresponds to DTMFInbandTone.frequencyList1. + * @param frequency2 The second frequence which composes the tone. Available + * values corresponds to DTMFInbandTone.frequencyList2. + */ + public DTMFInbandTone(String value, double frequency1, double frequency2) + { + this.value = value; + this.frequency1 = frequency1; + this.frequency2 = frequency2; + } + + /** + * Returns this tone value as a string representation. + * + * @return this tone value. + */ + public String getValue() + { + return this.value; + } + + /** + * Returns the first frequency coded by this tone. + * + * @return the first frequency coded by this tone. + */ + private double getFrequency1() + { + return this.frequency1; + } + + /** + * Returns the second frequency coded by this tone. + * + * @return the second frequency coded by this tone. + */ + private double getFrequency2() + { + return this.frequency2; + } + + /** + * Generates a sample for the current tone signal. + * + * @param samplingFrequency The sampling frequency (codec clock rate) in Hz + * of the stream which will encapsulate this signal. + * @param sampleNumber The sample number of this signal to be produced. The + * sample number corresponds to the abscissa of the signal function. + * + * @return the sample generated. This sample corresponds to the ordinate of + * the signal function + */ + public double getAudioSampleContinuous( + double samplingFrequency, + int sampleNumber) + { + double u1 = 2.0 * Math.PI * this.frequency1 / samplingFrequency; + double u2 = 2.0 * Math.PI * this.frequency2 / samplingFrequency; + double audioSample; + + // The signal generated is composed of 2 sinusoidal signals, which + // ampltudes is between -1 and 1 (included). + audioSample = Math.sin(u1 * sampleNumber) * 0.5 + + Math.sin(u2 * sampleNumber) * 0.5; + + return audioSample; + } + + /** + * Generates a sample for the current tone signal converted into a discrete + * signal. + * + * @param samplingFrequency The sampling frequency (codec clock rate) in Hz + * of the stream which will encapsulate this signal. + * @param sampleNumber The sample number of this signal to be produced. The + * sample number corresponds to the abscissa of the signal function. + * @param sampleSizeInBits The size of each sample (8 for a byte, 16 for a + * short and 32 for an int) + * + * @return the sample generated. This sample corresponds to the ordinate of + * the signal function + */ + public int getAudioSampleDiscrete( + double samplingFrequency, + int sampleNumber, + int sampleSizeInBits) + { + // If the param sampleSizeInBits is equal to 8, then its corresponds to + // a Java byte which is 8 bits signed type which contains a number + // between -128 and 127. Thus, as the result of the continuous function + // is between -1 and 1, we multiply each audioSample by 127. This + // generates a signal between -127 and 127. + // Same operation if sampleSizeInBits is equal to 16, this function + // generates a signal between -32767 and 32767. + // As well as if sampleSizeInBits is equal to 32, this function + // generates a signal between -2147483647 and 2147483647. + double amplitudeCoefficient = Math.pow(2.0, sampleSizeInBits - 1) - 1.0; + double audioSampleContinuous; + int audioSampleDiscrete; + + audioSampleContinuous = this.getAudioSampleContinuous( + samplingFrequency, + sampleNumber); + audioSampleDiscrete = (int) + (audioSampleContinuous * amplitudeCoefficient); + + return audioSampleDiscrete; + } + + /** + * Generates a signal sample for the current tone signal and stores it into + * the byte data array. + * + * @param samplingFrequency 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 int[] getAudioSamples( + double samplingFrequency, + int sampleSizeInBits) + { + int sampleNumber = 0; + + int nbToneSamples = ((int) (samplingFrequency / 1000.0)) * + DTMFInbandTone.toneDuration; + int nbInterDigitSamples = ((int) (samplingFrequency / 1000.0)) * + DTMFInbandTone.interDigitInterval; + + int[] sampleData = + new int[nbInterDigitSamples + nbToneSamples + nbInterDigitSamples]; + + while(sampleNumber < nbInterDigitSamples) + { + sampleData[sampleNumber] = 0; + ++sampleNumber; + } + while(sampleNumber < nbInterDigitSamples + nbToneSamples) + { + sampleData[sampleNumber] = getAudioSampleDiscrete( + samplingFrequency, + sampleNumber, + sampleSizeInBits); + + ++sampleNumber; + } + while(sampleNumber < sampleData.length) + { + sampleData[sampleNumber] = 0; + ++sampleNumber; + } + + return sampleData; + } + + /** + * Maps between protocol and media inband DTMF objects. + * @param tone The DTMF tone as defined in the service protocol, which is + * only composed by a value as its identifier. + * + * @return the corresponding DTMF tone which contains a value as an + * identifier and two frequencies composing the inband tone. + */ + public static DTMFInbandTone + mapTone(net.java.sip.communicator.service.protocol.DTMFTone tone) + { + if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_0)) + return DTMFInbandTone.DTMF_INBAND_0; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_1)) + return DTMFInbandTone.DTMF_INBAND_1; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_2)) + return DTMFInbandTone.DTMF_INBAND_2; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_3)) + return DTMFInbandTone.DTMF_INBAND_3; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_4)) + return DTMFInbandTone.DTMF_INBAND_4; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_5)) + return DTMFInbandTone.DTMF_INBAND_5; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_6)) + return DTMFInbandTone.DTMF_INBAND_6; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_7)) + return DTMFInbandTone.DTMF_INBAND_7; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_8)) + return DTMFInbandTone.DTMF_INBAND_8; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_9)) + return DTMFInbandTone.DTMF_INBAND_9; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_A)) + return DTMFInbandTone.DTMF_INBAND_A; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_B)) + return DTMFInbandTone.DTMF_INBAND_B; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_C)) + return DTMFInbandTone.DTMF_INBAND_C; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_D)) + return DTMFInbandTone.DTMF_INBAND_D; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_SHARP)) + return DTMFInbandTone.DTMF_INBAND_SHARP; + else if(tone.equals( + net.java.sip.communicator.service.protocol.DTMFTone.DTMF_STAR)) + return DTMFInbandTone.DTMF_INBAND_STAR; + + return null; + } +} |