微信语音分享

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



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

音视频基础


音视频文件如何生成的?

如上图,图像的原始格式是YUV/RGB。由于原始数据过大,需要对原始图像进行压缩成H-264/VP8,压缩过程也叫做编码。

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

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


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

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


其实安卓本身提供了录制和播放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、文件的魔数区分方法等知识,希望能对大家有所帮助!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值