Android DTMF识别

package com.encrypt.recognizer;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.AsyncTask;

import com.android.incallui.InCallPresenter;
import com.android.incallui.Log;

public class EncryptCallKeysListnerTask extends AsyncTask<Void, Object, Void> {

    private static final int RECEIVER_KEYS_LENGTH = 4;
    private Character[] mReceiverKeys = new Character[RECEIVER_KEYS_LENGTH];
    private int mReceiverKeyIndex = 0;
    private Character mLastKey = ' ';
    AudioRecord mAudioRecord = null;

    public EncryptCallKeysListnerTask() {
    }

    @Override
    protected Void doInBackground(Void... params) {
        Log.i(this,"EncryptCall, doInBackground:");

        int blockSize = 1024;
        int sampleRateInHz = 16000;
        int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;


        int bufferSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
        mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_DOWNLINK, sampleRateInHz, channelConfig, audioFormat, bufferSize);

        try {

            mAudioRecord.startRecording();
            short[] buffer = new short[blockSize];
            StatelessRecognizer statelessRecognizer = new StatelessRecognizer();

            Log.i(this,"EncryptCall, while:"+InCallPresenter.getInstance().getIsStartListner());
            while (InCallPresenter.getInstance().getIsStartListner()) {

                int bufferReadSize = mAudioRecord.read(buffer, 0, blockSize);
                Spectrum spectrum = new Spectrum(buffer, blockSize, bufferReadSize);
                Character key = statelessRecognizer.getRecognizedKey(spectrum);

                if (!key.equals(' ')) {

                    Log.i(this,"EncryptCall, get key: "+key + ",  mReceiverKeyIndex: " + mReceiverKeyIndex);
                    if (key.equals('#')) {
                        mReceiverKeyIndex = 0;
                        continue;
                    }

                    if (!key.equals('*') && mLastKey.equals('*')) {
                        if (mReceiverKeyIndex == 0 && (key.equals('3') || key.equals('5') || key.equals('7') || key.equals('8'))) {
                            mReceiverKeys[mReceiverKeyIndex++] = key;
                        } else if ((mReceiverKeyIndex == 1 && (key.equals('7') || key.equals('9'))) ||
                                (mReceiverKeyIndex == 2 && (key.equals('5') || key.equals('8'))) ||
                                (mReceiverKeyIndex == 3 && (key.equals('6') || key.equals('9')))) {
                            mReceiverKeys[mReceiverKeyIndex++] = key;
                        } else {
                            continue;
                        }
                    }

                    if (mReceiverKeyIndex == RECEIVER_KEYS_LENGTH) {
                        if (isReceiveKeys(mReceiverKeys, InCallPresenter.getInstance().BEG_ENCRYPT_KEYS)) {

                            Log.i(this,"EncryptCall, beg keys: ");
                            // 1: play noice
                            // 2: show dialog is encrypt call or not
                            InCallPresenter.getInstance().handleReceiverKeys(InCallPresenter.getInstance().ENCRYPT_CALL_BEGING);

                        } else if (isReceiveKeys(mReceiverKeys, InCallPresenter.getInstance().ACCEPT_ENCRYPT_KEYS)) {

                            Log.i(this, "EncryptCall, accept keys: ");
                            // 1: show build encrypt UI and BUTTON
                            InCallPresenter.getInstance().handleReceiverKeys(InCallPresenter.getInstance().ENCRYPT_CALL_ONGOING);

                        } else if (isReceiveKeys(mReceiverKeys, InCallPresenter.getInstance().REJECT_ENCRYPT_KEYS)) {

                            Log.i(this, "EncryptCall, reject keys: ");
                            // 1: show build encrypt UI and BUTTON
                            InCallPresenter.getInstance().handleReceiverKeys(InCallPresenter.getInstance().ENCRYPT_CALL_REJECTED);

                        } else if (isReceiveKeys(mReceiverKeys, InCallPresenter.getInstance().STOP_ENCRYPT_KEYS)) {

                            Log.i(this, "EncryptCall, stop keys: ");
                            // 1: show build encrypt UI and BUTTON
                            InCallPresenter.getInstance().handleReceiverKeys(InCallPresenter.getInstance().ENCRYPT_CALL_CANCEL);

                        } else {
                            // 1: if UI now is build encrypt UI, return normal UI
                        }
                        mReceiverKeyIndex = 0;
                    }
                    mLastKey = key;
                }
            }

        } catch (Throwable t) {
        }

