天天看點

3分鐘為你的應用添加聲波通信功能一、準确性二、接口簡單三、混音音效四、傳輸距離五、性能六、資料傳輸量七、編碼八、使用場景九、運作平台十、代碼及示例

目錄

一、準确性

二、接口簡單

三、混音音效

四、傳輸距離

五、性能

六、資料傳輸量

七、編碼

八、使用場景

九、運作平台

十、代碼及示例

android/iphone/windows/linux/微信 聲波通信庫,使手機與手機或者手機與裝置之間具備通信能力,可廣泛應用于智能裝置的聲波wifi配碼,聲波智能鎖,手機支付,聲波廣告互動,手機名片等領域。

基本特征:

(1)準确性98%以上。

(2)接口非常簡單,有完整的示例,3分鐘就可以讓你的應用增加聲波通信功能

(3)抗幹擾性強,基本上無論外界怎麼幹擾,信号都是準确的

(4)可自己任意調整通信頻段,支援低頻有聲頻段,也支援高頻無聲頻段,無聲頻段可混音任意效果聲音,如咻咻咻之類的。

(5)支援半雙工通信,使用兩個頻段可支援全雙工通信。

(6)可同時最多支援3個頻段進行通信。

(7)通信速度正常在60bps,也可調整到120bps或者200bps(包含校驗和糾錯碼)。

(8)基本的編碼為16進制,而通過編碼可傳輸任何字元

(9)一般通信的傳輸距離版本1米以内,加大音量可在5-10米,聲波廣告互動的信号傳輸距離在10-20米以上,通過裝置傳輸距離可在50米以上

(10)性能非常強,沒有運作不了的平台,而且通過記憶體池優化,長時間解碼不再配置設定新記憶體,可7*24小時運作

可支援任何平台,常見的平台android, iphone, windows, linux, arm, mipsel, stm32,微信小程式 都可以運作。

效果超牛的聲波通信,聲音指紋微信小程式版,請點這裡。

一、準确性

準确性98%以上,如果有識别有問題的情況,你可以開啟調試模式,該模式下會自動儲存識别失敗的的音頻段,你可以發給我分析識别失敗的原因,如果真是識别器沒有考慮到的情況的話,調整識别規則就可以完善識别到了。而且傳輸中加入了校驗碼,校驗碼有兩個目的,一個是保證識别正确性。保證識别結果不然就識别失敗,而如果識别到了就一定是對的,也就是說不會出現傳輸的是1,而識别提示為0;另一個是錯誤自動修正,進而保證傳輸中可以有20%左右(取決于你傳輸的資料長度)的錯誤而可以自動修正,進而使得使用過程中基本上識别是不會出錯的。識别接口中參數指定了識别是否成功完成,錯誤碼指出了如果識别失敗的話,失敗的原因。

二、接口簡單

我的接口盡量做得簡單,這樣用起來也比較小白,既然是當成一個庫,使用起來越簡單越好,就盡量不要去管底層的一些控制參數,比如說聲音采樣頻率、采樣精度、采樣格式、傳輸頻率、傳輸碼表、音量、緩沖區大小,這些在參數中你就不用管了,當然你想定制的話其實這些參數也全部是都是可以定制的。在這裡,這些參數的預設值我也說一下:聲音方面預設參數為:聲音采樣頻率為44100,單聲道,2個位元組(16位)長的采樣精度,小端編碼,桢大小就為1*2=2個位元組,那麼每秒處理的資料量就是44100*2=88200位元組。傳輸頻率為高頻段,抗幹擾能力非常好,不管你是在鬧市、馬路、KTV、或者其它室外場景下,或者你在家裡開着大音箱聽歌都不會影響到資料的傳輸。碼表為16進制的資料編碼,也就是所有資料都會編成16進制後傳輸。緩沖區的話預設需10k左右的緩沖區(裡面其它的記憶體配置設定都在記憶體池中完成,長時間運作解碼不會再配置設定記憶體)。如果這些參數你完全不懂,就忽略就算了,因為接口足夠簡單,能用就可以了,也不用了解那麼多原理。不過解碼器要求你傳入的音頻資料是這些格式,特别是輸入資料要求為44100,單聲道,16bits采樣精度,小端編碼的音頻資料。

