音视频开发进阶指南(第四章)-AudioTrack播放PCM

简介: 笔记

使用AudioTrack播放PCM


为什么只播放PCM不播放Mp3呢?因为AudioTrack是基础API,没有解码功能,而MediaPlayer是有解码功能的。所以要播放Mp3,还需要自行添加解码功能,把Mp3解码为PCM再播放。

只要做好两件事情:

  1. AudioTrack的初始化参数的含义
  2. AudioTrack的播放流程:play->write->stop


1. 初始化AudioTrack

//获取最小缓冲区大小
 int minBufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE,    //采样率
         AudioFormat.CHANNEL_OUT_STEREO, //双声道
         AudioFormat.ENCODING_PCM_16BIT  //采样格式
 );
 //初始化AudioTrack对象
 AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,   //媒体类型
         SAMPLE_RATE,  //采样率
         AudioFormat.CHANNEL_IN_STEREO, //双声道
         AudioFormat.ENCODING_PCM_16BIT, //采样格式
         minBufferSize,  //缓冲区大小
         AudioTrack.MODE_STREAM  //流式加载
 );

参数详解:

  • 参数一:streamType
    Android手机上提供了多重音频管理策略(例如按一下手机侧面音量键,会出现多个音量管理,这其实就是不同音频策略的音频控制展示),当系统有多个进程需要播放音频的时候,管理策略会决定最终的呈现效果,该参数的可选值将以常量的形式定义在类AudioManager中,主要包括以下内容:

public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_
public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
public static final int STREAM_RING = AudioSystem.STREAM_RING;
public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
  • 参数二:sampleRateInHz
    采样率,即播放的音频每秒钟会有多少次采样,可选用的采样频率列表为:8000、16000、22050、24000、32000、44100、48000等,要根据播放的PCM的采样率来决定初始化AudioTrack时的具体值,否则可能导致声音变快或者变慢
  • 参数三:channelConfig
    声道数(通道数)配置,可选值以常量形式配置在类AudioFormat中,常用的是CHANNEL_IN_MONO(输入单声道),CHANNEL_IN_STEREO(输入双声道)。(因为现在大多数手机的麦克风都是伪立体声采集,为了性能考虑,建议使用单声道进行音频采集,而转变为立体声的过程可以在声音的特效处理阶段来完成)。
  • 参数四:audioFormat
    该参数是用来配置数据位宽,表示了采样精度,可选值以常量的形式定义在类AudioFormat中,分别为ENCODING_PCM_16BIT和ENCODING_PCM_8BIT,注意,前者是可以兼容安卓所有手机的。
  • 参数五:bufferSizeInBytes
    它配置的是AudioTrack内部缓冲区的大小,AudioTrack类提供了一个静态方法getMinBufferSize来帮忙开发者确定缓冲区的大小,在实际开发中,强烈建议使用该方法,而不是自己手动计算。
  • 参数六:mode
    AudioTrack提供了两种播放模式,可选的值以常量的形式定义在类AudioTrack中,分别为:
  1. MODE_STREAM 按照一定的时间间隔不间断地定入音频数据,理论上它可以应用于任何音频播放的场景
  2. MODE_STATIC 需要一次性将所有的数据都写入播放缓冲区中,简单高效,通常用于播放铃声、系统提醒的音频片段。


2. 启动播放

//先启动播放
audioTrack.play();

3. write音频数据

//分配缓冲区
byte[] buffer = new byte[minBufferSize * 3];
is = getAssets().open(pcmFilePath);
dis = new DataInputStream(is);
int readCount = 0;
while (dis.available() > 0) {
    //读取PCM
    readCount = dis.read(buffer);
    Log.d(MainActivity.class.getSimpleName(), "readCount=" + readCount);
    if (readCount == AudioTrack.ERROR_INVALID_OPERATION || readCount == AudioTrack.ERROR_BAD_VALUE) {
        continue;
    }
    if (readCount != 0 && readCount != -1) {
        //写入AudioTrack
        audioTrack.write(buffer, 0, readCount);
    }
}
...
audioTrack.stop();


目录
相关文章
|
机器学习/深度学习 编解码 语音技术
音频基础知识 2
音频基础知识
279 0
|
存储 编解码 算法
音视频之音频知识入门
信息论的观点来看,描述信源的数据是信息和数据冗余之和,即:数据=信息+数据冗余。音频信号在时域和频域上具有相关性,也即存在数据冗余。将音频作为一个信源,音频编码的实质是减少音频中的冗余。自然界中的声音非常复杂,波形极其复杂,通常我们采用的是脉冲代码调制编码,即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。
678 0
|
4月前
|
编解码
FFmpeg开发笔记(三十三)分析ZLMediaKit对H.264流的插帧操作
《FFmpeg开发实战》书中3.4.3节讲解如何将H.264流封装成MP4。H.264流通常以SPS→PPS→IDR帧开始,这一说法通过雷霄骅的H264分析器得到验证。分析器能解析H.264文件但不支持MP4。ZLMediaKit服务器在遇到I帧时会自动插入SPS和PPS配置帧,确保流符合标准格式。若缺少这些帧,客户端拉流时会报错。FFmpeg开发实战:从零基础到短视频上线》书中提供了更多FFmpeg开发细节。
96 0
FFmpeg开发笔记(三十三)分析ZLMediaKit对H.264流的插帧操作
|
5月前
|
移动开发 JSON 前端开发
📺搞懂前端流媒体字幕
📺搞懂前端流媒体字幕
|
5月前
|
存储 编解码 C++
C++ 音视频原理
C++ 音视频原理
|
存储 编解码 算法
【ZEGO即构】音视频开发进阶 — 音频要素
【ZEGO即构】音视频开发进阶 — 音频要素
94 0
|
存储 Web App开发 编解码
音频基础知识 1
音频基础知识
144 1
|
12月前
|
编解码 数据处理 数据格式
[笔记]音视频学习之视音频数据处理入门《四》AAC
[笔记]音视频学习之视音频数据处理入门《四》AAC
|
12月前
|
存储 编解码 数据处理
[笔记]音视频学习之视音频数据处理入门《二》PCM
[笔记]音视频学习之视音频数据处理入门《二》PCM
128 0
|
12月前
|
存储 编解码 缓存
[笔记]音视频学习之视音频数据处理入门《三》H264
[笔记]音视频学习之视音频数据处理入门《三》H264
154 0