AudioTrack

由于AudioTrack是Android SDK层提供的最底层的音频播放API,因此只允许输入裸数据。和MediaPlayer相比,对于一个压缩的音频文件(比如MP3、AAC等文件),它需要自行实现解码操作和缓冲区控制。

首先来看一下AudioTrack的工作流程,具体如下。
1)根据音频参数信息,配置出一个AudioTrack的实例。
2)调用play方法,将AudioTrack切换到播放状态。
3)启动播放线程,循环向AudioTrack的缓冲区中写入音频数据。
4)当数据写完或者停止播放的时候,停止播放线程,并且释放所有资源。
根据AudioTrack的上述工作流程,本节将以4个小部分分别介绍每个流程的详细步骤。

1.配置AudioTrack
先来看一下AudioTrack的参数配置,要想构造出一个AudioTrack类型的实例,必须先了解其构造函数原型,代码如下所示:

public AudioTrack(int streamType, int sampleRateInHz, int channelConfig,int audioFormat, int bufferSizeInBytes, int mode);

其中构造函数的参数说明如下。

  • streamType,Android手机上提供了多重音频管理策略(按一下手机侧边的按键,可以看到有多个音量管理,这其实就是不同音频策略的音量控制展示),当系统有多个进程需要播放音频的时候,管理策略会决定最终的呈现效果,该参数的可选值将以常量的形式定义在类AudioManager中,主要包括以下内容:
    STREAM_VOCIE_CALL:电话声音
    STREAM_SYSTEM:系统声音
    STREAM_RING:铃声
    STREAM_MUSCI:音乐声
    STREAM_ALARM:警告声
    STREAM_NOTIFICATION:通知声
  • sampleRateInHz,采样率,即播放的音频每秒钟会有多少次采样,可选用的采样频率列表为:8000、16000、22050、24000、32000、44100、48000等,大家可以根据自己的应用场景进行合理的选择。
  • channelConfig,声道数(通道数)的配置,可选值以常量的形式配置在类AudioFormat中,常用的是CHANNEL_IN_MONO(单声道)、CHANNEL_IN_STEREO(双声道),因为现在大多数手机的麦克风都是伪立体声的采集,为了性能考虑,笔者建议使用单声道进行采集,而转变为立体声的过程可以在声音的特效处理阶段来完成。
  • audioFormat,该参数是用来配置“数据位宽”的,即采样格式,可选值以常量的形式定义在类AudioFormat中,分别为ENCODING_PCM_16BIT(16bit)ENCODING_PCM_8BIT(8bit),
    注意,前者是可以兼容所有Android手机的。
  • bufferSizeInBytes,其配置的是AudioTrack内部的音频缓冲区的大小,AudioTrack类提供了一个帮助开发者确定bufferSizeInBytes的函数,其原型具体如下:
int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat);

在实际开发中,强烈建议由该函数计算出需要传入的bufferSizeInBytes,而不是自己手动计算。

  • mode,AudioTrack提供了两种播放模式,可选的值以常量的形式定义在类AudioTrack中,一个是MODE_STATIC,需要一次性将所有的数据都写入播放缓冲区中,简单高效,通常用于播放铃声、系统提醒的音频片段;另一个是MODE_STREAM,需要按照一定的时间间隔不间
    断地写入音频数据,理论上它可以应用于任何音频播放的场景。

2.将AudioTrack切换到播放状态
首先判断AudioTrack实例是否初始化成功,如果当前状态处于初始成功的状态,那么就调用它的play方法,并切换到播放状态,代码如下:

if (null != audioTrack && audioTrack.getState() != AudioTrack.STATE_UNINITIALIZED)
{
    audioTrack.play();
}

3.开启播放线程
首先创建一个播放线程,代码如下:

playerThread = new Thread(new PlayerThread(), "playerThread");
playerThread.start();

接下来看看该线程中执行的任务,代码如下:

class PlayerThread implements Runnable {
    private short[] samples;
    public void run() {
       samples = new short[minBufferSize];
        while(!isStop) {
            int actualSize = decoder.readSamples(samples);
            audioTrack.write(samples, actualSize);
        }
    }
}

线程中的minBufferSize是在初始化AudioTrack的时候获得的缓冲区大小,会对其进行换算,即以2个字节表示一个采样的大小,也就是2倍的关系(因为初始化的时候是以字节为单位的);decoder是一个解码器,假设已经初始化成功,最后将调用write方法把从解码器中获得的PCM采样数据写入AudioTrack的缓冲区中,注意此方法是阻塞的方法,比如:一般要写入200ms的音频数据需要执行接近200ms的时间。

4.销毁资源
首先停止AudioTrack,代码如下:

if (null != audioTrack && audioTrack.getState() != AudioTrack.STATE_UNINITIALIZED)
{
    audioTrack.stop();
}

然后停止线程:

isStop = true;
if (null != playerThread) {
    playerThread.join();
    playerThread = null;
}

最后释放AudioTrack:

audioTrack.release();

你可能感兴趣的:(AudioTrack)