您的位置:首页 > 大数据 > 物联网

audiotrack分析

2016-02-20 20:02 731 查看
首先总结一下AudioTrack

AudioTrack字面意思是音轨,可以理解为一路音频的来源。

JAVA层也有AudioTrack的概念,但只是简单的封装,这里不介绍了。只介绍Native JNI的AT



AT 向下传送数据,有两种方式:

1,主动push方式,(对AF来说是被动方式)

AT调用write函数把音频数据“push”到AudioTrack中。

2,被动pull方式,(对AF来说是主动方式)

AF调用callback,从AT获取数据

从另外一个维度来看,还有两种方式:

1,static方式,一次性把数据全传送给AF

延时大,简单高效,适用于提示音等操作

2,stream方式,数据一点点的传送给AF,一块一块的传送

延时小,不受文件大小限制。流媒体播放只能用这种。

下面结合代码总结一下AT的初始化,以及运行起来的流程问题。

开始播放时,JAVA层用JNI调用native函数

static int android_media_AudioTrack_native_setup(....)
{
sp<AudioTrack> lpTrack = new AudioTrack();//初始化track对象
switch (memoryMode) {
case MODE_STREAM:
lpTrack->set(   //给track设置好参数
atStreamType,// stream type
sampleRateInHertz,
format,// word length, PCM
nativeChannelMask,
frameCount,
AUDIO_OUTPUT_FLAG_NONE,
audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
0,// shared mem   //stream模式不用共享内存
true,// thread can call Java
sessionId);// audio session ID
break;
case MODE_STATIC:
// AudioTrack is using shared memory
lpTrack->set(
atStreamType,// stream type
sampleRateInHertz,
format,// word length, PCM
nativeChannelMask,
frameCount,
AUDIO_OUTPUT_FLAG_NONE,
audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
lpJniStorage->mMemBase,// shared mem    //static模式使用共享内存
true,// thread can call Java
sessionId);// audio session ID
break;
}


static int android_media_AudioTrack_native_setup(....)
{
sp<AudioTrack> lpTrack = new AudioTrack();//初始化track对象
switch (memoryMode) {
case MODE_STREAM:
lpTrack->set(   //给track设置好参数
atStreamType,// stream type
sampleRateInHertz,
format,// word length, PCM
nativeChannelMask,
frameCount,
AUDIO_OUTPUT_FLAG_NONE,
audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
0,// shared mem   //stream模式不用共享内存
true,// thread can call Java
sessionId);// audio session ID
break;
case MODE_STATIC:
// AudioTrack is using shared memory
lpTrack->set(
atStreamType,// stream type
sampleRateInHertz,
format,// word length, PCM
nativeChannelMask,
frameCount,
AUDIO_OUTPUT_FLAG_NONE,
audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
lpJniStorage->mMemBase,// shared mem    //static模式使用共享内存
true,// thread can call Java
sessionId);// audio session ID
break;
}


由此可见,AudioTrack::set函数很重要。负责对AT初始化

status_t AudioTrack::set(.... )
{
....参数检查
audio_io_handle_t output = AudioSystem::getOutput(   //根据参数,为这个AT寻找恰当的output输出
streamType,
sampleRate, format, channelMask,
flags,
offloadInfo);
if (cbf != NULL) {
mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
}//启动一个AT线程,该线程负责处理callback事件,最主要的就是处理EVENT_MORE_DATA 事件,以便通过pull机制存储数据。
// create the IAudioTrack
status_t status = createTrack_l(streamType,
sampleRate,
format,
frameCount,
flags,
sharedBuffer,
output,
0 /*epoch*/);
//为AT在AF中创建一个Track实例,Track实例是AF和AT交互的桥梁。其handle是IAudioTrack形式的,存储在成员变量mAudioTrack中
}


AT与AF在两个不同进程,其通信依靠的是createTrack_l中创建的位于AF中的Track实例。Track实例在AF中用数组的形式存放。

下面分析一下createTrack_l函数。

status_t AudioTrack::createTrack_l()
{
status_t status;
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); //获得AF service
sp<IAudioTrack> track = audioFlinger->createTrack(streamType,  //调用AF接口来在AF里面创建Track实例
sampleRate,
format == AUDIO_FORMAT_PCM_8_BIT ?
AUDIO_FORMAT_PCM_16_BIT : format,
mChannelMask,
frameCount,
&trackFlags,
sharedBuffer,
output,
tid,
&mSessionId,
mName,
mClientUid,
&status);
sp<IMemory> iMem = track->getCblk();
mAudioTrack = track;
mCblkMemory = iMem;
audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMem->pointer());
mCblk = cblk;    //获得Audio data的FIFO地址
size_t temp = cblk->frameCount_;
frameCount = temp;
mAwaitBoost = false;
return NO_ERROR;
}


从上面看到,实际是调用了AudioFlinger::createTrack在AF里面创建了Track实例。那么是怎么创建的呢?

sp<IAudioTrack> AudioFlinger::createTrack(...)
{
Mutex::Autolock _l(mLock);
PlaybackThread *thread = checkPlaybackThread_l(output);//通过前面讲过的获得的output,来获得playbackThread

track = thread->createTrack_l(client, streamType, sampleRate, format,
channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, clientUid, &lStatus); //在这个playbackThread里面创建Track
trackHandle = new TrackHandle(track); //提供给AT的handle,是IAudioTrack形式的
}


上面我们看到,先利用前面获得的output,来得到output对应的playbackThread,然后在这个playbackThread里面创建了Track,并且为这个Track创建了handle,以提供给AT使用

可以看出,Track的创建,是基于playbackThread的,一个playbackThread可以有多个Track。

前面,我们在AudioTrack::createTrack_l函数里还可以看到audio data的数据区管理部分:

sp<IMemory> iMem = track->getCblk();

mAudioTrack = track;

mCblkMemory = iMem;

audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMem->pointer());

mCblk = cblk;

cblk实际上就是指向了audio buffer. 这样,AT就能用write函数写到这片audio data数据区了。

AF章节中,我们介绍过,AP通过调用AudioFlinger::openOutput函数,open了一个outStream, 创建了一个playbackThread, 并且用audio_io_handle_t id 键值来标记。

而output就是这个audio_io_handle_t id值,这样就能通过这个id,找到对应的playbackThread。然后在这个playback里面创建对应的Track。

如果一个playBackThread里面有多个Track,就需要用到AudioMixer来进行mixer混音操作。在AudioMixer章节,我们会详细介绍。

至此,我们大体介绍了AudioTrack是如何初始化的,如何在AudioFlinger中创建Track的,以及如何获得data buffer的。

很多细节我们放在了AudioFlnger和Audio Mixer来做介绍。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: