最近在做一个基于海思芯片网络摄像头的项目,其中有个需求就是能够实时通话,就和语音聊天一样,但是只要实现一边的实时传输功能就可以了,于是花了接近两个星期的捣鼓,终于搞出了一个比较完美的方案(原谅自己的菜)
AudioRecord 简介
Android提供了两个函数可以实现录音功能,一个是AudioRecord,另一个是功能比较强大的MediaRecord,因为要实现实时传输的功能,MediaRecord都是封装好的方法,无法实现边录边播,于是我选择了AudioRecord,他可以获取到原始数据,进而对齐进行需要的操作,例如传输,编码,转码等;下面列一下比较简单的两者的区别:
AudioRecord :语音的实时处理,可以用代码实现各种音频的封装;输出的是PCM语音数据,一般的播放器都播放不了,(我用的是海思提供的SDK来对PCM进行解码,居然可以放出音乐);当然一般加上WAV的头部文件就可以封装成WAV格式了,播放器可以播放;
MediaRecorder:已经集成了录音、编码、压缩等功能,支持的录音音频格式大概有aac,amr ,3gp(无mp3);无法实时处理音频,输出的音频格式不是很多;
MediaDecode 转码
当然如果只用PCM进行数据传输,那是比较消耗带宽的,一段30s的8K采样率单声道的文件数据大小就有3M左右,而利用转码可以减少很多消耗,例如G711数据量是PCM的一半,AAC数据压缩比例则是和原始声音有关,就像图片压缩中黑白图像和彩色图像的压缩一样;
得到的PCM数据进行转码就有很多方法,我之前在网上也找到了很多种方法,基本上可以分为三类:
1 调用JNI,自己写算法实现,这个对音频格式的转码和算法有比较高的理解
例如参考:https://blog.youkuaiyun.com/qq_24551315/article/details/51134689
2 调用开源的库进行编码调用,例如喜欢Linux的都想用ffmpeg这个库来进行编码解码,网上也可以搜索到一大堆移植ffmpeg库的例子
3 利用Android自带的MediaDecode来进行编解码
我当然是选择比较简单的第三种方法,因为自己还没有好好搞懂JNI的参数调用和传递,而查看API发现MediaDecode支持的编码格式还是比较多的,如下图所示
实现代码
说再多也没有用,程序员只有看代码才会知道这玩意是什么,下面就是我封装的一个类
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaRecorder;
import android.util.Log;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
/**
* Created by Unionman on 2018/9/19.
*/
public class AudioRecordFun {
private String TAG = "AudioRecordFun";
//网络设置
private int Host_PORT = 8888;
private InetA