Android音视频四:AudioTrack创建与通信

2022-06-18  本文已影响0人  小城哇哇

AudioTrack的创建

大致流程图

对应代码

总的来说:

  1. 上层的AudioTrack最后都会对应一个Native层的Track
  2. AudioTrack会通过binder通信给到AudioFlinger,AudioFlinger会根据属性找到合适的回放线程PlaybackThread
  3. AudioTrack还会和Track有binder通信,通过对IAudioTrack的实现(个人看法)

JAVA层的AudioTrack.java

# base/media/java/android/media/AudioTrack.java

private AudioTrack(....) throws IllegalArgumentException {
         // lyh JNI调用本地方法 native_setup --> android_media_AudioTrack_setup
        int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
                sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
                mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/,
                offload, encapsulationMode, tunerConfiguration,
                getCurrentOpPackageName());
}


AudioTrack的JNI

# base/core/jni/android_media_AudioTrack.cpp

static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,.....) {

        //   .... 省略
        // lyh native层AudioTrack对象创建
        lpTrack = new AudioTrack(opPackageNameStr.c_str());

        status_t status = NO_ERROR;
        // lyh 两种模式
        switch (memoryMode) {
            // lyh 写一段播一段
            case MODE_STREAM:
                // 给AudioTrack赋值
                status = lpTrack->set(...各种参数);
                break;
            // lyh 一次写完播放
            case MODE_STATIC:
                // lyh 应用端申请共享内存
                if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
                    ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
                    goto native_init_failure;
                }
                status = lpTrack->set(....);
                break;
}


AudioTrack.cpp

// lyh java层的new AudioTrack --> native_setup --> native的set
status_t AudioTrack::set(audio_stream_type_t streamType,uint32_t sampleRate,audio_format_t format,.....)
{

    // lyh 设置音频数据传输类型
    switch (transferType) {
        ....省略
    }

    // handle default values first.
    // lyh 音频流类型设置,程序会设为默认值AUDIO_STREAM_MUSIC
    if (streamType == AUDIO_STREAM_DEFAULT) {
        streamType = AUDIO_STREAM_MUSIC;
    }

    // lyh 音频格式设置,采样深度默认为16bit
    if (format == AUDIO_FORMAT_DEFAULT) {
        format = AUDIO_FORMAT_PCM_16_BIT;
    }

    // lyh 输出声道合法性检查
    if (!audio_is_output_channel(channelMask)) {
        status = BAD_VALUE;
        goto exit;
    }

    // lyh 左右声道声音
    mVolume[AUDIO_INTERLEAVE_LEFT] = 1.0f;
    mVolume[AUDIO_INTERLEAVE_RIGHT] = 1.0f;

    // lyh 如果设置了提供音频数据的回调函数,则启动AudioTrackThread线程来提供音频数据
    if (cbf != NULL) {
        // lyh 
        /*AudioTrackThread实现两个核心功能:
         *1 AudioTrack与AudioFlinger之间 数据传输,AudioFlinger启动了一个线程专门用于接收客户端的
         *  音频数据,同时客户端也需要一个线程来“不断”的传送音频数据
         *2 用于报告数据的传输状态,AudioTrack中保存了一个callback_t类型的回调函数(即全局变量mCbf)
         *  用于事件发生时进行回传
         */
        mAudioTrackThread = new AudioTrackThread(*this);
        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
    }

    // create the IAudioTrack
    {
        AutoMutex lock(mLock);
        // lyh 调用到自己的createTrack_l line-1505
        status = createTrack_l();
    }
exit:
    mStatus = status;
    return status;
}


//lyh 构建aduiotrack的流程
status_t AudioTrack::createTrack_l()
{
    // lyh 获取AudioFligner
    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();

    // lyh 这里调用了AudioFligner(并不是直接调用,而是通过binder通信,如果你直接进入AudioFligner.cpp看代码会晕)
    // lyh track == BnAudioTrack的代理对象 == BpAudioTrack
    sp<IAudioTrack> track = audioFlinger->createTrack(input,output,&status);

    // lyh BpAudioTrack保存在自己的变量中
    mAudioTrack = track;
}


AudioFlinger.cpp

sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input,
                                          CreateTrackOutput& output,
                                          status_t *status)
{
    sp<PlaybackThread::Track> track;
    sp<TrackHandle> trackHandle;

    // lyh 获取输出设备(这个函数最终会在AudioPolicyManager.cpp中实现,通过mEngine直接获取device)
    lStatus = AudioSystem::getOutputForAttr(&localAttr, &output.outputId, sessionId, &streamType,
                                            clientPid, clientUid, &input.config, input.flags,
                                            &output.selectedDeviceId, &portId, &secondaryOutputs);



    {
        Mutex::Autolock _l(mLock);
        // lyh 根据output确定回放线程
        PlaybackThread *thread = checkPlaybackThread_l(output.outputId);

        // lyh 创建Client
        client = registerPid(clientPid);

        // lyh 一个AudioTrack对应一个Track对象
        track = thread->createTrack_l(client, streamType, localAttr, &output.sampleRate,
                                      input.config.format, input.config.channel_mask,
                                      &output.frameCount, &outputcreateTrack_l.notificationFrameCount,
                                      input.notificationsPerBuffer, input.speed,
                                      input.sharedBuffer, sessionId, &output.flags,
                                      callingPid, input.clientInfo.clientTid, clientUid,
                                      &lStatus, portId, input.audioTrackCallback,
                                      input.opPackageName);

    }

    // return handle to client
    // lyh 为该Track创建代理对象TrackHandle
    // lyh TrackHandle extend BpTrackHandle
    trackHandle = new TrackHandle(track);

    // 返回给AudioTrack
    return trackHandle;
}


Threads.cpp

sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(....)
{

     // lyh track的构造
    track = new Track(this, client, streamType, attr, sampleRate, format,
                       channelMask, frameCount,
                       nullptr /* buffer */, (size_t)0 /* bufferSize */, sharedBuffer,
                      sessionId, creatorPid, uid, *flags, TrackBase::TYPE_DEFAULT, portId,
                       SIZE_MAX /*frameCountToBeReady*/, opPackageName);

    // lyh 保存
    mTracks.add(track);
    return track;
}


AudioTrack的Binder通信

不知道你有没有这样一个疑问,从上面的分析可以知道,在这个方法中返回的是audioFlinger->createTrack返回的是HandleTrack (extend BnAudioTrack),他是binder通信中的Bn端,而通过网上的资料查到,执行完这个方法,我们会拿到Binder通信的代理端Bp(BpAudioTrack)

有没有令人非常的费解...而出错的地方就是我没有真正的走AudioTrack和AudioFlinger的binder通信流程

# AudioTrack.cpp
status_t AudioTrack::createTrack_l()
{
    sp<IAudioTrack> track = audioFlinger->createTrack(input,output,&status);
}

AudioTrack和AudioFlinger

  1. 想要和AudioFliger通信,我们得拿到Bp代理端,这一步通常用AudioSystem帮我们做到
  2. 拿到代理对象就可以调用方法,内部会帮我们调用【remote()->transact】
  3. 通过进程的处理,最后在Bn本地端就会通过【onTransact】接受到对应方法去执行AudioFligner自己的方法了

所以AudioTrack调用audioFlinger->createTrack的真正流程是这样的

class BpAudioFlinger : public BpInterface<IAudioFlinger>
{
    // AudioTrack调用的方法!
    virtual sp<IAudioTrack> createTrack(const CreateTrackInput& input,
                                        CreateTrackOutput& output,
                                        status_t *status)
    {


        // lyh AudioTrack拿到AudioFlinger代理对象,调用createTrack,执行到这里等待到onTransact回复reply
        // lyh reply有BBinder(Bn端的父类,这里就是HandleTrack,也就是BnAudioTrack)
        // lyh 而这里BnAudioFligner会根据CREATE_TRACK去找本地方法,才会调用到AuioFlinger的createTrack
        // lyh 然后得到HandleTrack写入reply传递(?这不还是HandleTrack吗)
        status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);


        // lyh 这里可以去看看 binder通信中传递binder对象和Parcelable的转换
        // lyh reply.readStrongBinder() 返回的是 BBinder 的代理对象 BpBinder
        // lyh 也就是HandleTrack(BnAudioTrack)的代理对象BpAudioTrack
        track = interface_cast<IAudioTrack>(reply.readStrongBinder());
 
        output.readFromParcel(&reply);
        // lyh 再返回给AudioTrack使用
        return track;
    }
}

AudioTrack和Track

通过上面的分析我们已经拿到BpAudioTrack了,这个对象是用来AudioTrack和Track之间binder通信用的 所以调用和方法就是一条链路的,好像也没什么特别好说的,主要是知道这几个类之间的关系,才比较好找代码

上一篇下一篇

猜你喜欢

热点阅读