三、混音音效

另外實際上因為傳輸頻率屬于高頻段,開始超出正常人可聽到的階段,是以發送的時候感覺沒什麼反應一樣,是以可以在人耳可聽到的範圍另外加一段可聽到的音頻音效(咻咻咻、啾啾啾随便你,呵呵)讓使用者知道系統正在通訊中,最後的效果就是人聽到的是人耳可聽到那部分你加的音頻音效,可實際上裝置則可解碼出真正的信号,而不會互相幹擾。

四、傳輸距離

傳輸距離的話是取決于音量的,音量比較大的,傳輸距離就大,一般手機使用在1米之内,加大音量可在5-10米,特别定制聲波廣告互動的版本信号傳輸距離在10-20米以上,通過裝置傳輸距離可在50米以上

五、性能

至于性能,系統有兩種工作模式:一種是優化記憶體模式,耗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進制聲波通信編碼:

/************************************************************************
聲波通信庫示例,16進制聲波通信編碼
聲波通信庫特征:
準确性98%以上,其實一般是不會出錯的。
接口非常簡單,有完整的示例,3分鐘就可以讓你的應用增加聲波通信功能
抗幹擾性強,基本上無論外界怎麼幹擾,信号都是準确的
基本的編碼為16進制,而通過編碼可傳輸任何字元
性能非常強,沒有運作不了的平台,而且通過記憶體池優化,長時間解碼不再配置設定新記憶體,可7*24小時運作
可支援任何平台,常見的平台android, iphone, windows, linux, arm, mipsel都有示例
詳情可檢視:http://blog.csdn.net/softlgh
作者: 夜行俠 QQ:3116009971 郵件:[email protected]
************************************************************************/


//13,14,15,18開頭的手機号,手機号去除1以後,16進制在9位以内
public static String encode(String _mobile)
{
    if(_mobile.length() == 11 && _mobile.startsWith("1"))
    {    
    	long _number = Long.parseLong(_mobile.substring(1));
      String s = Long.toHexString(_number);
      while(s.length() < 9)
      {
          s = "0" + s;
      }
      return s;
    }
    return null;
}
           

任意字元串(先換成byte[])編成16進制聲波通信編碼:

/************************************************************************
聲波通信庫示例,16進制聲波通信編碼
聲波通信庫特征:
準确性98%以上,其實一般是不會出錯的。
接口非常簡單,有完整的示例,3分鐘就可以讓你的應用增加聲波通訊功能
抗幹擾性強,基本上無論外界怎麼幹擾,信号都是準确的
基本的編碼為16進制,而通過編碼可傳輸任何字元
性能非常強,沒有運作不了的平台,而且通過記憶體池優化,長時間解碼不再配置設定新記憶體,可7*24小時運作
可支援任何平台,常見的平台android, iphone, windows, linux, arm, mipsel都有示例
詳情可檢視:http://blog.csdn.net/softlgh
作者: 夜行俠 QQ:3116009971 郵件:[email protected]
************************************************************************/

public static final char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
public static String encodeString(byte[] _val)
{
    StringBuffer result = new StringBuffer(_val.length*2);
    for(int i = 0; i < _val.length; i ++)
    {
        result.append(hexChars[(_val[i] >> 4) & 0x0f]);
        result.append(hexChars[_val[i] & 0x0f]);
    }
    return result.toString();
}
           

八、使用場景

這裡也把現在市場上的一些應用到了聲波的先列一下:支付寶的聲波支付,微信的聲波雷達加好友,QQ音樂中的歌曲的聲波分享,茄子快傳,蛐蛐兒等等,國外的apple,google對聲波通信也都有應用。

聲波實際上可以看成是一種比二維碼可友好的傳輸方式,二維碼能實作的功能與聲波有很大的相似性,但聲波使用時會更友好。做以上這些功能的時候,基本上都是隻要靠近在手機上點一下/劃一下/推一下/甩一下/搖一下(這是你自己定的)就可以了,而不需要像二維碼一樣還要打開攝像頭、對準去拍那樣比較麻煩。相比來說,聲波傳輸更像刷卡一樣友善簡單,可以了解為類似NFC的一種近場通信技術。

