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);
}
}
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);
}
}