Android音频子系统,音频流(六)

音频数据流

音频正常的回放过程:

比如用MediaPlayer播放音频,先要把音频文件读取到内存中,然后执行对应的解码操作,mediaplayer是在mediaplayerservice的帮助下完成解码相关操作的,mediaplayerservice会使用audiotrack完成播放功能。

一个audiotrack代表一个播放实例,系统中可能同时运行多个audiotrack实例,同时系统中也会有多个音频回放设备,audiotrack和音频回放设备的对应关系由audiopolicyservice来确定,aps根据每个audiotrack所属“流类型”来为他选择与当前系统最匹配的输出设备,然后查找支持这个输出设备的audiofligner中的output输出通道(也就是openoutput所打开的通道)。

Audioflinger执行audiopolicyservice确定好的路由策略,将各路音频数据进行混音,然后传到hal层,进一步输出到最终的音频设备中。在回放时,Audiofligner中起关键作用的有两个:一个是playbackthread,往通道中传输数据;一个是audiomixer,这是混音的核心。

 

Audiotrack中的音频流

以MediaAudioTrackTest.java中范例来分析:
public void testSetStereoVolumeMax() @MediaAudioTrackTest.java throws Exception {
AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, 
TEST_FORMAT, minBuffSize, TEST_MODE);
	track.write(data, 0, data.length);
}

上面的代码中,write函数把data数据写入audiotrack中,说明audiotrack内部一定申请了内存空间来存储音频数据,这是java层代码,下面直接看native层的实现:

static jint android_media_AudioTrack_setup(…)@ android_media_AudioTrack.cpp{
	sp<AudioTrack> lpTrack = new AudioTrack();
//流模式下,音频数据是分多次传递的,这里传入的参数是0,audiotrack需要的内存空间是后面由audioflinger根据需要分配的一块缓冲区。
	status = lpTrack->set(…0,// shared mem …);
//静态模式下,把内存空间的地址(lpJniStorage->mMemBase)传给了audiotrack,这块空间是由AudioTrackJniStorage事先分配的。
	status = lpTrack->set(…lpJniStorage->mMemBase,// shared mem …);
}

接着看流模式下分配的缓冲区:

status_t AudioTrack::createTrack_l()@AudioTrack.cpp {
// frameCount决定了申请缓冲区的大小。
	sp<IAudioTrack> track = audioFlinger->createTrack(…frameCount…);
//向audioflinger申请缓冲区
	sp<IMemory> iMem = track->getCblk();
//与audioflinger的ipc通信中介
	mAudioTrack = track;
	mCblkMemory = iMem;
	audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
	mCblk = cblk;
}

IAudioTrack在audioflinger中的实现是TrackHandler。

sp<IMemory> AudioFlinger::TrackHandle::getCblk() const @ Tracks.cpp {
    return mTrack->getCblk();
}

这里的mTrack是一个playbackThread::track,是在audioflinger::createTrack时生成的。mTrack属于某个特定的playbackthread实例,每个audiotrack在audioflinger中都有一个对应的playbackthread。看看playbackthread::track如何生成一块内存区域:

Track继承自trackbase,trackbase的构造函数中将申请所需的内存单元。

AudioFlinger::ThreadBase::TrackBase::TrackBase(…frameCount…)@ Tracks.cpp {
	if (client != 0) {
		mCblkMemory = client->heap()->allocate(size);
	}
}

mCblkMemory指向的内存地址由client指定,这个client是在Audioflinger::createtrack中生成的,每个playbackthread虽然有使用内存空间的权利,但是对内存的申请、回收仍是由audioflinger来掌控的。

sp<IAudioTrack> AudioFlinger::createTrack( )@AudioFlinger.cpp{
	sp<Client> client = registerPid(pid);
}

函数registerPid为当前的pid(audiotrack所在进程的pid)生成一个audioflinger::client实例,并将<pid,client>键值对添加到mclients中。每个audiotrack在audioflinger中有且仅有一个client实例。

 

       到这里,audiotrack和audioflinger中与音频数据相关的内存空间就分析完了。大致是这样的:

       Audiotrack(java)在构造时,通过本地方法native_setup来传递应用层所需的最小音频数据空间。

       Native_setup负责生成audiotrack(native)对象,此时还没涉及内存申请,随后调用Audiotrack::set接口,并将应用层计算出的数据空间大小转化为framecount。

       在set实现中,首先找到匹配的audioflinger中的playbackthread,接着调用audioflinger::createtrack在playbackthread中新增一个track,同时建立audiotrack和audioflinger间的通信接口Iaudiotrack。在audioflinger内部的track生成过程中,会有trackbase申请相应的内存空间。

       接下来audiotrack可以通过Iaudiotrack::getCblk来获得这个数据空间。

       之后audiotrack和audioflinger就能够利用这个数据缓冲区空间来传递音频数据,在audiotrack中,它是有audiotrack::mCblkmemory来表示,在audioflinger中,它是由Trackbase::mCBlkMemory来表示的。

       AudioMixer是由playbackthread(MixerThread)生成的,跟audioflinger属于同一个进程。AudioMixer中用于混音操作的缓冲区对象,和audiotrack,audiofligner中的数据区是同一个。

    AudioMixer内部由一个state_t结构体变量mState,其中的数组track_t         tracks[MAX_NUM_TRACKS]存储了最多32路Track数据,每个PlaybackThread::TrackBase在AudioMixer中对应tracks数组中一个元素。




  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值