/* * Mobicents, Communications Middleware * * Copyright (c) 2008, Red Hat Middleware LLC or third-party * contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Middleware LLC. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * * Boston, MA 02110-1301 USA */ package org.mobicents.media.server.impl.resource.dtmf; import org.mobicents.media.Buffer; import org.mobicents.media.Format; import org.mobicents.media.format.AudioFormat; import org.mobicents.media.server.impl.AbstractSource; import org.mobicents.media.server.spi.SyncSource; import org.mobicents.media.server.spi.dsp.Codec; import org.mobicents.media.server.spi.resource.DtmfGenerator; /** * InbandGenerator generates Inband DTMF Tone only for uncompressed LINEAR * codec. After creating instance of InbandGenerator, it needs to be initialized * so that all the Tones are generated and kept ready for transmission once * start is called. * * By default the Tone duration is 80ms. This is suited for Tone Detector who * has Tone duration of greater than 40 and less than 80ms. For Tone Detector * who's Tone duration is set greater than 80ms may fail to detect Tone * generated by InbandGenerator(with duration 80ms). In that case increase the * duration here too. * * @author Oleg Kulikov * @author amit bhayani */ public class InbandGeneratorImpl extends AbstractSource implements DtmfGenerator { private final static AudioFormat LINEAR_AUDIO = new AudioFormat( AudioFormat.LINEAR, 8000, 16, 1, AudioFormat.LITTLE_ENDIAN, AudioFormat.SIGNED); public final static String[][] events = new String[][]{ {"1", "2", "3", "A"}, {"4", "5", "6", "B"}, {"7", "8", "9", "C"}, {"*", "0", "#", "D"} }; private int[] lowFreq = new int[]{697, 770, 852, 941}; private int[] highFreq = new int[]{1209, 1336, 1477, 1633}; private String digit = null; // Min duration = 40ms and max = 500ms private int duration = 50; private short A = Short.MAX_VALUE/2; private int volume = 0; private int f1, f2; private double dt; private int pSize; private double time = 0; public InbandGeneratorImpl(String name, SyncSource syncSource) { super(name); setSyncSource(syncSource); dt = 1/LINEAR_AUDIO.getSampleRate(); } public void setDigit(String digit) { this.digit = digit; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (events[i][j].equalsIgnoreCase(digit)) { f1 = lowFreq[i]; f2 = highFreq[j]; } } } } public String getDigit() { return this.digit; } public void setToneDuration(int duration) { if (duration < 40) { throw new IllegalArgumentException("Duration cannot be less than 40ms"); } this.duration = duration; } public int getToneDuration() { return duration; } public int getVolume() { return this.volume; } public void setVolume(int volume) { if (volume > 0) { throw new IllegalArgumentException("Volume has to be negative value expressed in dBm0"); } this.volume = volume; A = (short)(Math.pow(Math.pow(10, volume), 0.1) * (Short.MAX_VALUE / 2)); } private short getValue(double t) { return (short) (A* (Math.sin(2 * Math.PI * f1 * t) + Math.sin(2*Math.PI * f2 * t))); } public Format getFormat() { return Codec.LINEAR_AUDIO; } public Format[] getFormats() { return new Format[] {LINEAR_AUDIO}; } @Override public void evolve(Buffer buffer, long timestamp, long seq) { byte[] data = (byte[])buffer.getData(); int k = 0; pSize = (int)((double)getDuration()/1000.0/dt); for (int i = 0; i < pSize; i++) { short v = getValue(time + dt * i); data[k++] = (byte) v; data[k++] = (byte) (v >> 8); } buffer.setFormat(LINEAR_AUDIO); buffer.setSequenceNumber(seq); buffer.setTimeStamp(getSyncSource().getTimestamp()); buffer.setDuration(getDuration()); buffer.setOffset(0); buffer.setLength(2*pSize); time += ((double)getDuration())/1000.0; buffer.setEOM(time > (double)duration/1000.0); } @Override public void stop() { } }