比如說你可以用聲波支付,聲波會員卡,聲波券票,聲音名片,聲波簽到,聲波排隊,做wifi和密碼共享或者設定,做檔案/圖檔、你App裡面的任何項目分享,用聲波關注微網誌、微信等等。

聲波支付的流程前面有講過,實際上有可能稍微複雜一點,但大概是這樣的思路。

聲波會員卡是指使用者到店鋪後不需要帶實體卡了,而是手機代替了所有的會員卡,在商家一碰,會員資訊就自動顯示出來了。

聲波券票也很簡單,比如說一張電子團購券,電子電影券,可以設定成一個唯一的編碼,到場後與錄音裝置一碰,系統就能識别到這張券票

聲波簽到是指在固定位置安裝簽到軟體,使用者到達後,可以快速完成簽到操作。 

聲波分享以檔案/圖檔、或者你App裡面的任何項目為例:比如A要把一張圖檔發送給B,那麼A點選一下共享按鈕(或者一推一丢都行),這時手機通過聲音把這個圖檔的編号發送出去,當B收到這個标志時,馬上從你平台的伺服器上下載下傳這張圖檔。最後的效果就是A在要分享的圖檔上一點,B就能收到該張圖檔,非常的友善快捷。

九、運作平台

這個聲波傳輸庫可以運作在windows平台(所有windows系統), linux平台, mipsel平台, arm平台, iphone平台, android平台,全部都有SDK,後面的附件中有各個平台的庫,你自己可以選擇下載下傳

十、代碼及示例

庫的結構非常簡單:一個發送端,一個接收端。發送端很簡單,基本上就是一個send函數。接收端稍微複雜一點,但也是很簡單的:建立一個解碼器,設定監聽,往解碼器送音頻資料(解碼器就會開始分析音頻資料,并在監聽到信号後通知你),最後停止解碼器和銷毀解碼器。使用還是很簡單的,下面和附件中有例子說明。

這種庫的使用畢竟是商用,是以就不能免費了,呵呵。不過如果你完全是沒有任何商業目的的公益項目,我也是完全可以免費給你用的。

試用庫識别次數有限,或者沒有進行降噪處理

各個平台的例子及源碼

android平台聲波通信發送端接口:

/************************************************************************
聲波通訊庫示例,android平台聲波通訊發送端
聲波通訊庫特征:
準确性98%以上,其實一般是不會出錯的。
接口非常簡單,有完整的示例,3分鐘就可以讓你的應用增加聲波通訊功能
抗幹擾性強,基本上無論外界怎麼幹擾,信号都是準确的
基本的編碼為16進制,而通過編碼可傳輸任何字元
性能非常強,沒有運作不了的平台,而且通過記憶體池優化,長時間解碼不再配置設定新記憶體,可7*24小時運作
可支援任何平台,常見的平台android, iphone, windows, linux, arm, mipsel都有示例
詳情可檢視:http://blog.csdn.net/softlgh
作者: 夜行俠 QQ:3116009971 郵件:[email protected]
************************************************************************/


//建立聲波通訊播放器
player = new VoicePlayer();
//開始播放
player.play("12345678abcdef", 1, 200);
           

iphone平台聲波通訊發送端接口:

/************************************************************************
聲波通訊庫示例,iphone平台聲波通訊發送端
聲波通訊庫特征:
準确性98%以上,其實一般是不會出錯的。
接口非常簡單,有完整的示例,3分鐘就可以讓你的應用增加聲波通訊功能
抗幹擾性強,基本上無論外界怎麼幹擾,信号都是準确的
基本的編碼為16進制,而通過編碼可傳輸任何字元
性能非常強,沒有運作不了的平台,而且通過記憶體池優化,長時間解碼不再配置設定新記憶體,可7*24小時運作
可支援任何平台,常見的平台android, iphone, windows, linux, arm, mipsel都有示例
詳情可檢視:http://blog.csdn.net/softlgh
作者: 夜行俠 QQ:3116009971 郵件:[email protected]
************************************************************************/


NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init];
//建立聲波通訊播放器
VoicePlayer *player=[[VoicePlayer alloc] init];
//播放
[player play:@"12345678" playCount:1 muteInterval:0];
//沒播放完之前,不要釋放記憶體
while (![player isStopped]) {
    usleep(300 * 1000);//300ms
}
[tempPool drain];
           

