Android java层的AudioTrack使用总结

介绍:AudioTrack是安卓sdk提供的一种只能播放音频裸数据(解码后的pcm)的一个解决方案。

AudioTrack有两种载入数据的方式:

MODE_STATIC :静态方式:意思是一次性载入全部待播放的pcm数据,后续再播放出来。适合短小的音频播放,例如提示音等场景。不适合长时间播放音频场景。因为消耗内存太大
MODE_STREAM:流的放方式:意思是可以源源不断往AudioTrack缓冲区中写入pcm数据。适合听音乐,看电影等长时间播放音频场景

音频知识点:

采样率 {如44100 hz}:是指在声音录制过程,声音的模拟信号转为数字信号时单位时间内{1秒钟} 的采样点数。理论上采样率越高,声音还原度越高 ,但人耳对声音的敏感也有极限,目前最高是192k hz。

声道数 {如2个声道}:声道数量,现代有的声音最高可以做到24声道。奔驰S的大柏林了解一下。

采样位宽【常见的16位{2字节}、32位{4字节}】:量化位宽。

一秒钟播放的pcm字节数= 采样率 * 声道数 * 采样位宽{字节}  如采样率为 44100 hz,2声道、采样位宽是16位{2字节},则有一秒钟播放了:44100 * 2 * 2 = 176400 字节。约等于 172.27kb 存储。

所以由此可见【根据公式计算】,未经过压缩处理的音频裸数据,占用的存储空间还是蛮大的

使用AudioTrack播放音频的关键api:

1、初始化AudioTrack。

    1.1可以使用构造函数new一个实例对象、关键点是buffersize要计算正确:

  AudioTrack.getMinBufferSize(audioSampleRate,
        AudioFormat.CHANNEL_OUT_STEREO,
        AudioFormat.ENCODING_PCM_16BIT);  参数分别是采样率,声道布局配置、采样位宽

    1.2  也可以使用AudioTrack内部的Builder来构建支持更多参数设置的实例对象。

2、write方法:这个方法要求写入解码后的字节数据,通常是字节数组。write方法提供了好几个方式写入数据。很简单,对着参数要求传入即可。详细自行去看sdk中的方法api定义。

3、flush方法。在write后一定要调用flush方法刷出缓冲区内的数据,否则在播放某些音频可能会出现声音不连续的情况

4、如何计算当前音频的播放时长?和 总时长?

    总时长其实很简单:如果你播放的就是.pcm文件,则直接计算文件的总byte大小,然后除以 1秒的播放量就行。

    如果你播放的不是.pcm文件,而是封装过的音频文件,那么在解封装时,有api获取。

   例如你使用 MediaExtractor来解封装MP3文件,那么可以通过下面方式获取

     按照上面说的,可以使用: 总的播放字节数 / 一秒钟播放的字节数 = 播放了多少秒。

     只要知道 总的播放字节数就能求出。

     我们来简化一下公式:1 秒的数据量 * X 秒  = 总的播放数据量

    有:采样率* 声道数 * 采样位宽{字节} * X秒 = 总的播放数据量

    总的播放数据量 作为右边值,其声道数 和 采样位宽与左边公式的其实是一致的。于是有

     总的采样点数 / 采样率{1秒钟的采样点数} = 播放了多少秒

     AudioTrack中有提供api 获取总共播放的采样点数:

      audioTrack.getPlaybackHeadPosition() 这个方法合适以流的方式载入数据的场景。

于是有:

int playSize = audioTrack.getPlaybackHeadPosition();
int rate = audioTrack.getPlaybackRate();
float currentPlayTime = playSize * 1.0f / rate;
MyLog.v("音频当前播放到="+currentPlayTime+ "秒了");

实际使用中其实是希望有个监听器来更新当前音频播放时长的。AudioTrack也提供了方法。如下

audioTrack.setPositionNotificationPeriod(1000);//回调频率,一定要设置这个,否则不会回调,
audioTrack.setPlaybackPositionUpdateListener(new AudioTrack.OnPlaybackPositionUpdateListener() {
    @Override
    public void onMarkerReached(AudioTrack track) {

    }

    @Override
    public void onPeriodicNotification(AudioTrack audioTrack) {
     if (track == null || track.getState() == AudioTrack.STATE_UNINITIALIZED) {
         return;
      }

       if (track.getPlayState() != AudioTrack.PLAYSTATE_PLAYING) {
           return;
         }

            int playSize = audioTrack.getPlaybackHeadPosition();
            int rate = audioTrack.getPlaybackRate();
            float currentPlayTime = playSize * 1.0f / rate;
            MyLog.v("音频当前播放到: "+currentPlayTime+ "秒了");
    }
});

其他的api,诸如 暂停,播放,停止,释放资源等,直接调用就行。

注意,音频播放几乎都是多线程场景下运行代码,要注意临界资源问题。

  • 20
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值