        if (mAudioRecord != null) {
            mAudioRecord.stop();
        }
        return null;
    }

    private boolean isReceiveKeys(Character[] receiverKeys, Character[] encryptKeys) {
        for (int i = 0; i < RECEIVER_KEYS_LENGTH; i++) {
            if (receiverKeys[i] != encryptKeys[i]) {
                return false;
            }
        }
        return true;
    }
}

package com.encrypt.recognizer;

import android.util.Log;

import java.util.ArrayList;
import java.util.Collection;

public class StatelessRecognizer {

    private Collection<Tone> tones;

    public StatelessRecognizer()
    {
        tones = new ArrayList<Tone>();
        
        fillTones();
    }
    
    private void fillTones() {
        tones.add(new Tone(45, 77, '1'));        
        tones.add(new Tone(45, 86, '2'));        
        tones.add(new Tone(45, 95, '3'));        
        tones.add(new Tone(49, 77, '4'));        
        tones.add(new Tone(49, 86, '5'));        
        tones.add(new Tone(49, 95, '6'));        
        tones.add(new Tone(55, 77, '7'));        
        tones.add(new Tone(55, 86, '8'));        
        tones.add(new Tone(55, 95, '9'));        
        tones.add(new Tone(60, 77, '*'));        
        tones.add(new Tone(60, 86, '0'));        
        tones.add(new Tone(60, 95, '#'));        
    }

    public char getRecognizedKey(Spectrum spectrum)
    {
        int lowMax = spectrum.getMax(0, 75);
        int highMax = spectrum.getMax(75, 150);
        int max = spectrum.getMax(0, 150);
        Log.i("hanhanhan", "match(), lowMax: " + lowMax + ",  highMax: " + highMax+",  max"+max);
        
        if(max != lowMax && max != highMax)
            return ' ';
        
        for (Tone t : tones) {
            if(t.match(lowMax, highMax))
                return t.getKey();
        }
        
        return ' ';
    }
}

package com.encrypt.recognizer;

public class Spectrum {

    private double[] block;
    private double[] spectrum;
    private int length;

    public Spectrum(short[] buffer, int blockSize, int bufferReadSize)
    {
        block = new double[blockSize];

        for (int i = 0; i < blockSize && i < bufferReadSize; i++) {
            block[i] = (double) buffer[i];
        }

        this.spectrum = FFT.magnitudeSpectrum(block);
        this.length = this.spectrum.length;
        normalize();
    }

    private void normalize() {
        double maxValue = 0.0;
        
        for(int i=0;i<length; ++i)
            if(maxValue < spectrum[i])
                maxValue = spectrum[i];
        
        if(maxValue != 0)            
            for(int i=0;i<length; ++i)
                spectrum[i] /= maxValue;
    }

    public int getMax(int start, int end) {
        int max = 0;
        double maxValue = 0;

        for(int i = start; i <= end; ++i)
            if(maxValue < get(i))
            {
                maxValue = get(i);
                max = i;
            }

        return max;
    }
    
    public double get(int index) {
        return spectrum[index];
    }
}

package com.encrypt.recognizer;

import android.util.Log;

public class Tone {
    
    private int lowFrequency;
    private int highFrequency;
    
    private char key;
    
    private static int FREQUENCY_DELTA = 2;
    
    public Tone(int lowFrequency, int highFrequency, char key)
    {
        this.lowFrequency = lowFrequency;
        this.highFrequency = highFrequency;
        this.key = key;
    }

    public char getKey()
    {
        Log.i("hanhanhan", "getKey(),  key"+key);
        return key;
    }

    public boolean match(int lowFrequency, int highFrequency)
    {
        if(matchFrequency(lowFrequency, this.lowFrequency) && matchFrequency(highFrequency, this.highFrequency)) {
            Log.i("hanhanhan", "match(), lowFrequency: " + lowFrequency + ",  highFrequency: " + highFrequency);
            return true;
        }
        
        return false;
    }
    
