美文网首页
Android音视频四:AudioTrack创建与通信

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

作者: 小城哇哇 | 来源:发表于2022-06-18 14:53 被阅读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通信用的 所以调用和方法就是一条链路的,好像也没什么特别好说的,主要是知道这几个类之间的关系,才比较好找代码

    相关文章

      网友评论

          本文标题:Android音视频四:AudioTrack创建与通信

          本文链接:https://www.haomeiwen.com/subject/zmlpmrtx.html