支付宝中当面付的通过音频传输数据的研究(1)


  1102人阅读  评论(1)  收藏  举报
FFT 快速傅里叶变换 支付宝 超声波

近日公司提出了一个需求,要求做一个类似当面付中通过音频传输用户ID的方法。

拿到任务后马上祭起GOOGLE大法去查找。(此处再次吐槽一下GWF——我去年买了个表,超耐磨)

首先找到的是一个开源的软件 https://github.com/JesseGu/SinVoice 是Android的 。

首先试用,但是发现这个软件在传输过程中会有很多尖锐的声音产生,而支付宝就没有。

不管了,先看代码。。

里面有2个重要的类,SinGenerator(正弦生成)、VoiceRecognition(声音识别)。

经过研究 其原理就是通过SinGenerator将数据转换为不同频率的音频, 然后播放出去,接受方收到数据后查找从整数到负数变化的点,标记好后先后继续查找,当再找找到从整数到负数的变化点后,用新的变化点减去标记的变化点,就得出了一个时间,然后就可以算出这个正弦音频的频率。

生成音频的主要过程(

[java]  view plain copy
  1. public void gen(int genRate, int duration) {  
  2.        if (STATE_START == mState) {  
  3.            mGenRate = genRate;  
  4.            mDuration = duration;  
  5.   
  6.            if (null != mListener) {  
  7.                mListener.onStartGen();  
  8.            }  
  9.   
  10.            int n =  mBits/2;  
  11.            int totalCount = (mDuration * mSampleRate) / 1000//441个采样点  
  12.            double per = ( 2 * Math.PI * (double)mGenRate / (double) mSampleRate) ;  
  13.            double d =0;  
  14.            LogHelper.d(TAG, "genRate:" + genRate);  
  15.            if (null != mCallback) {  
  16.                mFilledSize = 0;  
  17.                BufferData buffer = mCallback.getGenBuffer();  
  18.                if (null != buffer) {  
  19.                    for (int i = 0; i < totalCount; ++i) {  
  20.                        if (STATE_START == mState) {  
  21.                            int out = (int) (Math.sin(dh)*n) ;  
  22.                            if (mFilledSize >= mBufferSize - 1) {  
  23.                                // free buffer  
  24.                                buffer.setFilledSize(mFilledSize);  
  25.                                mCallback.freeGenBuffer(buffer);  
  26.   
  27.                                mFilledSize = 0;  
  28.                                buffer = mCallback.getGenBuffer();  
  29.                                if (null == buffer) {  
  30.                                    LogHelper.d(TAG, "get null buffer");  
  31.                                    break;  
  32.                                }  
  33.                            }  
  34.   
  35.                            buffer.mData[mFilledSize++] = (byte) (out & 0xff);  
  36.                            if (BITS_16 == mBits) {  
  37.                                buffer.mData[mFilledSize++] = (byte) ((out >> 8) & 0xff);  
  38.                            }  
  39.   
  40.                            d +=per;  
  41.                        } else {  
  42.                            LogHelper.d(TAG, "sin gen force stop");  
  43.                            break;  
  44.                        }  
  45.                    }  
  46.                } else {  
  47.                    LogHelper.d(TAG, "get null buffer");  
  48.                }  
  49.   
  50.                if (null != buffer) {  
  51.                    buffer.setFilledSize(mFilledSize);  
  52.                    mCallback.freeGenBuffer(buffer);  
  53.                }  
  54.                mFilledSize = 0;  
  55.   
  56.                if (null != mListener) {  
  57.                    mListener.onStopGen();  
  58.                }  
  59.            }  
  60.        }  
  61.    }  


识别的主要函数

[java]  view plain copy
  1. private void process(BufferData data) {  
  2.         int size = data.getFilledSize() - 1;  
  3.         short sh = 0;  
  4.         for (int i = 0; i < size; i++) {  
  5.             short sh1 = data.mData[i];  
  6.             sh1 &= 0xff;  
  7.             short sh2 = data.mData[++i];  
  8.             sh2 <<= 8;  
  9.             sh = (short) ((sh1) | (sh2));  
  10.   
  11.             if (!mIsStartCounting) {  
  12.                 if (STATE_STEP1 == mStep) {  
  13.                     if (sh < 0) {  
  14.                         mStep = STATE_STEP2;  
  15.                     }  
  16.                 } else if (STATE_STEP2 == mStep) {  
  17.                     if (sh > 0) {  
  18.                         mIsStartCounting = true;  
  19.                         mCirclePointCount = 0;  
  20.                         mStep = STATE_STEP1;  
  21.                     }  
  22.                 }  
  23.             } else {  
  24.                 ++mCirclePointCount;  
  25.                 if (STATE_STEP1 == mStep) {  
  26.                     if (sh < 0) {  
  27.                         mStep = STATE_STEP2;  
  28.                     }  
  29.                 } else if (STATE_STEP2 == mStep) {  
  30.                     if (sh > 0) {  
  31.                         // preprocess the circle  
  32.                         int circleCount = preReg(mCirclePointCount);  
  33.   
  34.                         // recognise voice  
  35.                         reg(circleCount);  
  36.   
  37.                         mCirclePointCount = 0;  
  38.                         mStep = STATE_STEP1;  
  39.                     }  
  40.                 }  
  41.             }  
  42.         }  
  43.     }  

后面的事情就是移植的IOS上,很简单,基本上就是把代码复制过去就可以了。

然后给领导看~~~ 领导一句话就将所有的努力变成了狗屎——声音太刺耳。。。。。。。。。

没有办法了,只好去研究当面付

1)录音。 用CoolEdit录音

