08.音频系统:第004课_Android音频系统详解:第006节_AudioTrack创建过程

在前面的小节中,我们讲解了AudioPolicyService与AudioFlinger这两个系统提供的服务,那么我们的应用程序怎么去使用这些服务区播放声音呢?我们先来体验一个测试程序frameworks\base\media\tests\audiotests\shared_mem_test(共享内存测试程序-该程序会创建一个共享内存,然后在其中放入声音数据,进行播放):

int main() {
    ProcessState::self()->startThreadPool();
    AudioTrackTest *test;

    test = new AudioTrackTest();
    	/*构造一些正弦波*/
    	InitSine();     
    test->Execute();
    	Test01()
    		/*内存构建*/
    		heap = new MemoryDealer(1024*1024, "AudioTrack Heap Base");
    		sp<AudioTrack> track = new AudioTrack(AUDIO_STREAM_MUSIC,// stream typerate,
               AUDIO_FORMAT_PCM_16_BIT,// word length, PCM
               AUDIO_CHANNEL_OUT_MONO,
               iMem);
            track->start(); 
}

我们先体验一下这个应用程序,要先编译一下frameworks\base\media\tests\audiotests\shared_mem_test,然后重烧写,执行shared_mem_test命令,插上耳机我们就能听到声音。现在我们分析继续分析源码,忽略数据的构建过程,我们播放声音是非常简单的,只需要创建一个AudioTrack,然后调用track->start()。我们看看AudioTrack的构造函数:

AudioTrack::AudioTrack()
	mStatus = set(streamType, sampleRate, format, channelMask,frameCount, flags, cbf, user, notificationFrames,0 /*sharedBuffer*/, false/*threadCanCallJava*/,sessionId, transferType,offloadInfo, uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed);

其上的set函数才是直接和硬件挂钩的函数。上面的是C++的测试函数,现在我们来看看Java的测试程序frameworks\base\media\tests\MediaFrameworkTest\src\com\android\mediaframeworktest\functional\audio\MediaAudioTrackTest.java,在使用java编写的程序之前,我们应该知道,其也存在同名的AudioTrack类。及在Java创建AudioTrack时,其会导致C++的AudioTrack被创建。我们进入MediaAudioTrackTest.java文件:
在这里插入图片描述
如上,我们可以看到一堆的测试程序,我们找到:

public void testSetStereoVolumeMax() throws Exception {
	/*得到一个buffer*/
	int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
	/*创建一个AudioTrack*/
	AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT, minBuffSize, TEST_MODE);
	/*写入数据*/
	track.write(data, 0, data.length);
	/*播放数据*/
	track.play();

我们分析一下AudioTrack的创建过程:

 	// post-condition: mStreamType is overwritten with a value
    //     that reflects the audio attributes (e.g. an AudioAttributes object with a usage of
    //     AudioAttributes.USAGE_MEDIA will map to AudioManager.STREAM_MUSIC
 private native final int native_setup(Object /*WeakReference<AudioTrack>*/ audiotrack_this,
            Object /*AudioAttributes*/ attributes,
            int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat,
            int buffSizeInBytes, int mode, int[] sessionId, long nativeAudioTrack);

从名字上看,他会调用C++中实现的native_setup函数,android_media_AudioTrack.cpp:

static const JNINativeMethod gMethods[] = {
    {"native_stop",          "()V",      (void *)android_media_AudioTrack_stop},	

可以知道其对应:

android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, jobject jaa,jintArray jSampleRate, jint channelPositionMask, jint channelIndexMask,jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession,jlong nativeAudioTrack)
	sp<AudioTrack> lpTrack = 0;
    // create the native AudioTrack object,该处没有使用任何参数,则说明其没有调用set函数,即没有和硬件挂钩
    lpTrack = new AudioTrack();
    /*调用set函数,和硬件产生关联*/
    status = lpTrack->set(
                    AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
                    sampleRateInHertz,
                    format,// word length, PCM
                    nativeChannelMask,
                    frameCount,
                    flag,
                    audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
                    0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
                    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);

可以看到,其获得了一个C++实现的AudioTrack。AudioTrack创建过程中,最重要的是set函数。下面是总结的一句话:
播放声音时都要创建AudioTrack对象,
java的AudioTrack对象创建时会导致c++的AudioTrack对象被创建;
所以分析的核心是c++的AudioTrack类,
创建AudioTrack时涉及一个重要函数: set

接下来我们猜测一下AudioTrack创建过程中的主要工作,及set函数的主要工作:
在这里插入图片描述

我们知道对于android系统,其可能接有一个或者多个声卡,系统中使用output描述声卡的输出通道,对于每一个output都有一个线程(playbackThread),他们由AudioFlinger管理。
对于应用程序,他不关心声音从哪里播放,其只知道声音的格式,比如之前分析的c++测试程序,其其在创建AudioTrack时,会指定一些参数:

sp<AudioTrack> track = new AudioTrack(AUDIO_STREAM_MUSIC,// stream typerate,
               AUDIO_FORMAT_PCM_16_BIT,// word length, PCM
               AUDIO_CHANNEL_OUT_MONO,
               iMem);
            track->start(); 

即APP只能确定声音的属性,不能确定声音从哪个设备播放。到时其最终肯定需要一个设备进行播放,所以他需要和某个设备建立联系,或者某个设备对应的线程建立联系,由这些线程把对个应用程序传来的声音混合在一起,然后从某个设备播放出来。

那么AudioTrack在创建的时候,他就应该实现这个挂钩的操作,那么我们猜测一下AudioTrack在挂钩的过程中会做哪些事情:

1 使用AudioTrack的属性, 根据AudioPolicy找到对应的output、playbackThread
2 在playbackThread中创建对应的track
3 APP的AudioTrack 和 playbackThread的mTracks中的track之间建立共享内存

之前我们说过,在每个playbackThread中,有一个mTracks数组,其中肯定有一项,与我们的应用程序对应起来,以后应用程序往track中写入数据时,playbackThread就能从对应的track中取出数据,然后混音播放。所以APP的AudioTrack 和 playbackThread的mTracks中的track之间需要建立共享内存。下面是AudioTrack创建调用的时序图:
在这里插入图片描述
重要部分如下:
在这里插入图片描述
这次就不带大家走一遍了,有兴趣的朋友可以根据时序图,自己查看一下源码。下次继续分析以上三点:
1 使用AudioTrack的属性, 根据AudioPolicy找到对应的output、playbackThread
2 在playbackThread中创建对应的track
3 APP的AudioTrack 和 playbackThread的mTracks中的track之间建立共享内存

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江南才尽,年少无知!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值