使用AudioTrack播放PCM音频数据

234 篇文章 1 订阅

     Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用MediaPlayer实现的。MediaPlayer在底层是基于OpenCore(PacketVideo)的库实现的,为了构建一个MediaPlayer程序,上层还包含了进程间通讯等内容,这种进程间通讯的基础是Android基本库中的Binder机制。

     但是该类只能对完整的音频文件进行操作,而不能直接对纯PCM音频数据操作。假如我们通过解码得到PCM数据源,又当如何将它们播放?没错,就是用AudioTrack这个类(MediaPlayer内部也是调用该类进行真正的播放音频流操作)下面这个DEMO演示了如何使用AudioTrack

不啰嗦,上图先

以下这个类对AudioTrack做了简单封装:

public class MyAudioTrack {
        
        int mFrequency;                                        // 采样率
        
        int mChannel;                                        // 声道
        
        int mSampBit;                                        // 采样精度
        
        AudioTrack mAudioTrack;                        
        
        public MyAudioTrack(int frequency, int channel, int sampbit){
                mFrequency = frequency;
                mChannel = channel;
                mSampBit = sampbit;
        }
        
        public void init(){
                if (mAudioTrack != null){
                        release();
                }

// 获得构建对象的最小缓冲区大小
                int minBufSize = AudioTrack.getMinBufferSize(mFrequency, 
                                                                                                        mChannel,
                                                                                                        mSampBit);
                
                
                
//                         STREAM_ALARM:警告声
//                         STREAM_MUSCI:音乐声,例如music等
//                         STREAM_RING:铃声
//                         STREAM_SYSTEM:系统声音
//                         STREAM_VOCIE_CALL:电话声音
                mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                                mFrequency, 
                                mChannel, 
                                mSampBit, 
                                minBufSize,
                                AudioTrack.MODE_STREAM);
//                                AudioTrack中有MODE_STATIC和MODE_STREAM两种分类。
//                      STREAM的意思是由用户在应用程序通过write方式把数据一次一次得写到audiotrack中。
//                                这个和我们在socket中发送数据一样,应用层从某个地方获取数据,例如通过编解码得到PCM数据,然后write到audiotrack。
//                                这种方式的坏处就是总是在JAVA层和Native层交互,效率损失较大。
//                                而STATIC的意思是一开始创建的时候,就把音频数据放到一个固定的buffer,然后直接传给audiotrack,
//                                后续就不用一次次得write了。AudioTrack会自己播放这个buffer中的数据。
//                                这种方法对于铃声等内存占用较小,延时要求较高的声音来说很适用。
                
                
                
                
                mAudioTrack.play();        
        }
public void release(){
                if (mAudioTrack != null){
                        mAudioTrack.stop();                                               
                        mAudioTrack.release();
                }
        }
        
        public void playAudioTrack(byte []data, int offset, int length){
                if (data == null || data.length == 0){
                        return ;
                }
                
                try {
                        mAudioTrack.write(data, offset, length);
                } catch (Exception e) {
                        // TODO: handle exception
                        Log.i("MyAudioTrack", "catch exception...");
                }
        }
        
        public int getPrimePlaySize(){
                int minBufSize = AudioTrack.getMinBufferSize(mFrequency, 
                                mChannel,
                                mSampBit);
                
                return minBufSize * 2;
        }
}

mAudioTrack.write(data, offset, length);该函数正是将数据写入硬件播放的关键!



这是测试音频数据(内附详细说明):
音频数据.rar(2.6 MB, 下载次数: 437)


这是源码工程TestAudioTrack.rar(51.72 KB, 下载次数: 377)

好东西大家分享哈{:4_84:}


工程代码里有处错误:

在线程run函数里原文如下


        while(true){
                        try {
                                Thread.sleep(0);
                                
                                offset = index * playSize;
                                
                                
                                myAudioTrack.playAudioTrack(data, offset, playSize);
                                        
                        } catch (Exception e) {
                                // TODO: handle exception
                                break;
                        }
                        
                        index++;
                        if (index >= data.length)
                        {
                                break;
                        }
                }

应该改为

                while(true){
                        try {
                                Thread.sleep(0);
                                
                                offset = index * playSize;
                                

                                if (offset >= data.length){
                                        break;
                                }
                                
                                myAudioTrack.playAudioTrack(data, offset, playSize);
                                        
                        } catch (Exception e) {
                                // TODO: handle exception
                                break;
                        }
                        
                        index++;
                }

转贴:http://www.eoeandroid.com/thread-70014-1-1.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值