AudioTrack主要是用来播放声音的,AudioTrack贯穿了JAVA层,JNI层和Native层。
AudioTrack JAVA层:
framework\base\media\java\android\media\AudioTrack.java
以AudioTrack的使用方法举例:
// 得到一个满足最小要求的缓冲区的大小
int bufsize = AudioTrack.getMinBufferSize(8000,//采样率 = 每秒8K个点
AudioFormat.CHANNEL_CONFIGURATION_STEREO,//双声道
AudioFormat.ENCODING_PCM_16BIT);//采样精度 = 一个采样点16比特 = 2个字节
//创建AudioTrack
AudioTrack trackplayer = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,
AudioFormat.CHANNEL_CONFIGURATION_ STEREO,
AudioFormat.ENCODING_PCM_16BIT,
bufsize,
AudioTrack.MODE_STREAM);//
trackplayer.play() ;//开始
trackplayer.write(bytes_pkg, 0, bytes_pkg.length) ;//往track中写数据
//...
trackplayer.stop();//停止播放
trackplayer.release();//释放底层资源
AudioTrack Native层:
// 得到一个满足最小要求的缓冲区的大小
int bufsize = AudioTrack.getMinBufferSize(8000,//采样率 = 每秒8K个点
AudioFormat.CHANNEL_CONFIGURATION_STEREO,//双声道
AudioFormat.ENCODING_PCM_16BIT);//采样精度 = 一个采样点16比特 = 2个字节
getMinBufferSize实际调用了JNI通过Native代码来实现。
framework/base/core/jni/android_media_track.cpp
static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
jint sampleRateInHertz, jint nbChannels, jint audioFormat)
{//注意我们传入的参数是:
//sampleRateInHertz = 8000
//nbChannels = 2;
//audioFormat = AudioFormat.ENCODING_PCM_16BIT
int afSamplingRate;
int afFrameCount;
uint32_t afLatency;
if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) {
return -1;
}
if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
return -1;
}
if (AudioSystem::getOutputLatency(&afLatency) != NO_ERROR) {
return -1;
}
//音频中最常见的是frame,解释:一个frame就是1个采样点的字节数*声道。
// Ensure that buffer depth covers at least audio hardware latency
uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSamplingRate);
if (minBufCount < 2) minBufCount = 2;
uint32_t minFrameCount =
(afFrameCount*sampleRateInHertz*minBufCount)/afSamplingRate;
//下面根据最小的framecount计算最小的buffersize
int minBuffSize = minFrameCount
* (audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1)
* nbChannels;
return minBuffSize;
}
MODE_STREAM和MODE_STATIC
STREAM的意思是由用户在应用程序通过write方式把数据一次一次得写到audiotrack中。这个和我们在socket中发送数据一样,应用层从某个地方获取数据,例如通过编解码得到PCM数据,然后write到audiotrack。这种方式的坏处就是总是在JAVA层和Native层交互,效率损失较大。
In Streaming mode, the application writes a continuous stream of data to the AudioTrack, using one of the write() methods. These are blocking
MODE_STREAM模式终使用Write方法,该方法是阻塞的,当数据从Java层到Native层执行播放完毕后才返回。
而STATIC的意思是一开始创建的时候,就把音频数据放到一个固定的buffer,然后直接传给audiotrack,后续就不用一次次得write了。AudioTrack会自己播放这个buffer中的数据。这种方法对于铃声等内存占用较小,延时要求较高的声音来说很适用。
AudioTrack的构造函数
public AudioTrack (int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)
AudioTrack的构造函数中有一个变量用来指定buffer的大小bufferSizeInBytes。
AudioTrack在Native层会对这个变量的值进行有效性判断。首先,它至少要等于或者大于getMinBufferSize返回的值,然后它必须是frame大小的整数倍。
举例说明,MODE_STREAM模式下,在JAVA层构造AudioTrack时,bufferSizeInBytes的大小设定为9600,在Native层调用Write方法拷贝数据至Hardware进行回放,每次拷贝的大小为320.则需要拷贝到30次,声卡才发出声音。即需要将数据填满缓冲区才进行播放。(320*30=9600)