android audio从应用到中间层再到HAL层,涉及很多,比如音频链路的选择,共享内存的分配及音频数据的传输、平台音频配置文件的加载等等,内容很多又很复杂,每块可以单独拉出来讨论,今天先简单说下应用是怎么从AudioTrack一步步到AudioFlinger服务。
AudioTrack和Track的创建流程
首先我们先从应用使用开始:frameworks\base\media\tests\MediaFrameworkTest\src\com\android\mediaframeworktest\functional\audio\MediaAudioTrackTest.java
这个文件是针对AudioTrack向应用提供的一些接口,实现的测试程序,这里就随便取一个函数开涮:
//Test case 1: setStereoVolume() with max volume returns SUCCESS
@LargeTest
public void testSetStereoVolumeMax() throws Exception {
//测试立体声的最大值
// constants for test
final String TEST_NAME = "testSetStereoVolumeMax";
final int TEST_SR = 22050;
final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO; //通道数
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT; //位深
final int TEST_MODE = AudioTrack.MODE_STREAM; //音频数据传输模式
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;//音频类型,音乐
//-------- initialization --------------
int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);//重要,得到需要分配的共享内存大小
AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
minBuffSize, TEST_MODE); //陷入AudioTrack.java --重点
byte data[] = new byte[minBuffSize/2];
//-------- test --------------
track.write(data, 0, data.length);//写入音频数据
track.write(data, 0, data.length);
track.play();//播放控制
float maxVol = AudioTrack.getMaxVolume();//得到最大音量
assertTrue(TEST_NAME, track.setStereoVolume(maxVol, maxVol) == AudioTrack.SUCCESS);//设置最大音量
//-------- tear down --------------
track.release();//释放资源,使用完成后要释放所占用的资源,如:音频服务、音频通道...
}
以上函数,设置音频格式、音频数据传输模式、然后获取最小的共享内存大小(分配内存,详细分析见文末),创建AudioTrack对象,获取对应的接口实现功能。
AudioTrack.java
接着分析AudioTrack对象的创建都实现了些啥?
public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
int bufferSizeInBytes, int mode, int sessionId)
throws IllegalArgumentException {
// mState already == STATE_UNINITIALIZED
// remember which looper is associated with the AudioTrack instantiation
Looper looper;
if ((looper = Looper.myLooper()) == null) {
looper = Looper.getMainLooper();//获取主循环
}
//Looper associated with the thread that creates the AudioTrack instance.
mInitializationLooper = looper;
audioParamCheck(streamType, sampleRateInHz, channelConfig, audioFormat, mode);//参数合法性检查
audioBuffSizeCheck(bufferSizeInBytes);//buf大小的检查
if (sessionId < 0) {
//回话id不能为0
throw new IllegalArgumentException("Invalid audio session ID: "+sessionId);
}
int[] session = new int[1];
session[0] = sessionId;
// native initialization
int initResult = native_setup(new WeakReference<AudioTrack>(this),
mStreamType, mSampleRate, mChannels, mAudioFormat,
mNativeBufferSizeInBytes, mDataLoadMode, session);//重要,这里调用jni层的native方法实现,此处只是一个包装
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack.");
return; // with mState == STATE_UNINITIALIZED
}
mSessionId = session[0];
if (mDataLoadMode == MODE_STATIC) {
//设置音频数据传输模式
mState = STATE_NO_STATIC_DATA;
} else {
mState = STATE_INITIALIZED;
}
}
可以看出,在AudioTrack.java的构造函数中只是进行一些参数的检查,然后调用native_setup进入jni层的具体实现。
通过搜索我们发现,native_setup是jni层注册的一个方法,具体如下:
所在文件frameworks\base\core\jni\android_media_AudioTrack.cpp
cpp
android_media_AudioTrack.cpp
static JNINativeMethod gMethods[] = {
// name, signature, funcPtr
{
"native_start", "()V", (void *)android_media_AudioTrack_start},
{
"native_stop", "()V", (void *)android_media_AudioTrack_stop},
...
{
"native_setup", "(Ljava/lang/Object;IIIIII[I)I",
(void *)android_media_AudioTrack_native_setup},//
...
来看看这个函数做了些什么,因内容太长,我们只列举部分比较重要和主题相关的内容:
// check the stream type
audio_stream_type_t atStreamType;
switch (streamType) {
...
// check the format.
...
// compute the frame count
int bytesPerSample = audioFormat == ENCODING_PCM_16BIT ? 2 : 1;
audio_format_t format =</