Android音频采集、压缩、发送

基本的实现流程:

         

 1、从手机麦中采集音频数据;2、将PCM音频数据编码压缩;3、将压缩好的音频通过无线网络发送出去;4、其他手机接收音频数据并解码;5、将音频数据写入到音轨中播放。项目虽然简单,但其中的一些小问题也折腾了我不少时间。

  首先我们创建一个线程用来采集音频数据,通过android提供的AudioRecord可以实时采集音频流。AudioRecord类在Java应用程序中管理音频资源,用来记录从平台音频输入设备产生的数据。其实调用AudioRecord很简单,首先创建AudioRecord对象,AudioRecord会初始化并连接音频缓冲区,用来缓冲新的音频数据。根据指定的缓冲区的大小来决定AudioRecord能够记录多长的数据。

调用getMinBufferSize(int,int,int)返回最小的缓冲区大小。然后根据得到的最小缓冲区大小来创建AudioRecord对象:

复制代码
inputMinSize = AudioRecord.getMinBufferSize(8000, 
        AudioFormat.CHANNEL_CONFIGURATION_MONO, 
        AudioFormat.ENCODING_PCM_16BIT);
audioRec = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, 
        AudioFormat.CHANNEL_CONFIGURATION_MONO,
        AudioFormat.ENCODING_PCM_16BIT, inputMinSize);
复制代码
参数
  sampleRateInHz         默认采样率,单位Hz。
  channelConfig          描述音频通道设置。
  audioFormat              音频数据保证支持此格式。
 

  AudioRecord初始化工作完毕后启用录制线程,并且调用startRecording ()开始进行音频录制。调用read(short,int,int)方法从音频硬件录制缓冲区读取数据。拿到音频数据后,直接通过网络发送出去是不行的,我们在这里还要做一项工作就是实现音频压缩。在网上提供了很多音频的编码库,我们可以将源码导入到项目中通过android ndk编译成.so文件,最后通过jni来调用。我这里直接用sipdroid开源项目提供的SILK编解码库(下载编码库)。

本地方法 encode(short[] lin,int offset,byte[] encoded,int size)
参数                  
  lin        源数据                  
  offset       源数组的起始偏移量                  
  encoded     编码后的数据      
  size          请求编码的数据大小返回值   编码后的数据大小
 

  调用encode(short[], int, byte[], int)压缩已经采集完毕的音频数据,我们就可以通过网络发送出去了。 

  接下来,我们创建一个socket udp实例,为什么这里选择udp而不是tcp呢?从我们本身的项目需求出发,我们做的这个项目的通讯方式是相互收发数据的,属于手机与手机两“客户端“之间的通讯。并且,在这种音频通信过程中,我们要传输的数据量是比较庞大的,因此采用资源消耗少,处理速度快的UDP协议是合理的。指定发送的端口号,我们将数据封装成报文发送出去,整个采集发送的过程如下:

复制代码
class RecordSoundThread extends Thread {
        private boolean flag = true;
        private DatagramSocket mSocket;

        private int inputBufSize = 160;
        short[] inputBytes = new short[1024];
        byte[] encodeBytes = new byte[1024];

        RecordSoundThread() throws SocketException {
            // TODO Auto-generated constructor stub
            mSocket = new DatagramSocket();
        }

        @Override
        public void run() {
            if (mSocket == null)
                return;

            while (flag) {
                if (isSpeakMode) {
                    try {
                        int length = audioRec.read(inputBytes, 0, inputBufSize);

//                        calc(inputBytes, 0, length);

                        length = silk8.encode(inputBytes, 0, encodeBytes,
                                length);

                        DatagramPacket writePacket;
                        if (inetAddress.length() > 0) {
                            InetAddress inet = InetAddress
                                    .getByName(inetAddress);
                            writePacket = new DatagramPacket(encodeBytes,
                                    length, inet, NETPORT);
                            writePacket.setLength(length);
                            mSocket.send(writePacket);
                        }
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
        
        public void close() {
            flag = false;
            if (mSocket != null) {
                mSocket.close();
            }        
        }
    }
复制代码

  接下来我们要接收目标机器发送过来的音频数据了。同样,创建一个线程用来接收网络中的音频数据,并且对音频数据进行解码。

本地方法 decode(byte[] encoded, short[] lin, int size)
参数
       encoded     源数据
       lin          解码后的数据
       size        请求解码的数据大小
返回值          解码后的数据大小 

  得到解码后的PCM音频流,我们就可以使用AudioTrack将音频播放出来了。

  AudioTrack类在java应用程序中管理和播放音频资源,将PCM音频数据写入到缓冲区来播放音频设备。首先创建AudioTrack对象,AudioTrack会初始化并连接音频缓冲区,根据指定的缓冲区大小来决定audioTrack能够播放多长的数据。调用getMinBufferSize(int,int,int)返回最小的缓冲区大小。然后根据得到的最小缓冲区大小来创建audioTrack对象:

复制代码
outputMinSize = AudioTrack.getMinBufferSize(8000,
                AudioFormat.CHANNEL_CONFIGURATION_MONO,
                AudioFormat.ENCODING_PCM_16BIT);
audioTrk = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,
                AudioFormat.CHANNEL_CONFIGURATION_MONO,
                AudioFormat.ENCODING_PCM_16BIT, outputMinSize,
                AudioTrack.MODE_STREAM);
复制代码

  AudioTrack初始化工作完毕后启用接收线程,并且调用play()开始播放。调用write(short[],int,int)方法将PCM音频数据写入到音频硬件中。

 

  View Code

   最后,退出应用后别忘了释放资源。

复制代码
public void onDestroy() {
  silk8.close();
  recevThread.close();
  recordThread.close();
  audioRec.release();
  audioTrk.release();
}
复制代码
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值