/*
* 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() {
}
}