最近一年在Android手機中出現了大量的比較優秀的用聲波握手通信的應用程序,比如茄子快傳,支付寶聲波支付,還有小米的聲波握手傳輸等。其基本思路都是首先建立wifi熱點,然後用聲波通信的方法將wifi熱點name和password傳輸給對方,最後對方收到name和密碼後自動鏈接wifi熱點並傳輸各種大文件。該技術的主要難點在於聲波通信,下面是我最近寫的聲波通信程序,源代碼下載地址:http://download.csdn.net/detail/hcb1230/6442449
該代碼可以實現在兩個手機間用聲波傳輸信息。iphone上的chirp,android中的茄子快傳,支付寶聲波支付等衆多軟件都使用了聲波通信作爲握手服務。
[文件] SinVoicePlayer.java
/*
* Copyright (C) 2013 gujicheng
*
* Licensed under the GPL License Version 2.0;
* you may not use this file except in compliance with the License.
*
* If you have any question, please contact me.
*
*************************************************************************
** Author information **
*************************************************************************
** Email: [email protected] **
** QQ : 29600731 **
** Weibo: http://weibo.com/gujicheng197 **
*************************************************************************
*/
package com.libra.sinvoice;
import java.util.ArrayList;
import java.util.List;
import android.media.AudioFormat;
import android.text.TextUtils;
import com.libra.sinvoice.Buffer.BufferData;
public class SinVoicePlayer implements Encoder.Listener, Encoder.Callback, PcmPlayer.Listener, PcmPlayer.Callback {
private final static String TAG = "SinVoicePlayer";
private final static int STATE_START = 1;
private final static int STATE_STOP = 2;
private final static int STATE_PENDING = 3;
private final static int DEFAULT_GEN_DURATION = 100;
private String mCodeBook;
private List<Integer> mCodes = new ArrayList<Integer>();
private Encoder mEncoder;
private PcmPlayer mPlayer;
private Buffer mBuffer;
private int mState;
private Listener mListener;
private Thread mPlayThread;
private Thread mEncodeThread;
public static interface Listener {
void onPlayStart();
void onPlayEnd();
}
public SinVoicePlayer() {
this(Common.DEFAULT_CODE_BOOK);
}
public SinVoicePlayer(String codeBook) {
this(codeBook, Common.DEFAULT_SAMPLE_RATE, Common.DEFAULT_BUFFER_SIZE, Common.DEFAULT_BUFFER_COUNT);
}
public SinVoicePlayer(String codeBook, int sampleRate, int bufferSize, int buffCount) {
mState = STATE_STOP;
mBuffer = new Buffer(buffCount, bufferSize);
mEncoder = new Encoder(this, sampleRate, SinGenerator.BITS_16, bufferSize);
mEncoder.setListener(this);
mPlayer = new PcmPlayer(this, sampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
mPlayer.setListener(this);
setCodeBook(codeBook);
}
public void setListener(Listener listener) {
mListener = listener;
}
public void setCodeBook(String codeBook) {
if (!TextUtils.isEmpty(codeBook) && codeBook.length() < Encoder.getMaxCodeCount() - 1) {
mCodeBook = codeBook;
}
}
private boolean convertTextToCodes(String text) {
boolean ret = true;
if (!TextUtils.isEmpty(text)) {
mCodes.clear();
mCodes.add(Common.START_TOKEN);
int len = text.length();
for (int i = 0; i < len; ++i) {
char ch = text.charAt(i);
int index = mCodeBook.indexOf(ch);
if (index > -1) {
mCodes.add(index + 1);
} else {
ret = false;
LogHelper.d(TAG, "invalidate char:" + ch);
break;
}
}
if (ret) {
mCodes.add(Common.STOP_TOKEN);
}
} else {
ret = false;
}
return ret;
}
public void play(final String text) {
if (STATE_STOP == mState && null != mCodeBook && convertTextToCodes(text)) {
mState = STATE_PENDING;
mPlayThread = new Thread() {
@Override
public void run() {
mPlayer.start();
}
};
if (null != mPlayThread) {
mPlayThread.start();
}
mEncodeThread = new Thread() {
@Override
public void run() {
LogHelper.d(TAG, "encode start");
mEncoder.encode(mCodes, DEFAULT_GEN_DURATION);
LogHelper.d(TAG, "encode end");
LogHelper.d(TAG, "stop player start");
stopPlayer();
LogHelper.d(TAG, "stop player end");
mEncoder.stop();
mPlayer.stop();
}
};
if (null != mEncodeThread) {
mEncodeThread.start();
}
LogHelper.d(TAG, "play");
mState = STATE_START;
}
}
public void stop() {
if (STATE_START == mState) {
mState = STATE_PENDING;
LogHelper.d(TAG, "force stop start");
mEncoder.stop();
if (null != mEncodeThread) {
try {
mEncodeThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
mEncodeThread = null;
}
}
LogHelper.d(TAG, "force stop end");
}
}
private void stopPlayer() {
if (mEncoder.isStoped()) {
mPlayer.stop();
}
// put end buffer
mBuffer.putFull(BufferData.getEmptyBuffer());
if (null != mPlayThread) {
try {
mPlayThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
mPlayThread = null;
}
}
mBuffer.reset();
mState = STATE_STOP;
}
@Override
public void onStartEncode() {
LogHelper.d(TAG, "onStartGen");
}
@Override
public void freeEncodeBuffer(BufferData buffer) {
if (null != buffer) {
mBuffer.putFull(buffer);
}
}
@Override
public BufferData getEncodeBuffer() {
return mBuffer.getEmpty();
}
@Override
public void onEndEncode() {
}
@Override
public BufferData getPlayBuffer() {
return mBuffer.getFull();
}
@Override
public void freePlayData(BufferData data) {
mBuffer.putEmpty(data);
}
@Override
public void onPlayStart() {
if (null != mListener) {
mListener.onPlayStart();
}
}
@Override
public void onPlayStop() {
if (null != mListener) {
mListener.onPlayEnd();
}
}
}
. [文件] SinVoiceRecognition.java
/*
* Copyright (C) 2013 gujicheng
*
* Licensed under the GPL License Version 2.0;
* you may not use this file except in compliance with the License.
*
* If you have any question, please contact me.
*
*************************************************************************
** Author information **
*************************************************************************
** Email: [email protected] **
** QQ : 29600731 **
** Weibo: http://weibo.com/gujicheng197 **
*************************************************************************
*/
package com.libra.sinvoice;
import android.text.TextUtils;
import com.libra.sinvoice.Buffer.BufferData;
public class SinVoiceRecognition implements Record.Listener, Record.Callback, VoiceRecognition.Listener, VoiceRecognition.Callback {
private final static String TAG = "SinVoiceRecognition";
private final static int STATE_START = 1;
private final static int STATE_STOP = 2;
private final static int STATE_PENDING = 3;
private Buffer mBuffer;
private Record mRecord;
private VoiceRecognition mRecognition;
private Thread mRecordThread;
private Thread mRecognitionThread;
private int mState;
private Listener mListener;
private String mCodeBook;
private int mMaxCodeIndex;
public static interface Listener {
void onRecognitionStart();
void onRecognition(char ch);
void onRecognitionEnd();
}
public SinVoiceRecognition() {
this(Common.DEFAULT_CODE_BOOK);
}
public SinVoiceRecognition(String codeBook) {
this(codeBook, Common.DEFAULT_SAMPLE_RATE, Common.DEFAULT_BUFFER_SIZE, Common.DEFAULT_BUFFER_COUNT);
}
public SinVoiceRecognition(String codeBook, int sampleRate, int bufferSize, int bufferCount) {
mState = STATE_STOP;
mBuffer = new Buffer(bufferCount, bufferSize);
mRecord = new Record(this, sampleRate, Record.CHANNEL_1, Record.BITS_16, bufferSize);
mRecord.setListener(this);
mRecognition = new VoiceRecognition(this, sampleRate, Record.CHANNEL_1, Record.BITS_16);
mRecognition.setListener(this);
mMaxCodeIndex = Encoder.getMaxCodeCount() - 2;
setCodeBook(codeBook);
}
public void setListener(Listener listener) {
mListener = listener;
}
public void setCodeBook(String codeBook) {
if (!TextUtils.isEmpty(codeBook) && codeBook.length() <= mMaxCodeIndex) {
mCodeBook = codeBook;
}
}
public void start() {
if (STATE_STOP == mState) {
mState = STATE_PENDING;
mRecognitionThread = new Thread() {
@Override
public void run() {
mRecognition.start();
}
};
if (null != mRecognitionThread) {
mRecognitionThread.start();
}
mRecordThread = new Thread() {
@Override
public void run() {
mRecord.start();
LogHelper.d(TAG, "record thread end");
LogHelper.d(TAG, "stop recognition start");
stopRecognition();
LogHelper.d(TAG, "stop recognition end");
}
};
if (null != mRecordThread) {
mRecordThread.start();
}
mState = STATE_START;
}
}
private void stopRecognition() {
mRecognition.stop();
// put end buffer
BufferData data = new BufferData(0);
mBuffer.putFull(data);
if (null != mRecognitionThread) {
try {
mRecognitionThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
mRecognitionThread = null;
}
}
mBuffer.reset();
}
public void stop() {
if (STATE_START == mState) {
mState = STATE_PENDING;
LogHelper.d(TAG, "force stop start");
mRecord.stop();
if (null != mRecordThread) {
try {
mRecordThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
mRecordThread = null;
}
}
mState = STATE_STOP;
LogHelper.d(TAG, "force stop end");
}
}
@Override
public void onStartRecord() {
LogHelper.d(TAG, "start record");
}
@Override
public void onStopRecord() {
LogHelper.d(TAG, "stop record");
}
@Override
public BufferData getRecordBuffer() {
BufferData buffer = mBuffer.getEmpty();
if (null == buffer) {
LogHelper.d(TAG, "get null empty buffer");
}
return buffer;
}
@Override
public void freeRecordBuffer(BufferData buffer) {
if (null != buffer) {
if (!mBuffer.putFull(buffer)) {
LogHelper.d(TAG, "put full buffer failed");
}
}
}
@Override
public BufferData getRecognitionBuffer() {
BufferData buffer = mBuffer.getFull();
if (null == buffer) {
LogHelper.d(TAG, "get null full buffer");
}
return buffer;
}
@Override
public void freeRecognitionBuffer(BufferData buffer) {
if (null != buffer) {
if (!mBuffer.putEmpty(buffer)) {
LogHelper.d(TAG, "put empty buffer failed");
}
}
}
@Override
public void onStartRecognition() {
LogHelper.d(TAG, "start recognition");
}
@Override
public void onRecognition(int index) {
LogHelper.d(TAG, "zzzzzzzzzzzzzrecognition:" + index);
if (null != mListener) {
if (Common.START_TOKEN == index) {
mListener.onRecognitionStart();
} else if (Common.STOP_TOKEN == index) {
mListener.onRecognitionEnd();
} else if (index > 0 && index <= mMaxCodeIndex) {
mListener.onRecognition(mCodeBook.charAt(index - 1));
}
}
}
@Override
public void onStopRecognition() {
LogHelper.d(TAG, "stop recognition");
}
}