【Android开发经验】移动设备的“声波通信/验证”的实现——SinVoice开源项目介绍(一)

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992

在APP市场上,经常有一些充满新意的应用让我们眼前一亮,比如微信的面对面加好友,支付宝的声波支付等等,都是通过声波的方式进行握手通信,今天这篇文章将介绍声波通信和声波验证的实现原理和代码实现。

首先介绍一下声波验证的原理。如果我们想发出声音,就必须震动,说话是声带在震动,手机能播放音乐是喇叭在震动。既然发出声音必须震动,那么就有震动快慢之分,我们把震动的快慢叫做声音的频率。频率低的声音低沉有力,能传播很远的距离,比如说大象之间通信就是利用次声波,也就是频率很低的声波进行的。而蝙蝠,我们都知道是通过超声波进行探路的,超声波就是震动频率比较高的声音。频率太高或者太低,人的耳朵都听不到,人耳的识别范围是20HZ-20000HZ。这里引出了一个单位,叫做赫兹(HZ),它是指一秒钟的震动次数。

知道什么是声音的频率之后,我们就可以开始介绍声波通信的原理了。既然不同的声音有不同的频率,那么我们就可以假设1000HZ的声音代表1,2000HZ的声音代表2,以此类推,我们就可以用不同的频率代表不同的数字组合。在接收到声波之后,再根据不同的频率解析成我们需要的数据就好。

如果我们想发出单频率的声音,我们就需要自己构造特定频率的正弦函数。手机喇叭在震动的时候,实际上是根据不同的电流带动鼓纸,进行不同频率的震动才发出声音的。而如果我们想要发出1000HZ的声音,我们就需要设计对应的正弦函数,来提供一定规律的电流。

既然说到我们要自己设计正弦函数,还有几个名词我要解释一下:

1.采样率

是指每一秒要采集的声音的次数。因为平常我们说话的时候,产生的是模拟信号,就是时间连续的信号,如果我们想把语音录制下来怎么办呢?我们是做不到完完全全的都录制下来的,我们只能每隔一段时间采集一次数据,将模拟信号转化成数字信号,因此,采样点的多少就影响到语音的质量了。如果采样点多,那么质量就高,听起来就和原声的差别小;相对的,采样点少,质量就次,听起来就和原声不一样。这就是采样率的作用。

2.采样定理

上面说道,如果采样率高,录音的质量就高,那么,是不是采样率越高越好呢?当然不是。随着采样率的提高,虽然质量提高了,但是采样的难度也对应的增加了,而且,采样出来的数据需要存储,采样率越高,产生的数据文件就越大,因此质量高的音乐比一般的音乐体积大。所以,我们通常要选用一个合适的采样率。在信号处理领域有一个定理叫做“采样定理”,也称“奈奎斯特定理”,内容是:如果采样的频率高于信号最高频率的两倍,采样之后的数字信号就可以完整的保留下原始信号中的信息。因为人的听力范围在20HZ-20000HZ,所以一般采样频率在44.1kHZ,也就是一分钟44100次。

在明白了这些预备知识之后,下面开始介绍开源项目SinVoice。

上面是整个项目的结构,圈中的主要的类,下面把几个重要的类的功能和注意点介绍一下。为了便于理解,我自己添加了一些注释,并不是故意侵占原作者的版权哈。

首先,我们先看一下到底怎么用,下面是MainActivity的代码:

package com.example.sinvoicedemo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;

import com.libra.sinvoice.LogHelper;
import com.libra.sinvoice.SinVoicePlayer;
import com.libra.sinvoice.SinVoiceRecognition;

/**
 *
 * @ClassName: com.example.sinvoicedemo.MainActivity
 * @Description: 声波通信
 * @author zhaokaiqiang
 * @date 2014-11-15 下午12:36:32
 *
 */