Android平台聲波通信解碼端代碼:

/************************************************************************
聲波通訊庫示例,Android平台聲波通訊解碼端
聲波通訊庫特征:
準确性98%以上,其實一般是不會出錯的。
接口非常簡單,有完整的示例,3分鐘就可以讓你的應用增加聲波通訊功能
抗幹擾性強,基本上無論外界怎麼幹擾,信号都是準确的
基本的編碼為16進制,而通過編碼可傳輸任何字元
性能非常強,沒有運作不了的平台,而且通過記憶體池優化,長時間解碼不再配置設定新記憶體,可7*24小時運作
可支援任何平台,常見的平台android, iphone, windows, linux, arm, mipsel都有示例
詳情可檢視:http://blog.csdn.net/softlgh
作者: 夜行俠 QQ:3116009971 郵件:[email protected]
************************************************************************/
VoiceRecognition mRecognition = new VoiceRecognition();
mRecognition.setListener(new VoiceRecognitionListener()
{
    @Override
    public void onRecognitionStart() {
    }

    public void onRecognitionEnd(int _recogStatus, String _val)
    {
        if(_recogStatus == VoiceRecognition.Status_Success)
        {
            System.out.println(_val);
        }
    }
});
mRecognition.start();
           

c通用聲波通訊解碼端接口

/************************************************************************
聲波通訊庫示例,聲波通訊庫c解碼接口
聲波通訊庫特征:
準确性98%以上,其實一般是不會出錯的。
接口非常簡單,有完整的示例,3分鐘就可以讓你的應用增加聲波通訊功能
抗幹擾性強,基本上無論外界怎麼幹擾,信号都是準确的
基本的編碼為16進制,而通過編碼可傳輸任何字元
性能非常強,沒有運作不了的平台,而且通過記憶體池優化,長時間解碼不再配置設定新記憶體,可7*24小時運作
可支援任何平台,常見的平台android, iphone, windows, linux, arm, mipsel都有示例
詳情可檢視:http://blog.csdn.net/softlgh
作者: 夜行俠 QQ:3116009971 郵件:[email protected]
************************************************************************/
#ifdef VOICE_RECOG_DLL
#define VOICERECOGNIZEDLL_API __declspec(dllexport)
#else
#ifdef WIN32
#define VOICERECOGNIZEDLL_API __declspec(dllimport)
#else
#define VOICERECOGNIZEDLL_API
#endif
#endif

#ifndef VOICE_RECOG_H
#define VOICE_RECOG_H

#ifdef __cplusplus
extern "C" {
#endif
	enum VRErrorCode
	{
		VR_SUCCESS = 0
	};

	enum DecoderPriority
	{
		CPUUsePriority = 1//不占記憶體,但CPU消耗比較大一些
		, MemoryUsePriority = 2//不占CPU,但記憶體消耗大一些
	};

	typedef enum {vr_false = 0, vr_true = 1} vr_bool;

	typedef void (*vr_pRecognizerStartListener)(void);
	//_result如果為VR_SUCCESS,則表示識别成功,否則為錯誤碼,成功的話_data才有資料
	typedef void (*vr_pRecognizerEndListener)(int _result, char *_data, int _dataLen);

	//建立聲波識别器
	VOICERECOGNIZEDLL_API void *vr_createVoiceRecognizer(DecoderPriority _decoderPriority = CPUUsePriority);

	//銷毀識别器
	VOICERECOGNIZEDLL_API void vr_destroyVoiceRecognizer(void *_recognizer);

	//設定識别到信号的監聽器
	VOICERECOGNIZEDLL_API void vr_setRecognizerListener(void *_recognizer, vr_pRecognizerStartListener _startListener, vr_pRecognizerEndListener _endListener);

	//開始識别
	//這裡一般是線程,這個函數在停止識别之前不會傳回
	VOICERECOGNIZEDLL_API void vr_runRecognizer(void *_recognizer);

	//停止識别,該函數調用後vr_runRecognizer會傳回
	//該函數隻是向識别線程發出退出信号,判斷識别器是否真正已經退出要使用以下的vr_isRecognizerStopped函數
	VOICERECOGNIZEDLL_API void vr_stopRecognize(void *_recognizer);

	//判斷識别器線程是否已經退出
	VOICERECOGNIZEDLL_API vr_bool vr_isRecognizerStopped(void *_recognizer);

	//要求輸入資料要求為44100,單聲道,16bits采樣精度,小端編碼的音頻資料
	//小端編碼不用特别處理,一般你錄到的資料都是小端編碼的
	VOICERECOGNIZEDLL_API int vr_writeData(void *_recognizer, char *_data, int _dataLen);

#ifdef __cplusplus
}
#endif

