微信语音分享

微信是你们平时使用最多的聊天软件,其中能够经过打字、语音、视频等方式进行沟通。可是你们有没有发现一个问题,那就是微信里的语音是分享不了的,就算你是收藏了,而后再分享也会被提示语音格式不支持分享。



咱们想到是否能够以发送文件的方式发送过去呢?咱们首先找到微信保存在本地的语音,在tencent/MicroMsg下面,咱们发现微信的语音文件是.silk后缀名的未知格式文件,而且手机上没有自带app能够打开这种格式的语音。那么若是咱们直接找到该文件发送给好友,微信是否能自动识别而后让好友听到呢?答案是不能够的,当咱们将该语音以文件形式发过去的时候好友并不能播放,说明微信也是作过限制的。那么有没有办法能够将微信的语音分享出去让别人听到呢?答案固然是能够的,这就是做者今天要分享的内容,如何打开微信保存在本地的语音文件。想要实现该功能就必须了解音视频基础,接下来做者来说解一下。java

音视频基础数组


音视频文件如何生成的?
bash

如上图,图像的原始格式是YUV/RGB。因为原始数据过大,须要对原始图像进行压缩成H-264/VP8,压缩过程也叫作编码。微信

同理音频的过程也大体相似,音频的原始格式是PCM,同时也须要进行压缩成AAC/AMR。
app

编码之后将音频和视频封装成一个MP4/FLV文件,即咱们常见的音视频文件。ide


音视频文件时如何播放的?工具

播放其实就是和生成相反的步骤,入上图可看到,首先要解封装,而后音频和视频分别进行解压缩,解码成系统可以识别的格式,进而调用系统硬件进行工做。性能


其实安卓自己提供了录制和播放PCM的操做,只是因为MediaRecorder使用起来更简单易懂,因此可能不是很了解。通过对音视频编解码的了解,那么思路就有了,只要咱们能将微信的.silk文件里的PCM采集出来,那是否是就能够经过Android自带的PCM播放器AudioTrack播放出来了?下面做者就带领你们一块儿学习一下AudioTrack播放PCM的byte数据。
学习


AudioTrack其实使用起来很是简单,只须要4步就搞定了开发工具


步骤一   建立AudioTrack对象

int mBufferSizeInBytes = AudioTrack.getMinBufferSize(

sampleRate, // 采样率,每秒采集数据次数

AudioFormat.CHANNEL_OUT_MONO, // 声道

AudioFormat.ENCODING_PCM_16BIT); // 位数,一个数据16位


mAudioTrack = new AudioTrack(

AudioManager.STREAM_MUSIC, // 音乐流 (告诉系统将该数据当作音乐来播放)

sampleRate, // 采样率 (每秒采样数据的次数,次数越大声音越真实,可是耗性能)

AudioFormat.CHANNEL_OUT_MONO, // 声道 (双声道、单声道等选择好,如今是单声道)

AudioFormat.ENCODING_PCM_16BIT, //采集的数据每一个数据所占的位数

mBufferSizeInBytes, // 缓冲区大小,上面设置好的

AudioTrack.MODE_STREAM);  //设置以流的形式进行播放


步骤二    启动播放器

mAudioTrack.play();


步骤三    开始播放(MODE_STREAM)

mAudioTrack.write(mOutputBuffer, 0, len);


步骤四    中止与释放

mAudioTrack.stop();
mAudioTrack.release();


以上播放的准备已经作好了,只须要拿到PCM往上面的AudioTrack中传入就行了,那么今天重点来了,应该怎么作才能将silk文件中的PCM采集出来呢?


如何从微信语音文件中获取PCM数据

想获取其中的数据就必须知道silk是什么格式其实Silk是Skype开发的开源的音频压缩格式和音频编解码器。它是为在Skype中使用而开发的。实时带宽6-40Kbps便可工做,即便丢包水平达到10%依然能够稳定维持24KHz采样的通话音质,这个是该技术行业很是领先的。

那么Skype又是什么产品呢,Skype是一款即时通信软件,其具有IM所需的功能,好比视频聊天、多人语音会议、多人聊天、传送文件、文字聊天等功能,相似于微信QQ。

总结一下,silk就是就是一个C语言开发的开源的音频编解码库。既然微信是使用的第三方的编码方式,因此思路来了,咱们只须要让开源的silk库对微信语音文件进行解码,再播放便可。

