I am trying to do the following
I am getting a call to another person using my java application (Already done & works fine).
Then I am playing a recording, for example "Please press 1 one to continue in english" (Already done & works fine).
Now I want to detect that person press one, As per my researches in google search I got that this can do using DTMF.If the person press 1 I want to do the actions according to my condition.
My question is how to detect that number using DTMF in java (J2SE). I am using ZTE USB dongle to make the call. Dialing, Hangup, And other controls did by using AT commands + Java IO.
Here is my example code, but it is not giving the correct dial number and its looping every time.
public class zxczczz extends javax.swing.JFrame {
/**
* Creates new form zxczczz
*/
public zxczczz() {
initComponents();
}
float[] lowFreq = new float[]{697.0F, 770.0F, 852.0F, 941.0F};
float[] highFreq = new float[]{1209.0F, 1336.0F, 1477.0F, 1633.0F};
float[] dtmfTones = new float[]{697.0F, 770.0F, 852.0F, 941.0F, 1209.0F, 1336.0F, 1477.0F, 1633.0F};
int dtmfBoard[][] = {{1, 2, 3, 12}, {4, 5, 6, 13}, {7, 8, 9, 14}, {10, 0, 11, 15}};
byte[] buffer = new byte[2048];
static final char FRAME_SIZE = 160;
AudioFormat format = getAudioFormat();
int[] buf;
public boolean wait = false;
static boolean continueParsingDtmf = false;
public AudioFormat getAudioFormat() {
// float sampleRate = 8000.0F;
float sampleRate = 44100.0F;
//int sampleSizeInBits = 16;
int sampleSizeInBits = 8;
int channels = 1;
boolean signed = true;
boolean bigEndian = true;
return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
}
public class DtmfCapture extends Thread {
public void run() {
continueParsingDtmf = true;
try {
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
TargetDataLine out = (TargetDataLine) AudioSystem.getLine(info);
out.open(format);
out.drain();
out.start();
int count = 0;
while (continueParsingDtmf) {
byte[] buffer = new byte[2048];
//grab audio data
count = out.read(buffer, 0, buffer.length);
if (count >= 0) {
zxczczz.DecodeDtmf dtmf = new zxczczz.DecodeDtmf(buffer);
if (!wait) {
dtmf.start(); //look for dtmf
// System.out.println("aaaaaa");
Thread.sleep(100);
} else {
Thread.sleep(1000);// wait before searching again
System.out.println(System.currentTimeMillis());
wait = false;
}
}
}
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class DecodeDtmf extends Thread {
byte[] buffer;
DecodeDtmf(byte[] buffer) {
this.buffer = buffer;
}
public void run() {
int[] buf;
buf = new int[buffer.length / 2];
for (int j = 0; j < buffer.length / 2 - 1; j++) {
buf[j] = (int) ((buffer[j * 2 + 1] & 0xFF) + (buffer[j * 2] << 8));
}
int tone = findDTMF(buf);
if (tone >= 0) {
wait = true;
if (tone < 10) {
System.out.println(" THE TONE IS : " + tone);
}
if (tone == 12) {
// System.out.println(" THE TONE IS : A");
// }
// if (tone == 13) {
// System.out.println(" THE TONE IS : B");
// }
// if (tone == 14) {
// System.out.println(" THE TONE IS : C");
// }
// if (tone == 15) {
// System.out.println(" THE TONE IS : D");
// }
if (tone == 10) {
// System.out.println(" THE TONE IS : *");
}
if (tone == 11) {
// System.out.println(" THE TONE IS : #");
}
}
}
/*
Check if sample has dtmf tone
*/
public int findDTMF(int[] samples) {
double[] goertzelValues = new double[8];
double lowFreqValue = 0;
int lowFreq = 0;
double sumLow = 0;
double highFreqValue = 0;
int highFreq = 0;
double sumHigh = 0;
for (int i = 0; i < 8; i++) {
goertzelValues[i] = goertzel(samples, dtmfTones[i]);
}
// System.out.println("aa="+goertzelValues);
for (int i = 0; i < 4; i++) // Find st?rste low frequency
{
sumLow += goertzelValues[i]; // Sum til signal-test
if (goertzelValues[i] > lowFreqValue) {
lowFreqValue = goertzelValues[i];
lowFreq = i;
}
// System.out.println("low = "+i);
}
for (int i = 4; i < 8; i++) // Find st?rste high frequency
{
sumHigh += goertzelValues[i]; // Sum til signal-test
if (goertzelValues[i] > highFreqValue) {
highFreqValue = goertzelValues[i];
highFreq = i - 4;
}
}
if (lowFreqValue < sumLow / 2 || highFreqValue < sumHigh / 2) // Test signalstyrke
{
return -1;
}
// System.out.println("aaa="+dtmfBoard[lowFreq][highFreq]);
return dtmfBoard[lowFreq][highFreq]; // Returner DTMF tone
}
}
public double goertzel(int[] samples, float freq) {
double vkn = 0;
double vkn1 = 0;
double vkn2 = 0;
for (int j = 0; j < samples.length - 1; j++) {
vkn2 = vkn1;
vkn1 = vkn;
vkn = 2 * Math.cos(2 * Math.PI * (freq * samples.length / format.getSampleRate()) / samples.length) * vkn1 - vkn2 + samples[j];
}
double WNk = Math.exp(-2 * Math.PI * (freq * samples.length / format.getSampleRate()) / samples.length);
//System.out.println(WNk);
return Math.abs(vkn - WNk * vkn1);
}
}
Please Help me.
i was looking for the same thing for DTMF Detection in ActionScript i found something maybe you can recode this in java
package {
import flash.utils.ByteArray;
public class DTMFprocessor
{
/*
The following constants are used to find the DTMF tones. The COL1 is the column Hz that we
are searching for, and the COL2 is the row Hz. The DTMF_LAYOUT is the order that the cols and
rows intersect at.
*/
private static const COL1:Array = [697, 770, 852, 941];
private static const COL2:Array = [1209, 1336, 1477, 1633];
private static const DTMF_LAYOUT:Array = [ ["1","2","3","A"] ,
["4","5","6","B"] ,
["7","8","9","C"] ,
["*","0","#","D"] ];
private var sampleRate:int;
private var lastFound:String = "";
public var DTMFToneSensitivity:int = 15;
/**
* DTMF Processor Constructor
*
* @param sampleRate This is the sample rate, in frames per second that the application is operating in.
*
*/
public function DTMFprocessor(sampleRate:int = 44100)
{
this.sampleRate = sampleRate;
}
/**
* Generates DTMF byteArrays that can be played by the Sound() object.
*
* @param length length, in ms that the tone will be generated for.
* @param tone the string representing the tone that will be generated [0-9, A-D, *, #]
* @return the byteArray that contains the DTMF tone.
*
*/
public function generateDTMF(length:int, tone:String):ByteArray
{
var mySound:ByteArray = new ByteArray();
var neededSamples:int = Math.floor(length * sampleRate / 1000);
var mySampleCol:Number = 0;
var mySampleRow:Number = 0;
var hz:Object = findDTMF(tone.charAt(0));
for (var i:int = 0; i < neededSamples; i++)
{
mySampleCol = Math.sin(i * hz.col * Math.PI * 2 / sampleRate) * 0.5;
mySampleRow = Math.sin(i * hz.row * Math.PI * 2 / sampleRate) * 0.5;
mySound.writeFloat(mySampleRow + mySampleCol);
}
return mySound;
}
/**
* Searches a ByteArray (from a Sound() object) for a valid DTMF tone.
*
* @param tone ByteArray that should contain a valid DTMF tone.
* @return string representation of DTMF tones. Will return a blank string ('') if nothing is found
*
*/
public function searchDTMF(tone:ByteArray):String
{
var position:int = 0;
var charFound:String = "";
// seed blank values for strongest tone to be found in the byteArray
var maxCol:int = -1;
var maxColValue:int = 0;
var maxRow:int = -1;
var maxRowValue:int = 0;
var foundTones:String = "";
// reset the byteArray to the beginning, should we have gotten it in any other state.
tone.position = position;
// break up the byteArray in manageable chunks of 8192 bytes.
for (var bufferLoop:int =0; bufferLoop < tone.bytesAvailable; bufferLoop =+ 8192)
{
position = bufferLoop;
// search for the column tone.
for (var col:int = 0; col < 4; col++)
{
if (powerDB(goertzel(tone,8192,COL1[col],position)) > maxColValue)
{
maxColValue = powerDB(goertzel(tone,8192,COL1[col],position));
maxCol = col;
}
}
// search for the row tone.
for (var row:int = 0; row < 4; row++)
{
if (powerDB(goertzel(tone,8192,COL2[row],position)) > maxRowValue)
{
maxRowValue = powerDB(goertzel(tone,8192,COL2[row],position));
maxRow = row;
}
}
// was there enough strength in both the column and row to be valid?
if ((maxColValue < DTMFToneSensitivity) || (maxRowValue < DTMFToneSensitivity))
{
charFound = "";
}
else
{
charFound = DTMF_LAYOUT[maxCol][maxRow];
}
if (lastFound != charFound)
{
trace("Found DTMF Tone:",charFound);
lastFound = charFound; // this is so we don't have duplicates.
foundTones = foundTones + lastFound;
}
}
return foundTones;
}
/**
* Converts amplitude to dB (power).
*
* @param value amplitude value
* @return dB
*
*/
private function powerDB(value:Number):Number
{
return 20 * Math.log(Math.abs(value))*Math.LOG10E;
}
/**
* This function returns the amplitude of the a seeked wave in the buffer.
*
* @param buffer the byteArray that is being searched.
* @param bufferSize the size of the buffer that we wish to search.
* @param frequency the frequency (in Hz) that we are searching for.
* @param bufferPos the starting point that we want to search from.
* @return amplitude of the searched frequency, if any.
*
*/
private function goertzel(buffer:ByteArray, bufferSize:int, frequency:int, bufferPos:int):Number
{
var skn:Number = 0;
var skn1:Number = 0;
var skn2:Number = 0;
buffer.position = bufferPos;
for (var i:int=0; i < bufferSize; i++)
{
skn2 = skn1;
skn1 = skn;
if (buffer.bytesAvailable > 0)
skn = 2 * Math.cos(2 * Math.PI * frequency / sampleRate) * skn1 - skn2 + buffer.readFloat();
}
var wnk:Number = Math.exp(-2 * Math.PI * frequency / sampleRate);
return (skn - wnk * skn1);
}
/**
* Returns the Hz of the string tone that is searched.
*
* @param tone character that is being search for
* @return an untyped object that has col and row properties that contain the Hz of the DTMF tone.
*
*/
private function findDTMF(tone:String):Object
{
var myDTMF:Object = new Object();
switch(tone)
{
case "1":
myDTMF.col = COL1[0];
myDTMF.row = COL2[0];
break;
case "2":
myDTMF.col = COL1[0];
myDTMF.row = COL2[1];
break;
case "3":
myDTMF.col = COL1[0];
myDTMF.row = COL2[2];
break;
case "A":
myDTMF.col = COL1[0];
myDTMF.row = COL2[3];
break;
case "4":
myDTMF.col = COL1[1];
myDTMF.row = COL2[0];
break;
case "5":
myDTMF.col = COL1[1];
myDTMF.row = COL2[1];
break;
case "6":
myDTMF.col = COL1[1];
myDTMF.row = COL2[2];
break;
case "B":
myDTMF.col = COL1[1];
myDTMF.row = COL2[3];
break;
case "7":
myDTMF.col = COL1[2];
myDTMF.row = COL2[0];
break;
case "8":
myDTMF.col = COL1[2];
myDTMF.row = COL2[1];
break;
case "9":
myDTMF.col = COL1[2];
myDTMF.row = COL2[2];
break;
case "C":
myDTMF.col = COL1[2];
myDTMF.row = COL2[3];
break;
case "*":
myDTMF.col = COL1[3];
myDTMF.row = COL2[0];
break;
case "0":
myDTMF.col = COL1[3];
myDTMF.row = COL2[1];
break;
case "#":
myDTMF.col = COL1[3];
myDTMF.row = COL2[2];
break;
case "D":
myDTMF.col = COL1[3];
myDTMF.row = COL2[2];
break;
default:
myDTMF.col = 0;
myDTMF.row = 0;
}
return myDTMF;
}
}
}
I don't know enough to help you out, but have you seen the DTMF implentation in TarsosDSP on github?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With