Android音频子系统,音频流的回放(四)

Audiotrack被用于音频流的回放,用来传输数据。

AudioTrack支持两种数据模式:

一种是Static,静态就是指数据一次性交付给对方,简单高效,一次完成所有数据的传递。适用于铃声、系统提醒等对内存要求小的播放操作。

一种是streaming,流模式和基于网络的音频流回放类似,音频数据严格按照要求不断地传递给接收方,直到结束。通常适用于音频文件较大时;音频属性要求高,如采样率高、深度大的数据;音频数据是实时产生的。

 

源码中有Audiotrack的应用范例:用于测试立体声左右声道最大音量。

Framework/base/media/tests/../MediaAudioTrackTest.java

public void testSetStereoVolumeMax() throws Exception {
	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;

// step1,计算最小缓冲区大小
int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
//step2,生成audiotrack对象。
AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT, minBuffSize, TEST_MODE);
byte data[] = new byte[minBuffSize/2];
// step3,写入音频数据
track.write(data, 0, data.length);
track.write(data, 0, data.length);
// step4,开始播放音频
track.play();
//获取最大音量值。
float maxVol = AudioTrack.getMaxVolume();
track.release();
}


上面的例子,包含了AudioTrack的常规操作

Step1,getMinBufferSize,获取最小的Buffer大小。函数实现如下:

AudioTrack.java

static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
//获取音频的声道数属性。
	switch(channelConfig) {
		case AudioFormat.CHANNEL_OUT_MONO:
		channelCount = 1;
		break;
		case AudioFormat.CHANNEL_OUT_STEREO:
		channelCount = 2;
		break;
}

//检查音频采样深度。
	if (!AudioFormat.isPublicEncoding(audioFormat)) { return ERROR_BAD_VALUE; }
//检查采样频率。
	if ( (sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN) ||
		(sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) ) { 
return ERROR_BAD_VALUE; 
}
//最小buffer的计算,取决于采样频率,声道数,采样深度这三个属性。具体计算在native层,android_media_audiotrack.cpp中。
int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
}


Step2,有了minbuffersize,就可以创建一个audiotrack对象了。

转到audiotrack.java的构造函数

AudioTrack.java

public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
        int bufferSizeInBytes, int mode)throws IllegalArgumentException {
// native initialization
    int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
        sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/);
}

AudioTrack的一个重要任务是和Audioflinger建立联系,这是由native代码实现的。

android_media_AudioTrack.cpp

static jint android_media_AudioTrack_setup(…){
//创建一个native层的audiotrack。
	lpTrack = new AudioTrack();
//存储音频数据的地方
	lpJniStorage = new AudioTrackJniStorage();
//调用Audiotrack的set函数,设置各种属性
    status = lpTrack->set(
    AUDIO_STREAM_DEFAULT,
            sampleRateInHertz,
            format,// word length, PCM
            nativeChannelMask,
            frameCount,
            AUDIO_OUTPUT_FLAG_NONE,
            audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
			0,
//不同的内存模式,这个参数不一样,MODE_STREAM,这个值是0;MODE_STATIC,这个是:lpJniStorage->mMemBase
            0,// shared mem 
            true,// thread can call Java
            sessionId,// audio session ID
            AudioTrack::TRANSFER_SYNC,
            NULL,                         // default offloadInfo
            -1, -1,                       // default uid, pid values
            paa);
}

接着看AudioTrack.cpp中的set函数的实现:

status_t AudioTrack::set(…){
//默认流类型是AUDIO_STREAM_MUSIC
    if (streamType == AUDIO_STREAM_DEFAULT) {
        streamType = AUDIO_STREAM_MUSIC;
}
//默认采样深度是16bit。
    if (format == AUDIO_FORMAT_DEFAULT) {
        format = AUDIO_FORMAT_PCM_16_BIT;
}

在经过一些有效性检查后,Audiotrack就要使用底层的音频服务了,这里的底层服务是指audioflinger,audiopolicyservice等,android系统在Audiotrack和底层服务之间又加了audiosystem和Audioservice,这就降低了Audiotrack与底层服务间的耦合。就是说,即使不同版本Android的音频系统改动较大,但只要audioSystem,audioservice向上的接口不变,那么audiotrack就不需要做任何修改。
//step1,创建一个线程AudioTrackThread
	mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
	mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
//step2,创建一个IAudioTrack,createTrack_l函数中会经过Auidosystem,进一步调用到audiopolicyservice的服务接口。
	status_t status = createTrack_l();
}

