`
soft刘
  • 浏览: 399 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
最近访客 更多访客>>
社区版块
存档分类
最新评论

android/iphone/windows/linux声波通讯库

阅读更多

3分钟为你的应用添加声波通讯功能

 

前一段时间为了实现声波传输,网上找了半天,好不容易找到一个实现,但准确性远不能满足要求,没办法,只好自己写了一个。
后来一哥们要求在mipsel平台和arm平台上使用,就帮他用c移植到了mipsel平台,实现了在不到普通电脑千分之一cpu的系统平台上的运行。搞定这个后cpu消耗非常低,基本上应该算是没有运行不了的平台了。

一、准确性

准确性95%以上,如果有识别有问题的情况,你可以开启调试模式,该模式下会自动保存识别失败的的音频段,你可以发给我分析识别失败的原因,如果真是识别器没有考虑到的情况的话,调整识别规则就可以完善识别到了。而且传输中加入了校验码,校验码有两个目的,一个是保证识别正确性。保证识别结果不然就识别失败,而如果识别到了就一定是对的,也就是说不会出现传输的是1,而识别提示为0;另一个是错误自动修正,从而保证传输中可以有20%左右(取决于你传输的数据长度)的错误而可以自动修正,从而使得使用过程中基本上识别是不会出错的。识别接口中参数指定了识别是否成功完成,错误码指出了如果识别失败的话,失败的原因。

二、接口简单

我的接口尽量做得简单,这样用起来也比较小白,既然是当成一个库,使用起来越简单越好,就尽量不要去管底层的一些控制参数,比如说声音采样频率、采样精度、采样格式、传输频率、传输码表、音量、缓冲区大小,这些在参数中你就不用管了,当然你想定制的话其实这些参数也全部是都是可以定制的。在这里,这些参数的默认值我也说一下:声音方面默认参数为:声音采样频率为44100,单声道,2个字节(16位)长的采样精度,小端编码,桢大小就为1*2=2个字节,那么每秒处理的数据量就是44100*2=88200字节。传输频率为高频段,抗干扰能力非常好,不管你是在闹市、马路、KTV、或者其它室外场景下,或者你在家里开着大音箱听歌都不会影响到数据的传输。码表为16进制的数据编码,也就是所有数据都会编成16进制后传输。缓冲区的话默认需10k左右的缓冲区(里面其它的内存分配都在内存池中完成,长时间运行解码不会再分配内存)。如果这些参数你完全不懂,就忽略就算了,因为接口足够简单,能用就可以了,也不用理解那么多原理。不过解码器要求你传入的音频数据是这些格式,特别是输入数据要求为44100,单声道,16bits采样精度,小端编码的音频数据。

三、混音音效

另外实际上因为传输频率属于高频段,开始超出正常人可听到的阶段,所以发送的时候感觉没什么反应一样,所以可以在人耳可听到的范围另外加一段可听到的音频音效(咻咻咻、啾啾啾随便你,呵呵)让用户知道系统正在通讯中,最后的效果就是人听到的是人耳可听到那部分你加的音频音效,可实际上设备则可解码出真正的信号,而不会相互干扰。

四、传输距离

传输距离的话是取决于音量的,音量比较大的,传输距离就大,一般以手机的最大音量5-10米没问题,音量设小的话可以控制在10cm-30cm左右。

五、性能

至于性能,系统有两种工作模式:一种是优化内存模式,耗CPU稍多一点,但耗内存小,在当前正常使用的电脑或者现在的智能手机下使用是没有问题的,正常pc机的cpu基于可以看到在1%以下,反正windows任务管理器里显示的是0,应该是1%以下就会显示为0%,估计在百分之零点几左右吧。另一种是优化CPU模式,如果你是在计算能力非常有限的平台上使用,比如说计算能力不到pc千分之一的平台上使用,你可以使用这种模式,这种模式下,基本不会占用你的CPU,但会占内存会大一些,但如果你的CPU真的非常慢,你解码时间会长一点,但无论你的系统有多慢,都不会解不出来,也不会影响解码正确性,只是速度慢的话解码出来的时间就稍长一些。

六、数据传输量

说一说传输数据量的问题,首先我要说一下,我最先了解声波通讯的时候还以为传输率可以达到几k/秒,实际上声波1秒也就传输个十几个字符左右,而且一般来说传输总字符如果达到40个以上,解码正确率就会下降,数据量越大,出错率就会升高。所以想以k级来传输数据量的人就不要想了。当然这也是对怎么使用声波通讯的机制不了解的原因:声波传输使用时主要是作为握手和对接使用,真正的数据是通过对接后在互联网上传输。比如说面对面的声波支付,A要付款给B,那么声波通讯在这里面主要是传输用户标志,或者付款单编号来快速握手(这当然跟你设计的支付流程有关)。我这里以一种模拟刷卡的流程举例说明:A(客户)要付款给B(商家),我们设想如果是刷卡的话,流程可能是这样的,A(客户)在B(商家)的POS机上刷一下银行卡,B(商家)就知道A(客户)是哪张银行卡,从而把该卡和金额传到支付公司去扣款。那么换成声波后也是一样的,A(客户)在手机上点一下付款,A(客户)的手机发出一串声波,声波上传输A(客户)的用户标识,传到B(商家)的手机,这时B(商家)就可以把A(客户)的标志和扣款金额传到支付公司去扣款了。当然你也可以设计一个反过来的流程,就是由B端(商家端)发出一串账单音频,而由A端接收(客户关),但原理是一样的。所以在这整个流程里面,声波是做系统对接使用的,替代刷银行卡、或者扫二维码的对接方式,然后真正的数据传输还是在互联网上传输。

七、编码

我这里采用的是16进制的传输码,你自己要传输的信息可以自己先编成16进制码,不过码表其实是可以定制的,比如说你想传输数据量更大一点,那也可以扩展到32进制,这样相对来说传输数据量编码后会更小,数据量可以传输得更大一些。如果你要传输的是数字,先把数字编成16进制编码,如果你要传字母,那么一个字母可以编成2个16进制的字符。
我这里列出几种编码的情况,比如说你要传输QQ号,手机号这类数字,那就最好转成16进制后再传输。以传输手机号为例:因为手机号肯定是以1开始的,那么1就可以不传了,而且都是以13,15,18开头,那么你可以把3,5,8先映射为1,2,3,然后再做16进制转码。当然解码端你自己怎么做的编码就怎么做解码,这样一个手机号本来有11位,优化下来就可以做到9位,或者8位。呵呵,声波传输就是要做到尽量小的数据量,数据量越小传输准确率就越可靠,你的系统就越可靠。
我这里列出几种编码的示例。
手机号编成16进制声波通讯编码:

[java] view plaincopy
 
  1. /************************************************************************ 
  2. 声波通讯库示例,16进制声波通讯编码 
  3. 声波通讯库特征: 
  4. 准确性95%以上,其实一般是不会出错的。 
  5. 接口非常简单,有完整的示例,3分钟就可以让你的应用增加声波通讯功能 
  6. 抗干扰性强,基本上无论外界怎么干扰,信号都是准确的 
  7. 基本的编码为16进制,而通过编码可传输任何字符 
  8. 性能非常强,没有运行不了的平台,而且通过内存池优化,长时间解码不再分配新内存,可7*24小时运行 
  9. 可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel都有示例 
  10. 详情可查看:http://blog.csdn.net/softlgh 
  11. 作者: 夜行侠 QQ:3116009971 邮件:3116009971@qq.com 
  12. ************************************************************************/  
  13.   
  14.   
  15. //13,14,15,18开头的手机号,手机号去除1以后,16进制在9位以内  
  16. public static String encode(String _mobile)  
  17. {  
  18.     if(_mobile.length() == 11 && _mobile.startsWith("1"))  
  19.     {      
  20.         long _number = Long.parseLong(_mobile.substring(1));  
  21.       String s = Long.toHexString(_number);  
  22.       while(s.length() < 9)  
  23.       {  
  24.           s = "0" + s;  
  25.       }  
  26.       return s;  
  27.     }  
  28.     return null;  
  29. }  


任意字符串(先换成byte[])编成16进制声波通讯编码:

[java] view plaincopy
 
  1. /************************************************************************ 
  2. 声波通讯库示例,16进制声波通讯编码 
  3. 声波通讯库特征: 
  4. 准确性95%以上,其实一般是不会出错的。 
  5. 接口非常简单,有完整的示例,3分钟就可以让你的应用增加声波通讯功能 
  6. 抗干扰性强,基本上无论外界怎么干扰,信号都是准确的 
  7. 基本的编码为16进制,而通过编码可传输任何字符 
  8. 性能非常强,没有运行不了的平台,而且通过内存池优化,长时间解码不再分配新内存,可7*24小时运行 
  9. 可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel都有示例 
  10. 详情可查看:http://blog.csdn.net/softlgh 
  11. 作者: 夜行侠 QQ:3116009971 邮件:3116009971@qq.com 
  12. ************************************************************************/  
  13.   
  14. public static final char[] hexChars = {'0''1''2''3''4''5''6''7''8''9''a''b''c''d''e''f'};  
  15. public static String encodeString(byte[] _val)  
  16. {  
  17.     StringBuffer result = new StringBuffer(_val.length*2);  
  18.     for(int i = 0; i < _val.length; i ++)  
  19.     {  
  20.         result.append(hexChars[(_val[i] >> 4) & 0x0f]);  
  21.         result.append(hexChars[_val[i] & 0x0f]);  
  22.     }  
  23.     return result.toString();  
  24. }  

八、使用场景

这里也把现在市场上的一些应用到了声波的先列一下:支付宝的声波支付,微信的声波雷达加好友,QQ音乐中的歌曲的声波分享,茄子快传,蛐蛐儿等等,国外的apple,google对声波通讯也都有应用。

声波实际上可以看成是一种比二维码可友好的传输方式,二维码能实现的功能与声波有很大的相似性,但声波使用时会更友好。做以上这些功能的时候,基本上都是只要靠近在手机上点一下/划一下/推一下/甩一下/摇一下(这是你自己定的)就可以了,而不需要像二维码一样还要打开摄像头、对准去拍那样比较麻烦。相比来说,声波传输更像刷卡一样方便简单,可以理解为类似NFC的一种近场通讯技术。

 

比如说你可以用声波支付,声波会员卡,声波券票,声音名片,声波签到,声波排队,做wifi和密码共享或者设定,做文件/图片、你App里面的任何项目分享,用声波关注微博、微信等等。

声波支付的流程前面有讲过,实际上有可能稍微复杂一点,但大概是这样的思路。

声波会员卡是指用户到店铺后不需要带物理卡了,而是手机代替了所有的会员卡,在商家一碰,会员信息就自动显示出来了。

声波券票也很简单,比如说一张电子团购券,电子电影券,可以设置成一个唯一的编码,到场后与录音设备一碰,系统就能识别到这张券票

声波签到是指在固定位置安装签到软件,用户到达后,可以快速完成签到操作。 

声波分享以文件/图片、或者你App里面的任何项目为例:比如A要把一张图片发送给B,那么A点击一下共享按钮(或者一推一丢都行),这时手机通过声音把这个图片的编号发送出去,当B收到这个标志时,马上从你平台的服务器上下载这张图片。最后的效果就是A在要分享的图片上一点,B就能收到该张图片,非常的方便快捷。

九、运行平台

这个声波传输库可以运行在windows平台(所有windows系统), linux平台, mipsel平台, arm平台, iphone平台, android平台,全部都有SDK,后面的附件中有各个平台的库,你自己可以选择下载

十、代码及示例

库的结构非常简单:一个发送端,一个接收端。发送端很简单,基本上就是一个send函数。接收端稍微复杂一点,但也是很简单的:创建一个解码器,设置监听,往解码器送音频数据(解码器就会开始分析音频数据,并在监听到信号后通知你),最后停止解码器和销毁解码器。使用还是很简单的,下面和附件中有例子说明。

这种库的使用毕竟是商用,所以就不能免费了,呵呵。不过如果你完全是没有任何商业目的的公益项目,我也是完全可以免费给你用的。
试用库识别次数有限,或者没有进行降噪处理

各个平台的例子及源码
android平台声波通讯发送端接口:

[java] view plaincopy
 
  1. /************************************************************************ 
  2. 声波通讯库示例,android平台声波通讯发送端 
  3. 声波通讯库特征: 
  4. 准确性95%以上,其实一般是不会出错的。 
  5. 接口非常简单,有完整的示例,3分钟就可以让你的应用增加声波通讯功能 
  6. 抗干扰性强,基本上无论外界怎么干扰,信号都是准确的 
  7. 基本的编码为16进制,而通过编码可传输任何字符 
  8. 性能非常强,没有运行不了的平台,而且通过内存池优化,长时间解码不再分配新内存,可7*24小时运行 
  9. 可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel都有示例 
  10. 详情可查看:http://blog.csdn.net/softlgh 
  11. 作者: 夜行侠 QQ:3116009971 邮件:3116009971@qq.com 
  12. ************************************************************************/  
  13.   
  14.   
  15. //创建声波通讯播放器  
  16. player = new VoicePlayer();  
  17. //开始播放  
  18. player.play("12345678abcdef"1200);  

       
iphone平台声波通讯发送端接口:

[objc] view plaincopy
 
  1. /************************************************************************ 
  2. 声波通讯库示例,iphone平台声波通讯发送端 
  3. 声波通讯库特征: 
  4. 准确性95%以上,其实一般是不会出错的。 
  5. 接口非常简单,有完整的示例,3分钟就可以让你的应用增加声波通讯功能 
  6. 抗干扰性强,基本上无论外界怎么干扰,信号都是准确的 
  7. 基本的编码为16进制,而通过编码可传输任何字符 
  8. 性能非常强,没有运行不了的平台,而且通过内存池优化,长时间解码不再分配新内存,可7*24小时运行 
  9. 可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel都有示例 
  10. 详情可查看:http://blog.csdn.net/softlgh 
  11. 作者: 夜行侠 QQ:3116009971 邮件:3116009971@qq.com 
  12. ************************************************************************/  
  13.   
  14.   
  15. NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init];  
  16. //创建声波通讯播放器  
  17. VoicePlayer *player=[[VoicePlayer alloc] init];  
  18. //播放  
  19. [player play:@"12345678" playCount:1 muteInterval:0];  
  20. //没播放完之前,不要释放内存  
  21. while (![player isStopped]) {  
  22.     usleep(3300 * 1000);//300ms  
  23. }  
  24. [tempPool drain];  

    

Android平台声波通讯解码端代码:

[java] view plaincopy
 
  1. /************************************************************************ 
  2. 声波通讯库示例,Android平台声波通讯解码端 
  3. 声波通讯库特征: 
  4. 准确性95%以上,其实一般是不会出错的。 
  5. 接口非常简单,有完整的示例,3分钟就可以让你的应用增加声波通讯功能 
  6. 抗干扰性强,基本上无论外界怎么干扰,信号都是准确的 
  7. 基本的编码为16进制,而通过编码可传输任何字符 
  8. 性能非常强,没有运行不了的平台,而且通过内存池优化,长时间解码不再分配新内存,可7*24小时运行 
  9. 可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel都有示例 
  10. 详情可查看:http://blog.csdn.net/softlgh 
  11. 作者: 夜行侠 QQ:3116009971 邮件:3116009971@qq.com 
  12. ************************************************************************/  
  13. VoiceRecognition mRecognition = new VoiceRecognition();  
  14. mRecognition.setListener(new VoiceRecognitionListener()  
  15. {  
  16.     @Override  
  17.     public void onRecognitionStart() {  
  18.     }  
  19.   
  20.     public void onRecognitionEnd(int _recogStatus, String _val)  
  21.     {  
  22.         if(_recogStatus == VoiceRecognition.Status_Success)  
  23.         {  
  24.             System.out.println(_val);  
  25.         }  
  26.     }  
  27. });  
  28. mRecognition.start();  


c通用声波通讯解码端接口

 

[cpp] view plaincopy
 
  1. /************************************************************************ 
  2. 声波通讯库示例,声波通讯库c解码接口 
  3. 声波通讯库特征: 
  4. 准确性95%以上,其实一般是不会出错的。 
  5. 接口非常简单,有完整的示例,3分钟就可以让你的应用增加声波通讯功能 
  6. 抗干扰性强,基本上无论外界怎么干扰,信号都是准确的 
  7. 基本的编码为16进制,而通过编码可传输任何字符 
  8. 性能非常强,没有运行不了的平台,而且通过内存池优化,长时间解码不再分配新内存,可7*24小时运行 
  9. 可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel都有示例 
  10. 详情可查看:http://blog.csdn.net/softlgh 
  11. 作者: 夜行侠 QQ:3116009971 邮件:3116009971@qq.com 
  12. ************************************************************************/  
  13. #ifdef VOICE_RECOG_DLL  
  14. #define VOICERECOGNIZEDLL_API __declspec(dllexport)  
  15. #else  
  16. #ifdef WIN32  
  17. #define VOICERECOGNIZEDLL_API __declspec(dllimport)  
  18. #else  
  19. #define VOICERECOGNIZEDLL_API  
  20. #endif  
  21. #endif  
  22.   
  23. #ifndef VOICE_RECOG_H  
  24. #define VOICE_RECOG_H  
  25.   
  26. #ifdef __cplusplus  
  27. extern "C" {  
  28. #endif  
  29.     enum VRErrorCode  
  30.     {  
  31.         VR_SUCCESS = 0  
  32.     };  
  33.   
  34.     enum DecoderPriority  
  35.     {  
  36.         CPUUsePriority = 1//不占内存,但CPU消耗比较大一些  
  37.         , MemoryUsePriority = 2//不占CPU,但内存消耗大一些  
  38.     };  
  39.   
  40.     typedef enum {vr_false = 0, vr_true = 1} vr_bool;  
  41.   
  42.     typedef void (*vr_pRecognizerStartListener)(void);  
  43.     //_result如果为VR_SUCCESS,则表示识别成功,否则为错误码,成功的话_data才有数据  
  44.     typedef void (*vr_pRecognizerEndListener)(int _result, char *_data, int _dataLen);  
  45.   
  46.     //创建声波识别器  
  47.     VOICERECOGNIZEDLL_API void *vr_createVoiceRecognizer(DecoderPriority _decoderPriority = CPUUsePriority);  
  48.   
  49.     //销毁识别器  
  50.     VOICERECOGNIZEDLL_API void vr_destroyVoiceRecognizer(void *_recognizer);  
  51.   
  52.     //设置识别到信号的监听器  
  53.     VOICERECOGNIZEDLL_API void vr_setRecognizerListener(void *_recognizer, vr_pRecognizerStartListener _startListener, vr_pRecognizerEndListener _endListener);  
  54.   
  55.     //开始识别  
  56.     //这里一般是线程,这个函数在停止识别之前不会返回  
  57.     VOICERECOGNIZEDLL_API void vr_runRecognizer(void *_recognizer);  
  58.   
  59.     //停止识别,该函数调用后vr_runRecognizer会返回  
  60.     //该函数只是向识别线程发出退出信号,判断识别器是否真正已经退出要使用以下的vr_isRecognizerStopped函数  
  61.     VOICERECOGNIZEDLL_API void vr_stopRecognize(void *_recognizer);  
  62.   
  63.     //判断识别器线程是否已经退出  
  64.     VOICERECOGNIZEDLL_API vr_bool vr_isRecognizerStopped(void *_recognizer);  
  65.   
  66.     //要求输入数据要求为44100,单声道,16bits采样精度,小端编码的音频数据  
  67.     //小端编码不用特别处理,一般你录到的数据都是小端编码的  
  68.     VOICERECOGNIZEDLL_API int vr_writeData(void *_recognizer, char *_data, int _dataLen);  
  69.   
  70. #ifdef __cplusplus  
  71. }  
  72. #endif  
  73.   
  74. #endif  



使用c声波通讯接口从wav文件中解码的例子:

[cpp] view plaincopy
 
  1. /************************************************************************ 
  2. 声波通讯库示例,从wav文件中读取音频信号进行解码,该工程示例是可跨平台的 
  3. 声波通讯库特征: 
  4. 准确性95%以上,其实一般是不会出错的。 
  5. 接口非常简单,有完整的示例,3分钟就可以让你的应用增加声波通讯功能 
  6. 抗干扰性强,基本上无论外界怎么干扰,信号都是准确的 
  7. 基本的编码为16进制,而通过编码可传输任何字符 
  8. 性能非常强,没有运行不了的平台,而且通过内存池优化,长时间解码不再分配新内存,可7*24小时运行 
  9. 可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel都有示例 
  10. 详情可查看:http://blog.csdn.net/softlgh 
  11. 作者: 夜行侠 QQ:3116009971 邮件:3116009971@qq.com 
  12. ************************************************************************/  
  13. //当次解码结束的回调函数  
  14. void waveRecognizerEnd(int _recogStatus, char *_data, int _dataLen)  
  15. {  
  16.     if (_recogStatus == VR_SUCCESS)  
  17.     {  
  18.         char buf[51];  
  19.         memcpy(buf, _data, _dataLen);  
  20.         buf[_dataLen] = 0;  
  21.         printf("------------------recognized data:%s\n", buf);  
  22.     }  
  23.     else  
  24.     {  
  25.         printf("------------------recognize invalid data, errorCode:%d\n", _recogStatus);  
  26.     }  
  27. }  
  28.   
  29. //识别到有信号时开始解码回调函数  
  30. void waveRecognizerStart()  
  31. {  
  32.     printf("------------------recognize start\n");  
  33. }  
  34.   
  35. //WIN32与linux所需的线程函数原型有点不一样  
  36. #ifdef WIN32  
  37. DWORD WINAPI waveRunVoiceRecognize( LPVOID _recognizer)    
  38. {  
  39. #else  
  40. void *waveRunVoiceRecognize( void * _recognizer)   
  41. {  
  42.     printf("voice recognizer thread start:%d\n", getpid());  
  43. #endif  
  44.     vr_runRecognizer(_recognizer);  
  45.     return 0;  
  46. }  
  47.   
  48. //从wav文件中装载数据进入声波识别器  
  49. void test_voiceRecog_from_wav(int argc, char* argv[])  
  50. {  
  51.     char *wavFile = (char *)"data.wav";  
  52.     if(argc > 1)  
  53.     {  
  54.         wavFile = argv[1];  
  55.     }  
  56.   
  57.     //读入wav文件  
  58.     struct WavData wavData;  
  59.     memset(&wavData, 0, sizeof(wavData));  
  60.     readWave(wavFile, &wavData);  
  61.     printf("%s data size:%d\n", wavFile, (int)wavData.size);  
  62.   
  63.     //创建识别器,并开始运行  
  64.     void *recognizer = vr_createVoiceRecognizer(MemoryUsePriority);  
  65.     vr_setRecognizerListener(recognizer, waveRecognizerStart, waveRecognizerEnd);  
  66. #ifdef WIN32  
  67.     HANDLE recogThread = CreateThread( NULL, 0, waveRunVoiceRecognize, recognizer, 0, 0 );  
  68.     //_beginthread(waveRunVoiceRecognize, 0, recognizer);  
  69. #else  
  70.     pthread_t recogThread;  
  71.     pthread_create(&recogThread, NULL, waveRunVoiceRecognize, recognizer);  
  72.     //printf("voice recognizer thread id:%lu\n", (recogThread));  
  73. #endif  
  74.   
  75.     //往识别器写入数据,这里可以反复写  
  76.     vr_writeData(recognizer, wavData.data, wavData.size);  
  77.   
  78.     //通知识别器停止,并等待识别器真正退出  
  79.     do   
  80.     {  
  81.         vr_stopRecognize(recognizer);  
  82.         printf("recognizer is quiting\n");  
  83. #ifdef WIN32  
  84.         Sleep(1000);  
  85. #else  
  86.         sleep(1);  
  87. #endif  
  88.     } while (!vr_isRecognizerStopped(recognizer));  
  89.   
  90.     //销毁识别器  
  91.     vr_destroyVoiceRecognizer(recognizer);  
  92.   
  93.     printf("press enter key to exit.......\n");  
  94.     char c;  
  95.     scanf("%c", &c);  
  96. }  



使用c声波通讯接口从实时录音数据中解码的例子:

[cpp] view plaincopy
 
  1. /************************************************************************ 
  2. 声波通讯库示例,从实时录音数据获取音频信号进行解码,该工程示例是可跨平台的 
  3. 声波通讯库特征: 
  4. 准确性95%以上,其实一般是不会出错的。 
  5. 接口非常简单,有完整的示例,3分钟就可以让你的应用增加声波通讯功能 
  6. 抗干扰性强,基本上无论外界怎么干扰,信号都是准确的 
  7. 基本的编码为16进制,而通过编码可传输任何字符 
  8. 性能非常强,没有运行不了的平台,而且通过内存池优化,长时间解码不再分配新内存,可7*24小时运行 
  9. 可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel都有示例 
  10. 详情可查看:http://blog.csdn.net/softlgh 
  11. 作者: 夜行侠 QQ:3116009971 邮件:3116009971@qq.com 
  12. ************************************************************************/  
  13. //识别到有信号时开始解码回调函数  
  14. void recorderRecognizerStart()  
  15. {  
  16.     printf("------------------recognize start\n");  
  17. }  
  18.   
  19. //当次解码结束的回调函数  
  20. void recorderRecognizerEnd(int _recogStatus, char *_data, int _dataLen)  
  21. {  
  22.     if (_recogStatus == VR_SUCCESS)  
  23.     {  
  24.         char buf[51];  
  25.         memcpy(buf, _data, _dataLen);  
  26.         buf[_dataLen] = 0;  
  27.         printf("------------------recognized data:%s\n", buf);  
  28.     }  
  29.     else  
  30.     {  
  31.         printf("------------------recognize invalid data, errorCode:%d\n", _recogStatus);  
  32.     }  
  33. }  
  34.   
  35. #ifdef WIN32  
  36. void runRecorderVoiceRecognize( void * _recognizer)    
  37. #else  
  38. void *runRecorderVoiceRecognize( void * _recognizer)   
  39. #endif  
  40. {  
  41.     vr_runRecognizer(_recognizer);  
  42. }  
  43.   
  44. int recorderShortWrite(void *_writer, const void *_data, unsigned long _sampleCout)  
  45. {  
  46.     char *data = (char *)_data;  
  47.     void *recognizer = _writer;  
  48.     return vr_writeData(recognizer, data, (int)_sampleCout);  
  49. }  
  50.   
  51. void test_recorderVoiceRecog()  
  52. {  
  53.     //创建识别器,并设置监听器  
  54.     void *recognizer = vr_createVoiceRecognizer();  
  55.     vr_setRecognizerListener(recognizer, recorderRecognizerStart, recorderRecognizerEnd);  
  56.     //创建录音机  
  57.     void *recorder = NULL;  
  58.     int r = initRecorder(44100, 1, 16, 512, &recorder);//要求录取short数据  
  59.     if(r != 0)  
  60.     {  
  61.         printf("recorder init error:%d", r);  
  62.         return;  
  63.     }  
  64.     //开始录音  
  65.     //r = startRecord(recorder, recognizer, recorderFloatWrite);//float数据  
  66.     r = startRecord(recorder, recognizer, recorderShortWrite);//short数据  
  67.     if(r != 0)  
  68.     {  
  69.         printf("recorder record error:%d", r);  
  70.         return;  
  71.     }  
  72.     //开始识别  
  73. #ifdef WIN32  
  74.     //CreateThread( NULL, 0, runRecorderVoiceRecognize, recognizer, 0, 0 );  
  75.     _beginthread(runRecorderVoiceRecognize, 0, recognizer);  
  76. #else  
  77.     pthread_t ntid;  
  78.     pthread_create(&ntid, NULL, runRecorderVoiceRecognize, recognizer);  
  79. #endif  
  80.     printf("\n\n\nrecognize start, waiting for signals ............\n");  
  81.     char c = 0;  
  82.     do   
  83.     {  
  84.         printf("press q to end recognize\n");  
  85.         scanf_s("%c", &c);  
  86.     } while (c != 'q');  
  87.   
  88.     //停止录音  
  89.     r = stopRecord(recorder);  
  90.     if(r != 0)  
  91.     {  
  92.         printf("recorder stop record error:%d", r);  
  93.     }  
  94.     r = releaseRecorder(recorder);  
  95.     if(r != 0)  
  96.     {  
  97.         printf("recorder release error:%d", r);  
  98.     }  
  99.   
  100.     //通知识别器停止,并等待识别器真正退出  
  101.     do   
  102.     {  
  103.         vr_stopRecognize(recognizer);  
  104.         printf("recognizer is quiting\n");  
  105. #ifdef WIN32  
  106.         Sleep(1000);  
  107. #else  
  108.         sleep(1);  
  109. #endif  
  110.     } while (!vr_isRecognizerStopped(recognizer));  
  111.   
  112.     //销毁识别器  
  113.     vr_destroyVoiceRecognizer(recognizer);  
  114. }  


相应的录音机抽象接口:

[cpp] view plaincopy
 
  1. /************************************************************************ 
  2. 声波通讯库示例,录音机抽象接口,该工程示例是可跨平台的 
  3. 声波通讯库特征: 
  4. 准确性95%以上,其实一般是不会出错的。 
  5. 接口非常简单,有完整的示例,3分钟就可以让你的应用增加声波通讯功能 
  6. 抗干扰性强,基本上无论外界怎么干扰,信号都是准确的 
  7. 基本的编码为16进制,而通过编码可传输任何字符 
  8. 性能非常强,没有运行不了的平台,而且通过内存池优化,长时间解码不再分配新内存,可7*24小时运行 
  9. 可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel都有示例 
  10. 详情可查看:http://blog.csdn.net/softlgh 
  11. 作者: 夜行侠 QQ:3116009971 邮件:3116009971@qq.com 
  12. ************************************************************************/  
  13.   
  14. //_data的数据格式是根据initRecorder传入的数据类型定的,一般可能为short。  
  15. //_sampleCout是表示_data中含有的样本数,不是指_data的长度  
  16. //返回已经处理的信号数,如果返回-1,则录音线程应退出  
  17. typedef int (*r_pwrite)(void *_writer, const void *_data, unsigned long _sampleCout);  
  18.   
  19. /************************************************************************/  
  20. /* 创建录音机 
  21. /* _sampleRateInHz为44100 
  22. /* _channel为单声道,1为单声道,2为立体声 
  23. /* _audioFormat为一个信号的bit数,单声道双字节精度的话为16 
  24. /************************************************************************/  
  25. int initRecorder(int _sampleRateInHz, int _channel, int _audioFormat, int _bufferSize, void **_precorder);  
  26.   
  27. /************************************************************************/  
  28. /* 开始录音 
  29. /************************************************************************/  
  30. int startRecord(void *_recorder, void *_writer, r_pwrite _pwrite);  
  31.   
  32. /************************************************************************/  
  33. /* 停止录音 
  34. /************************************************************************/  
  35. int stopRecord(void *_recorder);  
  36.   
  37. /************************************************************************/  
  38. /* 释放录音器的资源 
  39. /************************************************************************/  
  40. int releaseRecorder(void *_recorder);  


使用PA实现的录音机接口,可跨平台:

[cpp] view plaincopy
 
  1. /************************************************************************ 
  2. 声波通讯库示例,PA库实现的录音机接口,该库是跨平台的 
  3. 声波通讯库特征: 
  4. 准确性95%以上,其实一般是不会出错的。 
  5. 接口非常简单,有完整的示例,3分钟就可以让你的应用增加声波通讯功能 
  6. 抗干扰性强,基本上无论外界怎么干扰,信号都是准确的 
  7. 基本的编码为16进制,而通过编码可传输任何字符 
  8. 性能非常强,没有运行不了的平台,而且通过内存池优化,长时间解码不再分配新内存,可7*24小时运行 
  9. 可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel都有示例 
  10. 详情可查看:http://blog.csdn.net/softlgh 
  11. 作者: 夜行侠 QQ:3116009971 邮件:3116009971@qq.com 
  12. ************************************************************************/  
  13.   
  14. #include "record.h"  
  15. #include <stdio.h>  
  16. #include <stdlib.h>  
  17. //#include <syslib.h>  
  18. #include "portaudio.h"  
  19.   
  20. #pragma comment(lib, "portaudio_x86.lib")  
  21.   
  22. #define SAMPLE_RATE  (44100)  
  23. #define FRAMES_PER_BUFFER (512)  
  24. #define NUM_SECONDS     (5)  
  25. #define NUM_CHANNELS    (2)  
  26. #define DITHER_FLAG     (0) /**/  
  27. #define WRITE_TO_FILE   (0)  
  28.   
  29. /* Select sample format. */  
  30. #if 1  
  31. #define PA_SAMPLE_TYPE  paFloat32  
  32. typedef float SAMPLE;  
  33. #define SAMPLE_SILENCE  (0.0f)  
  34. #define PRINTF_S_FORMAT "%.8f"  
  35. #elif 1  
  36. #define PA_SAMPLE_TYPE  paInt16  
  37. typedef short SAMPLE;  
  38. #define SAMPLE_SILENCE  (0)  
  39. #define PRINTF_S_FORMAT "%d"  
  40. #elif 0  
  41. #define PA_SAMPLE_TYPE  paInt8  
  42. typedef char SAMPLE;  
  43. #define SAMPLE_SILENCE  (0)  
  44. #define PRINTF_S_FORMAT "%d"  
  45. #else  
  46. #define PA_SAMPLE_TYPE  paUInt8  
  47. typedef unsigned char SAMPLE;  
  48. #define SAMPLE_SILENCE  (128)  
  49. #define PRINTF_S_FORMAT "%d"  
  50. #endif  
  51.   
  52. struct PARecorder  
  53. {  
  54.     PaStream* stream;  
  55.     PaStreamParameters  inputParameters,  
  56.         outputParameters;  
  57.     int sampleRateInHz, channel, audioFormat, bufferSize;  
  58.     void *writer;  
  59.     r_pwrite write;  
  60. };  
  61.   
  62. /* This routine will be called by the PortAudio engine when audio is needed. 
  63. ** It may be called at interrupt level on some machines so don't do anything 
  64. ** that could mess up the system like calling malloc() or free(). 
  65. */  
  66. static int recordCallback( const void *inputBuffer, void *outputBuffer,  
  67.     unsigned long framesPerBuffer,  
  68.     const PaStreamCallbackTimeInfo* timeInfo,  
  69.     PaStreamCallbackFlags statusFlags,  
  70.     void *userData )  
  71. {  
  72.     //void *recognizer = userData;  
  73.     PARecorder *recorder = (PARecorder *)userData;  
  74.     int r = recorder->write(recorder->writer, inputBuffer, framesPerBuffer);  
  75.     if (r >= 0)  
  76.     {  
  77.         return paContinue;  
  78.     }  
  79.     else  
  80.     {  
  81.         return paComplete;  
  82.     }  
  83. }  
  84.   
  85. int initRecorder(int _sampleRateInHz, int _channel, int _audioFormat, int _bufferSize, void **_precorder)  
  86. {  
  87.     PaError err = Pa_Initialize();  
  88.     if( err != paNoError )   
  89.     {  
  90.         Pa_Terminate();  
  91.     }  
  92.     PARecorder *recorder = new PARecorder();  
  93.     recorder->stream = NULL;  
  94.     recorder->sampleRateInHz = _sampleRateInHz;  
  95.     recorder->channel = _channel;  
  96.     recorder->audioFormat = _audioFormat;  
  97.     recorder->bufferSize = _bufferSize;  
  98.     recorder->writer = NULL;  
  99.     *_precorder = recorder;  
  100.   
  101.     return err;  
  102. }  
  103.   
  104. int startRecord(void *_recorder, void *_writer, r_pwrite _pwrite)  
  105. {  
  106.     PARecorder* recorder = (PARecorder*)_recorder;  
  107.     recorder->write = _pwrite;  
  108.     recorder->writer = _writer;  
  109.     PaStreamParameters *inputParameters = &recorder->inputParameters;  
  110.     inputParameters->device = Pa_GetDefaultInputDevice(); /* default input device */  
  111.     if (inputParameters->device == paNoDevice) {  
  112.         fprintf(stderr,"Error: No default input device.\n");  
  113.         Pa_Terminate();  
  114.         return -1;//这个编号要与PA的其它编号不重复  
  115.     }  
  116.     inputParameters->channelCount = recorder->channel;  
  117.     if(recorder->audioFormat == 0)inputParameters->sampleFormat = paFloat32;  
  118.     else inputParameters->sampleFormat = paInt16;  
  119.     //inputParameters->sampleFormat = PA_SAMPLE_TYPE;  
  120.     inputParameters->suggestedLatency = Pa_GetDeviceInfo( inputParameters->device )->defaultLowInputLatency;  
  121.     inputParameters->hostApiSpecificStreamInfo = NULL;  
  122.   
  123.     /* Record some audio. -------------------------------------------- */  
  124.     PaError err = Pa_OpenStream(  
  125.         &recorder->stream,  
  126.         &recorder->inputParameters,  
  127.         NULL,                  /* &outputParameters, */  
  128.         recorder->sampleRateInHz,  
  129.         recorder->bufferSize,  
  130.         paClipOff,      /* we won't output out of range samples so don't bother clipping them */  
  131.         recordCallback,  
  132.         recorder );  
  133.     if (err == paNoError)  
  134.     {  
  135.         err = Pa_StartStream( recorder->stream );  
  136.     }  
  137.     if( err != paNoError )   
  138.     {  
  139.         delete recorder;  
  140.     }  
  141.     return err;  
  142. }  
  143.   
  144. int stopRecord(void *_recorder)  
  145. {  
  146.     PaError err = paNoError;  
  147.     if(_recorder != NULL)  
  148.     {  
  149.         PARecorder *recorder = (PARecorder *)_recorder;  
  150.         PaError err = Pa_CloseStream( recorder->stream );  
  151.     }  
  152.     return err;  
  153. }  
  154.   
  155. int releaseRecorder(void *_recorder)  
  156. {  
  157.     PaError err = paNoError;  
  158.     err = Pa_Terminate();  
  159.     if(_recorder != NULL)  
  160.     {  
  161.         PARecorder *recorder = (PARecorder *)_recorder;  
  162.         delete recorder;  
  163.     }  
  164.     return err;  
  165. }  

 

所有代码都在附件中

 

附件说明:
各平台相应的文件在相应平台的文件夹下,有些平台文件夹下只有编码端或者解码端,或者是因为不需要,或者是我自己现在没用到,也懒得去编译了,你自己需要的时候找我吧。各平台的库是demo版,c语言版是限制了解码次数,android的java版是没有去除噪音功能,你自己如果真正需要相应的正式版,再找我吧。各个平台的编码端都没有任何限制


本文件夹下包含:
VoiceRecogFromRecorder.exe:从windows录音设备读取音频数据解码信号的示例程序,其代码在windows文件夹下。该示例工程是可跨平台编译的,链接时去链接相应平台的.so文件就可以了。使用时确保windows录音正常,然后从android手机播放信号后windows上就能识别到了。
VoiceRecogFromWav.exe:从本目录下的data.wav文件读取音频数据解码信号的示例,代码在windows文件夹下。该示例工程是可跨平台编译的,链接时去链接相应平台的.so文件就可以了。
声波通讯测试.apk:android平台上同时进行音频编码和解码的示例,其代码在android文件夹下
voiceDemoWithNoise.jar:android平台上同时进行音频编码和解码库,此库为没有处理噪音的开发版,不是正式版


各平台文件夹:
android:示例apk,java版的编码和解码库,相应的解码、解码使用示例代码,但解码库没有降噪处理,错误率比正式版高。
iphone:现在我只用到了编码端和使用示例代码,解码端没有编译。
windows:现在我只用到了解码端,所以只有解码库,限制了使用次数。windows平台文件夹下有使用声波通讯库的完整示例代码,这些示例代码实际上是跨平台,可在任何支持c的平台上编译运行,包括linux,arm,mipsel等平台,arm平台,linux平台,mipsel平台上使用解码库与windows相同,链接时去链接相应平台的.so文件就可以了。示例中包括从wav文件读取音频数据,或者从录音机读取音频数据。
arm:现在我只用到了解码端,所以只有解码库,限制了使用次数。解码使用示例代码见windows文件夹下
linux:现在我只用到了解码端,所以只有解码库,限制了使用次数。解码使用示例代码见windows文件夹下
mipsel:现在我只用到了解码端,所以只有解码库,限制了使用次数。解码使用示例代码见windows文件夹下

 

下载附件:附件

 

声波通讯库文档

 

作者: 夜行侠 QQ:3116009971 邮件:3116009971@qq.com

 

 

分享到:
评论

相关推荐

    android/iphone/windows/linux/微信 声波通讯库(新版)

    跨平台声波通讯库(新版) 声波通讯库特征: 准确性95%以上,其实一般是...可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel都有示例 http://blog.csdn.net/softlgh/article/details/40507623

    android/iphone/windows/linux/微信 声波通讯库

    跨平台声波通讯库 声波通讯库特征: 准确性95%以上,其实一般是不会出错...可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel都有示例 http://blog.csdn.net/softlgh/article/details/40507623

    android/iphone/windows/linux声波通信库(2017)

    iphone, windows, linux, arm, mipsel, stm32都有示例。 详情了解:http://blog.csdn.net/softlgh/article/details/40507623 也可从http://pan.baidu.com/s/1mi00vhe下载 后面还会上传最近两年做过的一些声音信号...

    android/iphone/windows/linux声波通信-声波wifi配码库(2020)

    声波广告互动的信号传输距离在10-20米以上,通过设备传输距离可在50米以上 性能非常强,没有运行不了的平台,而且通过内存池优化,长时间解码不再分配新内存,可7*24小时运行 可支持任何平台,常见的平台android , ...

    android/iphone/windows/linux声波通信库(2018)

    可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel, stm32都有示例。 详情了解:http://blog.csdn.net/softlgh/article/details/40507623 也可从http://pan.baidu.com/s/1mi00vhe下载 后面还...

    android/iphone/windows/linux/微信 声波通信-声波wifi配码库(2020)

    性能非常强,没有运行不了的平台,而且通过内存池优化,长时间解码不再分配新内存,可7*24小时运行 可支持任何平台,常见的平台android , iphone, windows, linux, arm, mipsel, stm32都有示例。 详情了解:...

    android/iphone/windows/linux声波通信库(2019)

    可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel, stm32都有示例。 详情了解:http://blog.csdn.net/softlgh/article/details/40507623 没有积分的也可从...

    android/iphone/windows/linux/微信 声波通信-声波wifi配码库(2021)

    接口非常简单,3分钟就可以让你的应用增加声波通讯功能 抗干扰性强,基本上无论外界怎么干扰,信号都是准确的 可自己任意调整通信频段,支持低频有声频段,也支持高频无声频段,无声频段可混音任意效果声音,如咻...

    android/iphone/windows/linux/微信 声波通信-声波wifi配码库(2023)

    接口非常简单,3分钟就可以让你的应用增加声波通讯功能 抗干扰性强,基本上无论外界怎么干扰,信号都是准确的 可自己任意调整通信频段,支持低频有声频段,也支持高频无声频段,无声频段可混音任意效果声音,如咻...

    android/iphone/windows/linux/微信 声波通信-声波wifi配码库(2022)

    接口非常简单,3分钟就可以让你的应用增加声波通讯功能 抗干扰性强,基本上无论外界怎么干扰,信号都是准确的 可自己任意调整通信频段,支持低频有声频段,也支持高频无声频段,无声频段可混音任意效果声音,如咻...

    声波通讯库(2016)

    可支持任何平台,常见的平台android, iphone, windows, linux, arm, mipsel, stm32都有示例。 详情了解:http://blog.csdn.net/softlgh/article/details/40507623 后面还会上传最近两年做过的一些声音信号处理项目:...

Global site tag (gtag.js) - Google Analytics