#endif
           

使用c聲波通訊接口從wav檔案中解碼的例子:

/************************************************************************
聲波通訊庫示例,從wav檔案中讀取音頻信号進行解碼,該工程示例是可跨平台的
聲波通訊庫特征:
準确性98%以上,其實一般是不會出錯的。
接口非常簡單,有完整的示例,3分鐘就可以讓你的應用增加聲波通訊功能
抗幹擾性強,基本上無論外界怎麼幹擾,信号都是準确的
基本的編碼為16進制,而通過編碼可傳輸任何字元
性能非常強,沒有運作不了的平台,而且通過記憶體池優化,長時間解碼不再配置設定新記憶體,可7*24小時運作
可支援任何平台,常見的平台android, iphone, windows, linux, arm, mipsel都有示例
詳情可檢視:http://blog.csdn.net/softlgh
作者: 夜行俠 QQ:3116009971 郵件:[email protected]
************************************************************************/
//當次解碼結束的回調函數
void waveRecognizerEnd(int _recogStatus, char *_data, int _dataLen)
{
	if (_recogStatus == VR_SUCCESS)
	{
		char buf[51];
		memcpy(buf, _data, _dataLen);
		buf[_dataLen] = 0;
		printf("------------------recognized data:%s\n", buf);
	}
	else
	{
		printf("------------------recognize invalid data, errorCode:%d\n", _recogStatus);
	}
}

//識别到有信号時開始解碼回調函數
void waveRecognizerStart()
{
	printf("------------------recognize start\n");
}