public class MainActivity extends Activity implements
		SinVoiceRecognition.Listener, SinVoicePlayer.Listener {

	private final static String TAG = "MainActivity";
	// 最大数字
	private final static int MAX_NUMBER = 5;
	// 识别成功
	private final static int MSG_SET_RECG_TEXT = 1;
	// 开始识别
	private final static int MSG_RECG_START = 2;
	// 识别结束
	private final static int MSG_RECG_END = 3;

	private final static String CODEBOOK = "12345";

	private Handler mHanlder;
	// 播放
	private SinVoicePlayer mSinVoicePlayer;
	// 录音
	private SinVoiceRecognition mRecognition;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mSinVoicePlayer = new SinVoicePlayer(CODEBOOK);
		mSinVoicePlayer.setListener(this);

		mRecognition = new SinVoiceRecognition(CODEBOOK);
		mRecognition.setListener(this);

		final TextView playTextView = (TextView) findViewById(R.id.play_text);
		mHanlder = new RegHandler((TextView) findViewById(R.id.regtext));

		// 开始播放声音
		findViewById(R.id.start_play).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				String text = genText(15);
				playTextView.setText(text);
				mSinVoicePlayer.play(text);
			}
		});

		// 停止播放声音
		findViewById(R.id.stop_play).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				mSinVoicePlayer.stop();
			}
		});

		// 开始声音识别
		findViewById(R.id.start_reg).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				mRecognition.start();
			}
		});

		// 停止声音识别
		findViewById(R.id.stop_reg).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				mRecognition.stop();
			}
		});
	}

	// 获取长度为count且最大值为MAX_NUMBER的随机数
	private String genText(int count) {
		StringBuilder sb = new StringBuilder();
		int pre = 0;
		while (count > 0) {
			int x = (int) (Math.random() * MAX_NUMBER + 1);
			if (Math.abs(x - pre) > 0) {
				sb.append(x);
				--count;
				pre = x;
			}
		}

		return sb.toString();
	}

	private static class RegHandler extends Handler {

		private StringBuilder mTextBuilder = new StringBuilder();
		private TextView mRecognisedTextView;

		public RegHandler(TextView textView) {
			mRecognisedTextView = textView;
		}

		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case MSG_SET_RECG_TEXT:
				char ch = (char) msg.arg1;
				mTextBuilder.append(ch);
				if (null != mRecognisedTextView) {
					mRecognisedTextView.setText(mTextBuilder.toString());
				}
				break;

			case MSG_RECG_START:
				mTextBuilder.delete(0, mTextBuilder.length());
				break;

			case MSG_RECG_END:
				LogHelper.d(TAG, "recognition end");
				break;
			}
		}
	}

	@Override
	public void onRecognitionStart() {
		mHanlder.sendEmptyMessage(MSG_RECG_START);
	}

	@Override
	public void onRecognition(char ch) {
		mHanlder.sendMessage(mHanlder.obtainMessage(MSG_SET_RECG_TEXT, ch, 0));
	}

	@Override
	public void onRecognitionEnd() {
		mHanlder.sendEmptyMessage(MSG_RECG_END);
	}

	@Override
	public void onPlayStart() {
		LogHelper.d(TAG, "start play");
	}

	@Override
	public void onPlayEnd() {
		LogHelper.d(TAG, "stop play");
	}

}

我们可以看出,声波播放和识别的代码封装的非常简单易用,我主要强调以下几点

1.常量CODEBOOK是一个编码本,因为是这个功能可以商用,因此开源的代码中只给出了使用12345这5个数字进行编码的实例,所以这个常量不要修改。

2.SinVoicePlayer和SinVoiceRecognition是两个非常重要的类,前者可以实现将数字转化成单频率的音频进行输出,后者则可以根据音频进行识别。我们可以设置监听器,来监听识别成功的事件回调。

3.genText(int count) 方法是为了获取一个长度是count的随机数,而且这个随机数是有要求的,因为示例代码只实现了1到5的编码和解码,因此,生成的随机数必须在1到5之间才能进行正确的编解码,所以使用MAX_NUMBER进行随机数的大小控制

如果只是想简单的使用这个功能,了解上面的知识之后,就完全可以用了,下一篇文章中,我将介绍实现过程中的一些细节问题,下一篇再见。

项目的Github地址:https://github.com/JesseGu/SinVoice