前面说过,silk是一个C语言的库,若是想在Android中使用到C语言的库,就必须进行NDK的开发了。


什么是JNI和NDK?

JNI:

Java Native Interface,JDK提供的一套API,实现了Java和其余语言的通讯(主要是C&C++),它容许Java代码和其余语言写的代码进行交互。

NDK:

Native Development Kit,本地开发工具包

NDK和SDK很相似。在SDK中java文件是经过javac编译成class,而后再经过dx打包成classes.dex包。在NDK中.c/.cpp文件时经过gcc等编译成.o文件,而后经过ar打包成.so包。


如何使用ndk开发将silk文件解码成PCM?

前面已经研究过了,只须要调用silk库进行解码便可,因为silk的解码sdk是C语言库,因此须要使用ndk开发。接下来我要作的思路大体以下:用户从本地选择一个文件,而后代码中经过获取该文件的path,循环读取byte数组传入silk库中进行解码成PCM,而后传入AudioTrack中进行播放。这里咱们定义3个须要在c文件中书写的native方法,其中nativeInit方法用来调用silk的初始化方法来建立解码器,nativeDecode方法是用来调用silk的解码方法,实时传入从语音文字中获取到的byte数组给silk库,nativeClean是用来善后处理,好比讲解码器关闭,回收c的内存等。

private native void nativeInit();
private native int nativeDecode(byte[] silkData, short byteSize, short[] outBuffer);
private native void nativeClean();复制代码


如何判断某文件是silk格式的?

若是根据文件后缀名来判断是不严谨的,这里就要用到魔数知识了,通常在文件的字节码开头或者结尾会有。能够经过010Editor这款16进制查看软件进行查看字节码数据咱们打开全部的silk文件,其前缀都是固定的。不光是silk,其余的文件格式也是如此,大部分都会在开头或者结尾有一串固定的字节码。这个固定的字节码就叫作魔数,因此咱们只须要判断文件的魔数是不是silk拥有的魔数便可。

接下来咱们具体在代码中实现一下,以下图这个dis就是本地的微信语音文件保存路径,咱们将它读入进输入流中,而后获取前10个字节,接下来和silk的魔数字节前缀HEADER数组进行对比,若是彻底同样就说明该文件是silk文件,接下来才能进行解码以及播放的操做。




每次应该给silk传多大的byte数组?

其实在魔数后的2个字节是short数据,好比前面那个截图魔数后面跟的是13 00,那么应该如何将这个13 00转化成音频数据的长度呢?这里还有大小端之分,须要将16进制的13 00 交换位置,变成00 13,而后再转换成10进制,变成19,也就是说接下来一段音频会有19个字节码


至此,其中的坑点都已经明确了,咱们只须要按照思路走下去就能够了,在java层调用c层的解码代码如上,循环依次获取到每段音频的2位16进制字节码,而后因为大小端字节码顺序进行替换,接下来获取到实际的长度,而后传递计算出来的长度到nativeDecode方法中,其中初始化了一个outBuffer用来接收从silk传递回来的解码后的数据,最后调用AudioTrack播放器进行播放已解码的PCM数据,最后成功的播放了微信文件。只须要让好友安装咱们的app,就能够听到咱们给TA分享的微信语音啦!


核心的silk解码代码如上图,咱们能够看到其实就是调用了核心的silk库进行解码,而后循环接收全部的silk库返回的byte数组,最后写入到java层传入的接收参数的outBuffer数组中。其他2个native方法分别用于初始化silk解码器以及内存回收,使用malloc申请了内存就须要free来释放,这里代码就不贴了,你们感兴趣的话能够进一步了解silk库以及C语言的基本使用。

坑点:最后须要注意,有的6.0以上手机须要动态申请获取本地文件权限,而后注意那个path在不一样手机上可能会有兼容性问题,主要体如今7.0之后必须使用fileprovider来共享文件,因此要经过contentresover来解析Uri,而不能直接getPath,否则会报fileNotFoundException。

总结:今天咱们主线是尝试使用silk库来解码微信的语音文件,而且使用Android系统自带的AudioTrack播放器对silk解码后的PCM数据进行播放。其中讲解了音视频的基础知识、JNI和NDK开发的基础知识、silk库以及AudioTrack播放器的使用、查看文件的16进制字节码方式010Editor、文件的魔数区分方法等知识,但愿能对你们有所帮助!

相关文章
相关标签/搜索