支付宝中当面付的通过音频传输数据的研究(1)_第1张图片

这就是支付宝产生的音频 其中"咻"的一声是红色的部分,但是我们看到字两个咻之间还是有音频波形,但是听不见,所有由此判断 ,这部分数据肯定是在人的听力范围之外。也就是说, 不是次声波就是超声波。

放大这部分数据

支付宝中当面付的通过音频传输数据的研究(1)_第2张图片


放大的波形还是没有什么特点,而且频率都一样,接近50Hz(次声波),所以由此判断数据还是不对,只有继续放大。

支付宝中当面付的通过音频传输数据的研究(1)_第3张图片


好了到此我们可以肯定 支付宝应该是使用2个正弦的乘积产生的波形 sin(2*PI*超声频率/采样率)*sin(2*PI*次声频率/采样率)——很像调频的公式。

好了 我们可以修改SinGenerator这个类进行来产生类似支付宝的音频。结果很理想,播放出啦后听不见, 用CoolEdit可以采集到类似支付宝的数据。


为题出来了 怎么判断高频啊~~ 因为手机的采样最高为44100,也就是说 最多能表达22050Hz的波形, 而我们的差生的数据有20000Hz,基本上每个采样周期都其数据都回产生呢跨过基线的数据, 素以 已经不能SinVoice的方法判断频率了,太快了。


开始重点了


使用CoolEdit查看支付宝音频的频谱。。。。。。

支付宝中当面付的通过音频传输数据的研究(1)_第4张图片


看到了什么,上面的粗线。。。。原来支付使用超声波频率并不一样,明显是一段一段的,由此判断 数据肯定就是这些。。而且每段都大概是20ms,吼吼。。数据出来了

仔细观察,支付宝的数据都是意48段重复播放的。

既然用CoolEdit的频谱能看到数据 我们用手机算出来这个频谱吧。。。(继续Google大法——再次吐槽GWF)(频谱的计算方法)

搜索后 悲剧了....真心看不懂啊用FFT计算连续信号的频谱.......好吧 怎么说有个关键词了 “FFT”  。什么是FFT呢 ——快速傅里叶变换-,继续不懂。。。。

哥是学计算机的 貌似没有学过这个啊,好吧就算是学过,毕业小20年了,早还给老师了。。。。。

没有办法 学习吧。。。 苦逼。。。。。

下面几篇文章,很不错

http://blog.csdn.net/lhfslhfs/article/details/7684494

http://blog.csdn.net/xuexiang0704/article/details/8295425

http://blog.csdn.net/v_JULY_v/article/details/6196862


好了有目标了 后边慢慢进行吧。。。。

你可能感兴趣的:(支付宝中当面付的通过音频传输数据的研究(1))