Step1,AudioTrackThread线程,一方面在Audiotrack和audioflinger之间做数据传输,作为客户端audiotrack用这个线程不断的传送数据,作为接收端的audioflinger也有一个线程(playbackthread)用于接收客户端发来的音频数据;另一方面,用于报告数据传输状态,Audiotrack中保存了mCbf变量,是callback_t类型的回调函数,用于回传音频传输过程中的状态给调用者。

Step2,createTrack_l中,会由audiosystem作为中转,调用audiopolicyservice,audioflinger实现的功能,如:getOutputForAttr,getFrameCount等;还有一个重要操作,是建立audiotrack与audioflinger之间跨进程沟通的桥梁IAudioTrack。

status_t AudioTrack::createTrack_l(){
	status = AudioSystem::getOutputForAttr(attr, &output,…);
	status = AudioSystem::getFrameCount(output, &mAfFrameCount);

	sp<IAudioTrack> track = audioFlinger->createTrack(streamType,…);
}

AudioSystem::getOutputForAttr(…);这个功能实现,最终还是有AudioPolicyservice来完成的。Getoutput会在当前系统中寻找最适合audiotrack的audio interface,及output输出通道(由audioflinger通过openoutput打开的通道),然后audiotrack会向这个output申请一个track(PlaybackThread::Track),audiotrack在Audioflinger内部就是以这个track来管理的,因为audiotrack和Audioflinger之间是跨进程的,所以还创建了他们之间的桥梁是IaudioTrack。

 

createTrack中的关键步骤:

AudioFlinger.cpp

sp<IAudioTrack> AudioFlinger::createTrack(…){
	sp<PlaybackThread::Track> track;
	sp<TrackHandle> trackHandle;
//这里的output (audio_io_handle_t),是在audioflinger::openoutput时产生的,这个值跟playbackthread是对应的。依据audio_io_handle_t全局标记值,找到匹配的playbackthread。然后在其内部创建playbacktrack::track对象,这个track的父类是trackBase,所有track对象都被添加到playbackthread:: mTracks中进行管理。TrackHandle就是Iaudiotrack.。
	PlaybackThread *thread = checkPlaybackThread_l(output);
	track = thread->createTrack_l(client, streamType, sampleRate, format,…);
	trackHandle = new TrackHandle(track);
}

Tracks.cpp

在创建Track对象时,同时调用了父类Trackbase的构造函数:

AudioFlinger::PlaybackThread::Track::Track(…) :  TrackBase(…){…}

在trackbase的构造函数中,申请了一块缓冲区,这块空间是可以跨进程共享的。AudioTrack通过track->getCblk();获取的就是这块内存空间,这块内存空间是针对mode_stream流模式下的音频数据的存放的。静态模式下音频数据的存放空间是由AudioTrackJniStorage来申请的。

AudioFlinger::ThreadBase::TrackBase::TrackBase(…){
	mCblkMemory = client->heap()->allocate(size);
}

AudioTrack.cpp

status_t AudioTrack::createTrack_l(){
	sp<IAudioTrack> track = audioFlinger->createTrack(…);
	sp<IMemory> iMem = track->getCblk();
}


下面是getCblk()的调用堆栈:

sp<IMemory> AudioFlinger::TrackHandle::getCblk() @Tracks.cppconst {
    return mTrack->getCblk();
}
sp<IMemory> getCblk()@TrackBase.h const { return mCblkMemory; }
到这里,Audiotrack可以通过IaudioTrack调用audioflinger的服务,应用实例(前面的testSetStereoVolumeMax ()@MediaAudioTrackTest.java)可以通过不断写入音频数据(track.write(data, 0, data.length);)回放声音。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值