    private boolean matchFrequency(int frequency, int frequencyPattern)
    {
        if((frequency - frequencyPattern) * (frequency - frequencyPattern) < FREQUENCY_DELTA * FREQUENCY_DELTA) {
            return true;
        }
        
        return false;
    }

}

package com.encrypt.recognizer;

/*
 * http://www.cs.princeton.edu/introcs/97data/FFT.java.html
 * Should be optimized. w_n may be looked up from a table etc.
 *
 * Java DSP book
 */
public class FFT {
    
    private static double[] r_data = null;
    private static double[] i_data = null;
    private static boolean forward = true;
    
    public static double[] magnitudeSpectrum(double[] realPart) {

        double[] imaginaryPart = new double[realPart.length];
        
        for (int i = 0; i < imaginaryPart.length; i++) {
            imaginaryPart[i] = 0;
        }
        forwardFFT(realPart, imaginaryPart);
        
        for (int i = 0; i < realPart.length; i++) {
            realPart[i] = Math.sqrt( r_data[i]*r_data[i] + i_data[i]*i_data[i] );
        }
        
        return realPart;
    }

    public static void forwardFFT(double in_r[], double in_i[]) {
        int id;

        int localN;
        double wtemp, Wjk_r, Wjk_i, Wj_r, Wj_i;
        double theta, tempr, tempi;

        int numBits = (int)log2(in_r.length);

        // Truncate input data to a power of two
        int length = 1 << numBits; // length = 2**nu
        int n = length;
        int nby2;

        // Copy passed references to variables to be used within
        // fft routines & utilities
        r_data = in_r;
        i_data = in_i;

        bitReverse();
        for (int m = 1; m <= numBits; m++) {
            // localN = 2^m;
            localN = 1 << m;

            nby2 = localN / 2;
            Wjk_r = 1;
            Wjk_i = 0;

            theta = Math.PI / nby2;

            // for recursive comptutation of sine and cosine
            Wj_r = Math.cos(theta);
            Wj_i = -Math.sin(theta);
            if (forward == false) {
                Wj_i = -Wj_i;
            }


            for (int j = 0; j < nby2; j++) {
                // This is the FFT innermost loop
                // Any optimizations that can be made here will yield
                // great rewards.
                for (int k = j; k < n; k += localN) {
                    id = k + nby2;
                    tempr = Wjk_r * r_data[id] - Wjk_i * i_data[id];
                    tempi = Wjk_r * i_data[id] + Wjk_i * r_data[id];

                    // Zid = Zi -C
                    r_data[id] = r_data[k] - tempr;
                    i_data[id] = i_data[k] - tempi;
                    r_data[k] += tempr;
                    i_data[k] += tempi;
                }

                // (eq 6.23) and (eq 6.24)

                wtemp = Wjk_r;

                Wjk_r = Wj_r * Wjk_r - Wj_i * Wjk_i;
                Wjk_i = Wj_r * Wjk_i + Wj_i * wtemp;
            }
        }

        // normalize output of fft.
        if(false)
            for (int i = 0; i < r_data.length; i++) {
                r_data[i] = r_data[i] / (double) n;
                i_data[i] = i_data[i] / (double) n;
            }
        in_r = r_data;
        in_r = i_data;
    }
    
    private static void bitReverse() {
        int n = r_data.length;
        int j = 1;

        int k;

        for (int i = 1; i < n; i++) {

            if (i < j) swapInt(i, j);
            k = n / 2;
            while (k >= 1 && k < j) {

                j = j - k;
                k = k / 2;
            }
            j = j + k;
        }
    }

    //     swap Zi with Zj
    private static void swapInt(int i, int j) {
        double tempr;
        int ti;
        int tj;
        ti = i - 1;
        tj = j - 1;
        tempr = r_data[tj];
        r_data[tj] = r_data[ti];
        r_data[ti] = tempr;
        tempr = i_data[tj];
        i_data[tj] = i_data[ti];
        i_data[ti] = tempr;
    }

    private static double log2(double x) {
        return Math.log10(x)/Math.log10(2.0);
    }
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值