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函数
由此可见,AudioTrack::set函数很重要。负责对AT初始化
AT与AF在两个不同进程,其通信依靠的是createTrack_l中创建的位于AF中的Track实例。Track实例在AF中用数组的形式存放。
下面分析一下createTrack_l函数。
从上面看到,实际是调用了AudioFlinger::createTrack在AF里面创建了Track实例。那么是怎么创建的呢?
上面我们看到,先利用前面获得的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来做介绍。
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来做介绍。
相关文章推荐
- 物联网架构
- Canonical 携手三星:将 Ubuntu Core 带到 Artik 物联网硬件上
- 这7家物联网公司即将改变你的生活,你却还被蒙在鼓里!!!
- 树莓派2安装win 10 IoT
- 越狱Season 1-Episode 7: Riots, Drills and the Devil: Part 2
- 越狱Season 1-Episode 6: Riots, Drills and the Devil: Part 1
- 《Windows IoT 应用开发指南》
- 构建IoT系统必须的五项内容 (Page 4)
- 构建IoT系统必须的五项内容 (Page 3)
- 构建IoT系统必须的五项内容 (Page 2)
- 构建IoT系统必须的五项内容 (Page 1)
- 2016年物联网:你需要知道这6点
- 物联网是下一个5年的风口 万物互联是大势所趋
- 【工业4.0】物联网“新概”思考
- 通往快速、灵活、可扩展的商业物联网解决方案之路
- Piotr's Ants
- 【物联网】OpenWrt编译出现Unable to find remote helper for 'https'问题
- 怎样把LoRa终端功耗降到极致
- [文章摘要]Constructing knowledge from multivariate spatiotemporal data: integrating geographical visuali
- 物联网网络编程、Web编程综述