//WIN32與linux所需的線程函數原型有點不一樣
#ifdef WIN32
DWORD WINAPI waveRunVoiceRecognize( LPVOID _recognizer)  
{
#else
void *waveRunVoiceRecognize( void * _recognizer) 
{
	printf("voice recognizer thread start:%d\n", getpid());
#endif
	vr_runRecognizer(_recognizer);
	return 0;
}

//從wav檔案中裝載資料進入聲波識别器
void test_voiceRecog_from_wav(int argc, char* argv[])
{
	char *wavFile = (char *)"data.wav";
	if(argc > 1)
	{
		wavFile = argv[1];
	}

	//讀入wav檔案
	struct WavData wavData;
	memset(&wavData, 0, sizeof(wavData));
	readWave(wavFile, &wavData);
	printf("%s data size:%d\n", wavFile, (int)wavData.size);

	//建立識别器,并開始運作
	void *recognizer = vr_createVoiceRecognizer(MemoryUsePriority);
	vr_setRecognizerListener(recognizer, waveRecognizerStart, waveRecognizerEnd);
#ifdef WIN32
	HANDLE recogThread = CreateThread( NULL, 0, waveRunVoiceRecognize, recognizer, 0, 0 );
	//_beginthread(waveRunVoiceRecognize, 0, recognizer);
#else
	pthread_t recogThread;
	pthread_create(&recogThread, NULL, waveRunVoiceRecognize, recognizer);
	//printf("voice recognizer thread id:%lu\n", (recogThread));
#endif

	//往識别器寫入資料,這裡可以反複寫
	vr_writeData(recognizer, wavData.data, wavData.size);

	//通知識别器停止,并等待識别器真正退出
	do 
	{
		vr_stopRecognize(recognizer);
		printf("recognizer is quiting\n");
#ifdef WIN32
		Sleep(1000);
#else
		sleep(1);
#endif
	} while (!vr_isRecognizerStopped(recognizer));

	//銷毀識别器
	vr_destroyVoiceRecognizer(recognizer);

	printf("press enter key to exit.......\n");
	char c;
	scanf("%c", &c);
}
           

使用c聲波通訊接口從實時錄音資料中解碼的例子:

/************************************************************************
聲波通訊庫示例,從實時錄音資料擷取音頻信号進行解碼,該工程示例是可跨平台的
聲波通訊庫特征:
準确性98%以上,其實一般是不會出錯的。
接口非常簡單,有完整的示例,3分鐘就可以讓你的應用增加聲波通訊功能
抗幹擾性強,基本上無論外界怎麼幹擾,信号都是準确的
基本的編碼為16進制,而通過編碼可傳輸任何字元
性能非常強,沒有運作不了的平台,而且通過記憶體池優化,長時間解碼不再配置設定新記憶體,可7*24小時運作
可支援任何平台,常見的平台android, iphone, windows, linux, arm, mipsel都有示例
詳情可檢視:http://blog.csdn.net/softlgh
作者: 夜行俠 QQ:3116009971 郵件:[email protected]
************************************************************************/
//識别到有信号時開始解碼回調函數
void recorderRecognizerStart()
{
	printf("------------------recognize start\n");
}

//當次解碼結束的回調函數
void recorderRecognizerEnd(int _recogStatus, char *_data, int _dataLen)
{
	if (_recogStatus == VR_SUCCESS)
	{
		char buf[51];
		memcpy(buf, _data, _dataLen);
		buf[_dataLen] = 0;
		printf("------------------recognized data:%s\n", buf);
	}
	else
	{
		printf("------------------recognize invalid data, errorCode:%d\n", _recogStatus);
	}
}

#ifdef WIN32
void runRecorderVoiceRecognize( void * _recognizer)  
#else
void *runRecorderVoiceRecognize( void * _recognizer) 
#endif
{
	vr_runRecognizer(_recognizer);
}

int recorderShortWrite(void *_writer, const void *_data, unsigned long _sampleCout)
{
	char *data = (char *)_data;
	void *recognizer = _writer;
	return vr_writeData(recognizer, data, (int)_sampleCout);
}

void test_recorderVoiceRecog()
{
	//建立識别器,并設定監聽器
	void *recognizer = vr_createVoiceRecognizer();
	vr_setRecognizerListener(recognizer, recorderRecognizerStart, recorderRecognizerEnd);
	//建立錄音機
	void *recorder = NULL;
	int r = initRecorder(44100, 1, 16, 512, &recorder);//要求錄取short資料
	if(r != 0)
	{
		printf("recorder init error:%d", r);
		return;
	}
	//開始錄音
	//r = startRecord(recorder, recognizer, recorderFloatWrite);//float資料
	r = startRecord(recorder, recognizer, recorderShortWrite);//short資料
	if(r != 0)
	{
		printf("recorder record error:%d", r);
		return;
	}
	//開始識别
#ifdef WIN32
	//CreateThread( NULL, 0, runRecorderVoiceRecognize, recognizer, 0, 0 );
	_beginthread(runRecorderVoiceRecognize, 0, recognizer);
#else
	pthread_t ntid;
	pthread_create(&ntid, NULL, runRecorderVoiceRecognize, recognizer);
#endif
	printf("\n\n\nrecognize start, waiting for signals ............\n");
	char c = 0;
	do 
	{
		printf("press q to end recognize\n");
		scanf_s("%c", &c);
	} while (c != 'q');

	//停止錄音
	r = stopRecord(recorder);
	if(r != 0)
	{
		printf("recorder stop record error:%d", r);
	}
	r = releaseRecorder(recorder);
	if(r != 0)
	{
		printf("recorder release error:%d", r);
	}

	//通知識别器停止,并等待識别器真正退出
	do 
	{
		vr_stopRecognize(recognizer);
		printf("recognizer is quiting\n");
#ifdef WIN32
		Sleep(1000);
#else
		sleep(1);
#endif
	} while (!vr_isRecognizerStopped(recognizer));

	//銷毀識别器
	vr_destroyVoiceRecognizer(recognizer);
}
           

相應的錄音機抽象接口:

/************************************************************************
聲波通訊庫示例,錄音機抽象接口,該工程示例是可跨平台的
聲波通訊庫特征:
準确性98%以上,其實一般是不會出錯的。
接口非常簡單,有完整的示例,3分鐘就可以讓你的應用增加聲波通訊功能
抗幹擾性強,基本上無論外界怎麼幹擾,信号都是準确的
基本的編碼為16進制,而通過編碼可傳輸任何字元
性能非常強,沒有運作不了的平台,而且通過記憶體池優化,長時間解碼不再配置設定新記憶體,可7*24小時運作
可支援任何平台,常見的平台android, iphone, windows, linux, arm, mipsel都有示例
詳情可檢視:http://blog.csdn.net/softlgh
作者: 夜行俠 QQ:3116009971 郵件:[email protected]
************************************************************************/

//_data的資料格式是根據initRecorder傳入的資料類型定的,一般可能為short。
//_sampleCout是表示_data中含有的樣本數,不是指_data的長度
//傳回已經處理的信号數,如果傳回-1,則錄音線程應退出
typedef int (*r_pwrite)(void *_writer, const void *_data, unsigned long _sampleCout);

/************************************************************************/
/* 建立錄音機
/* _sampleRateInHz為44100
/* _channel為單聲道,1為單聲道,2為立體聲
/* _audioFormat為一個信号的bit數,單聲道雙位元組精度的話為16
/************************************************************************/
int initRecorder(int _sampleRateInHz, int _channel, int _audioFormat, int _bufferSize, void **_precorder);

/************************************************************************/
/* 開始錄音
/************************************************************************/
int startRecord(void *_recorder, void *_writer, r_pwrite _pwrite);

/************************************************************************/
/* 停止錄音
/************************************************************************/
int stopRecord(void *_recorder);

/************************************************************************/
/* 釋放錄音器的資源
/************************************************************************/
int releaseRecorder(void *_recorder);
           

使用PA實作的錄音機接口,可跨平台:

/************************************************************************
聲波通訊庫示例,PA庫實作的錄音機接口,該庫是跨平台的
聲波通訊庫特征:
準确性98%以上,其實一般是不會出錯的。
接口非常簡單,有完整的示例,3分鐘就可以讓你的應用增加聲波通訊功能
抗幹擾性強,基本上無論外界怎麼幹擾,信号都是準确的
基本的編碼為16進制,而通過編碼可傳輸任何字元
性能非常強,沒有運作不了的平台,而且通過記憶體池優化,長時間解碼不再配置設定新記憶體,可7*24小時運作
可支援任何平台,常見的平台android, iphone, windows, linux, arm, mipsel都有示例
詳情可檢視:http://blog.csdn.net/softlgh
作者: 夜行俠 QQ:3116009971 郵件:[email protected]
************************************************************************/

#include "record.h"
#include <stdio.h>
#include <stdlib.h>
//#include <syslib.h>
#include "portaudio.h"

#pragma comment(lib, "portaudio_x86.lib")

#define SAMPLE_RATE  (44100)
#define FRAMES_PER_BUFFER (512)
#define NUM_SECONDS     (5)
#define NUM_CHANNELS    (2)
#define DITHER_FLAG     (0) /**/
#define WRITE_TO_FILE   (0)

/* Select sample format. */
#if 1
#define PA_SAMPLE_TYPE  paFloat32
typedef float SAMPLE;
#define SAMPLE_SILENCE  (0.0f)
#define PRINTF_S_FORMAT "%.8f"
#elif 1
#define PA_SAMPLE_TYPE  paInt16
typedef short SAMPLE;
#define SAMPLE_SILENCE  (0)
#define PRINTF_S_FORMAT "%d"
#elif 0
#define PA_SAMPLE_TYPE  paInt8
typedef char SAMPLE;
#define SAMPLE_SILENCE  (0)
#define PRINTF_S_FORMAT "%d"
#else
#define PA_SAMPLE_TYPE  paUInt8
typedef unsigned char SAMPLE;
#define SAMPLE_SILENCE  (128)
#define PRINTF_S_FORMAT "%d"
#endif

struct PARecorder
{
	PaStream* stream;
	PaStreamParameters  inputParameters,
		outputParameters;
	int sampleRateInHz, channel, audioFormat, bufferSize;
	void *writer;
	r_pwrite write;
};

/* This routine will be called by the PortAudio engine when audio is needed.
** It may be called at interrupt level on some machines so don't do anything
** that could mess up the system like calling malloc() or free().
*/
static int recordCallback( const void *inputBuffer, void *outputBuffer,
	unsigned long framesPerBuffer,
	const PaStreamCallbackTimeInfo* timeInfo,
	PaStreamCallbackFlags statusFlags,
	void *userData )
{
	//void *recognizer = userData;
	PARecorder *recorder = (PARecorder *)userData;
	int r = recorder->write(recorder->writer, inputBuffer, framesPerBuffer);
	if (r >= 0)
	{
		return paContinue;
	}
	else
	{
		return paComplete;
	}
}

int initRecorder(int _sampleRateInHz, int _channel, int _audioFormat, int _bufferSize, void **_precorder)
{
	PaError err = Pa_Initialize();
	if( err != paNoError ) 
	{
		Pa_Terminate();
	}
	PARecorder *recorder = new PARecorder();
	recorder->stream = NULL;
	recorder->sampleRateInHz = _sampleRateInHz;
	recorder->channel = _channel;
	recorder->audioFormat = _audioFormat;
	recorder->bufferSize = _bufferSize;
	recorder->writer = NULL;
	*_precorder = recorder;

	return err;
}

int startRecord(void *_recorder, void *_writer, r_pwrite _pwrite)
{
	PARecorder* recorder = (PARecorder*)_recorder;
	recorder->write = _pwrite;
	recorder->writer = _writer;
	PaStreamParameters *inputParameters = &recorder->inputParameters;
	inputParameters->device = Pa_GetDefaultInputDevice(); /* default input device */
	if (inputParameters->device == paNoDevice) {
		fprintf(stderr,"Error: No default input device.\n");
		Pa_Terminate();
		return -1;//這個編号要與PA的其它編号不重複
	}
	inputParameters->channelCount = recorder->channel;
	if(recorder->audioFormat == 0)inputParameters->sampleFormat = paFloat32;
	else inputParameters->sampleFormat = paInt16;
	//inputParameters->sampleFormat = PA_SAMPLE_TYPE;
	inputParameters->suggestedLatency = Pa_GetDeviceInfo( inputParameters->device )->defaultLowInputLatency;
	inputParameters->hostApiSpecificStreamInfo = NULL;

	/* Record some audio. -------------------------------------------- */
	PaError err = Pa_OpenStream(
		&recorder->stream,
		&recorder->inputParameters,
		NULL,                  /* &outputParameters, */
		recorder->sampleRateInHz,
		recorder->bufferSize,
		paClipOff,      /* we won't output out of range samples so don't bother clipping them */
		recordCallback,
		recorder );
	if (err == paNoError)
	{
		err = Pa_StartStream( recorder->stream );
	}
	if( err != paNoError ) 
	{
		delete recorder;
	}
	return err;
}

int stopRecord(void *_recorder)
{
	PaError err = paNoError;
	if(_recorder != NULL)
	{
		PARecorder *recorder = (PARecorder *)_recorder;
		PaError err = Pa_CloseStream( recorder->stream );
	}
	return err;
}

int releaseRecorder(void *_recorder)
{
	PaError err = paNoError;
	err = Pa_Terminate();
	if(_recorder != NULL)
	{
		PARecorder *recorder = (PARecorder *)_recorder;
		delete recorder;
	}
	return err;
}
           

所有代碼都在附件中

附件說明:

各平台相應的檔案在相應平台的檔案夾下,有些平台檔案夾下隻有編碼端或者解碼端,或者是因為不需要,或者是我自己現在沒用到,也懶得去編譯了,你自己需要的時候找我吧。各平台的庫是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檔案夾下

詳情可檢視:http://blog.csdn.net/softlgh

作者: 夜行俠 QQ:3116009971 郵件:[email protected]

android/iphone/windows/linux/微信 聲波通信庫及源碼:

百度盤下載下傳:https://pan.baidu.com/s/1co0TaQ5KAFFc-MBdrIA6MA

csdn下載下傳

相關參考:

基于聲波通信和聲音指紋的線上線下互動

聲波通信的原理

3分鐘為你的應用添加聲波通信功能

android/iphone/windows/linux/微信聲波通信庫

Android/iphone/微信手機通過聲波初始化智能裝置的WIFI資訊

繼續閱讀