时间: 2024-10-18 04:13:19

【Android开发经验】移动设备的“声波通信/验证”的实现——SinVoice开源项目介绍(一)的相关文章

[android] androidPN开源项目介绍

打开androidPN项目,会看到server和client两份代码 server部分 找到server的代码,开启服务,双击 bin/run.bat ,服务启动后监听127.0.0.1:7070端口 在浏览器上打开上面的连接,可以看到界面,说明启动成功 client部分 把代码导入到eclipse中 查看清单文件,看到一下activity DemoAppActivity NotificationDetailsActivity NotificationSettingsActivity 还有一个服

Android中通过ViewHelper.setTranslationY实现View移动控制(NineOldAndroids开源项目)

我们知道有不少开源工程,能实现很多不错的效果.前几天,我看了一个效果,刚好项目中也用到了这个jar包.没事挖一挖 学一学(一说到挖一挖,那么问题来了,挖掘机技术到底哪家强 ),看看不错的效果怎么实现的呢?函数的具体意义有是什么呢?很多效果,我们不需要重新造轮子,只需要装配轮子,开车走起就可以了,你没有那么多时间造轮子,我们可以选择自己喜欢的轮子,开我们的兰博基尼,开我们的保时捷概念车,开起来! 先看一下效果吧!挖自开源项目中的(NineOldAndroids开源项目) 不废话.我们解释下相关函数

[转]Android开源项目分类汇总

我喜欢收集源码,如今这个时代,我觉得我们要做的不是做前人做过的事,而是学习他们的经验然后在这基础上创新做出更伟大的事. 转自https://github.com/Trinea/android-open-project Android开源项目第一篇——个性化控件(View)篇  包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.ProgressBar.TextView.ScrollView.TimeView.TipView

GitHub上史上最全的Android开源项目分类汇总

今天在看博客的时候,无意中发现了@Trinea在GitHub上的一个项目Android开源项目分类汇总,由于类容太多了,我没有一个个完整地看完,但是里面介绍的开源项目都非常有参考价值,包括很炫的界面特效设计.个性化控件.工具库.优秀的Android开源项目.开发测试工具.优秀个人和团体等.可以这样说,每一位Andorid开发人员都能从中找到一个或多个适用自己项目的解决方案,消化吸收并加以利用,可以为自己的APP增色不少.文章最后还列出了部分国外著名Android开发者的信息,包括GitHub地址

Android 开源项目分类汇总

目前包括: Android 开源项目第一篇--个性化控件(View)篇  包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.ProgressBar.TextView.ScrollView.TimeView.TipView.FlipView.ColorPickView.GraphView.UI Style.其他Android 开源项目第二篇--工具库篇  包括依赖注入.图片缓存.网络请求.数据库 ORM 工具包.Andro

Android开源项目分类汇总

转自https://github.com/Trinea/android-open-project Android开源项目第一篇——个性化控件(View)篇  包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.ProgressBar.TextView.ScrollView.TimeView.TipView.FlipView.ColorPickView.GraphView.UI Style.其他Android开源项目第二篇—

Android常用酷炫控件(开源项目)github地址汇总

转载一个很牛逼的控件收集贴... 第一部分 个性化控件(View) 主要介绍那些不错个性化的 View,包括 ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.ProgressBar.TextView.ScrollView.TimeView.TipView.FlipView.ColorPickView.GraphView.UI Style 等等. 一.ListView android-pulltorefresh一个强大的拉动

Android 开源项目分类汇总(转)

## 第一部分 个性化控件(View)主要介绍那些不错个性化的 View,包括 ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.ProgressBar.TextView.ScrollView.TimeView.TipView.FlipView.ColorPickView.GraphView.UI Style 等等. #### 一.ListView1. android-pulltorefresh  一个强大的拉动刷新开源项目

66.Android 开源项目分类汇总

转载:https://github.com/Trinea/android-open-project 目前包括: Android 开源项目第一篇——个性化控件(View)篇  包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.ProgressBar.TextView.ScrollView.TimeView.TipView.FlipView.ColorPickView.GraphView.UI Style.其他Android