美文网首页
AudioRecord源码解读(3)

AudioRecord源码解读(3)

作者: android小奉先 | 来源:发表于2021-10-05 21:54 被阅读0次

    本篇介绍

    AudioRecord可以用来采集PCM,本篇介绍下AudioRecord的创建流程。

    源码介绍

        public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
                int bufferSizeInBytes)
    

    这儿的souce可以选择的如下:

           AudioSource.DEFAULT,
            AudioSource.MIC,
            AudioSource.VOICE_UPLINK,
            AudioSource.VOICE_DOWNLINK,
            AudioSource.VOICE_CALL,
            AudioSource.CAMCORDER,
            AudioSource.VOICE_RECOGNITION,
            AudioSource.VOICE_COMMUNICATION,
            AudioSource.UNPROCESSED,
            AudioSource.VOICE_PERFORMANCE,
    

    关于采样率,除了44100Hz所有设备上都保证支持,其他频率就不一定支持了,这时候可以通过使用参数SAMPLE_RATE_UNSPECIFIED,让设备自己去决策使用的采样率。
    channelConfig是采样通道,当前所有设备都保证支持单声道,多声道就不一定支持了。
    bufferSizeInBytes是buffer大小,用来存采集的数据,一般是直接用接口getMinBufferSize的返回值作为buffer大小。
    现在看下getMinBufferSize的实现:

        static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
            int channelCount = 0;
            switch (channelConfig) {
            case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
            case AudioFormat.CHANNEL_IN_MONO:
            case AudioFormat.CHANNEL_CONFIGURATION_MONO:
                channelCount = 1;
                break;
            case AudioFormat.CHANNEL_IN_STEREO:
            case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
            case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
                channelCount = 2;
                break;
            case AudioFormat.CHANNEL_INVALID:
            default:
                loge("getMinBufferSize(): Invalid channel configuration.");
                return ERROR_BAD_VALUE;
            }
    
            int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
            if (size == 0) {
                return ERROR_BAD_VALUE;
            }
            else if (size == -1) {
                return ERROR;
            }
            else {
                return size;
            }
        }
    

    可以看到Java侧没做啥逻辑,实现下沉到了native,接着看下native_get_min_buff_size的内容:

    static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env,  jobject thiz,
        jint sampleRateInHertz, jint channelCount, jint audioFormat) {
        size_t frameCount = 0;
        audio_format_t format = audioFormatToNative(audioFormat); // 把java 的格式转成native的
        status_t result = AudioRecord::getMinFrameCount(&frameCount,  // 获取最小帧数
                sampleRateInHertz,
                format,
                audio_channel_in_mask_from_count(channelCount));
        return frameCount * channelCount * audio_bytes_per_sample(format);
    }
    

    这儿的关键就是获取最小帧数,接着看下getMinFrameCount的实现:

    status_t AudioRecord::getMinFrameCount(
            size_t* frameCount,
            uint32_t sampleRate,
            audio_format_t format,
            audio_channel_mask_t channelMask)
    {
        if (frameCount == NULL) {
            return BAD_VALUE;
        }
    
        size_t size;
        status_t status = AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &size);
        if (status != NO_ERROR) {
            ALOGE("%s(): AudioSystem could not query the input buffer size for"
                  " sampleRate %u, format %#x, channelMask %#x; status %d",
                   __func__, sampleRate, format, channelMask, status);
            return status;
        }
    
        // We double the size of input buffer for ping pong use of record buffer.
        // Assumes audio_is_linear_pcm(format)
        if ((*frameCount = (size * 2) / (audio_channel_count_from_in_mask(channelMask) *
                audio_bytes_per_sample(format))) == 0) {
            ALOGE("%s(): Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
                    __func__, sampleRate, format, channelMask);
            return BAD_VALUE;
        }
    
        return NO_ERROR;
    }
    

    这儿关键的方法是getInputBufferSize,继续看下实现:

    status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t format,
            audio_channel_mask_t channelMask, size_t* buffSize)
    {
        const sp<AudioFlingerClient> afc = getAudioFlingerClient();
        if (afc == 0) {
            return NO_INIT;
        }
        return afc->getInputBufferSize(sampleRate, format, channelMask, buffSize);
    }
    

    这时候的afc并不是AudioFlinger,而是AudioSystem自己定义的一个Client,用来向AudioFligner注册回调,感知audio io变化的。因此这时候实现还在AdioSystem里面:

    status_t AudioSystem::AudioFlingerClient::getInputBufferSize(
                                                    uint32_t sampleRate, audio_format_t format,
                                                    audio_channel_mask_t channelMask, size_t* buffSize)
    {
        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); 
        if (af == 0) {
            return PERMISSION_DENIED;
        }
        Mutex::Autolock _l(mLock);
        // Do we have a stale mInBuffSize or are we requesting the input buffer size for new values
        if ((mInBuffSize == 0) || (sampleRate != mInSamplingRate) || (format != mInFormat)
            || (channelMask != mInChannelMask)) {
            size_t inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask);
            if (inBuffSize == 0) {
                ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %#x channelMask %#x",
                        sampleRate, format, channelMask);
                return BAD_VALUE;
            }
            // A benign race is possible here: we could overwrite a fresher cache entry
            // save the request params
            mInSamplingRate = sampleRate;
            mInFormat = format;
            mInChannelMask = channelMask;
    
            mInBuffSize = inBuffSize;
        }
    
        *buffSize = mInBuffSize;
    
        return NO_ERROR;
    }
    

    这儿可以看到buffersize是从AudioFlinger请求过来的,接下来就看下AudioFliner的实现:

    
    size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format,
            audio_channel_mask_t channelMask) const
    {
        status_t ret = initCheck();
    
        AutoMutex lock(mHardwareLock);
    
        mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
    
        sp<DeviceHalInterface> dev = mPrimaryHardwareDev->hwDevice();
        std::vector<audio_channel_mask_t> channelMasks = {channelMask};
        if (channelMask != AUDIO_CHANNEL_IN_MONO)
            channelMasks.push_back(AUDIO_CHANNEL_IN_MONO);
        if (channelMask != AUDIO_CHANNEL_IN_STEREO)
            channelMasks.push_back(AUDIO_CHANNEL_IN_STEREO);
    
        std::vector<audio_format_t> formats = {format};
        if (format != AUDIO_FORMAT_PCM_16_BIT)
            formats.push_back(AUDIO_FORMAT_PCM_16_BIT);
    
        std::vector<uint32_t> sampleRates = {sampleRate};
        static const uint32_t SR_44100 = 44100;
        static const uint32_t SR_48000 = 48000;
    
        if (sampleRate != SR_48000)
            sampleRates.push_back(SR_48000);
        if (sampleRate != SR_44100)
            sampleRates.push_back(SR_44100);
    
        mHardwareStatus = AUDIO_HW_IDLE;
    
        // Change parameters of the configuration each iteration until we find a
        // configuration that the device will support.
        audio_config_t config = AUDIO_CONFIG_INITIALIZER;
        for (auto testChannelMask : channelMasks) {
            config.channel_mask = testChannelMask;
            for (auto testFormat : formats) {
                config.format = testFormat;
                for (auto testSampleRate : sampleRates) {
                    config.sample_rate = testSampleRate;
    
                    size_t bytes = 0;
                    status_t result = dev->getInputBufferSize(&config, &bytes); // 从hal层获取bytes
                    if (result != OK || bytes == 0) {
                        continue;
                    }
    
                    if (config.sample_rate != sampleRate || config.channel_mask != channelMask ||
                        config.format != format) {
                        uint32_t dstChannelCount = audio_channel_count_from_in_mask(channelMask);
                        uint32_t srcChannelCount =
                            audio_channel_count_from_in_mask(config.channel_mask);
                        size_t srcFrames =
                            bytes / audio_bytes_per_frame(srcChannelCount, config.format);
                        size_t dstFrames = destinationFramesPossible(
                            srcFrames, config.sample_rate, sampleRate);
                        bytes = dstFrames * audio_bytes_per_frame(dstChannelCount, format); // 重新计算bytes
                    }
                    return bytes;
                }
            }
        }
        return 0;
    }
    

    这时候就完成了getMinBufferSize的实现介绍。
    接下来继续看下AudioRecord的实现流程:

       public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
                int sessionId) throws IllegalArgumentException {
            mRecordingState = RECORDSTATE_STOPPED;
    
            // remember which looper is associated with the AudioRecord instanciation
            if ((mInitializationLooper = Looper.myLooper()) == null) {
                mInitializationLooper = Looper.getMainLooper();
            }
    
            // is this AudioRecord using REMOTE_SUBMIX at full volume?
            if (attributes.getCapturePreset() == MediaRecorder.AudioSource.REMOTE_SUBMIX) {
                final AudioAttributes.Builder filteredAttr = new AudioAttributes.Builder();
                final Iterator<String> tagsIter = attributes.getTags().iterator();
                while (tagsIter.hasNext()) {
                    final String tag = tagsIter.next();
                    if (tag.equalsIgnoreCase(SUBMIX_FIXED_VOLUME)) {
                        mIsSubmixFullVolume = true;
                        Log.v(TAG, "Will record from REMOTE_SUBMIX at full fixed volume");
                    } else { // SUBMIX_FIXED_VOLUME: is not to be propagated to the native layers
                        filteredAttr.addTag(tag);
                    }
                }
                filteredAttr.setInternalCapturePreset(attributes.getCapturePreset());
                mAudioAttributes = filteredAttr.build();
            } else {
                mAudioAttributes = attributes;
            }
    
            int rate = format.getSampleRate();
            if (rate == AudioFormat.SAMPLE_RATE_UNSPECIFIED) {
                rate = 0;
            }
    
            int encoding = AudioFormat.ENCODING_DEFAULT;
            if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0)
            {
                encoding = format.getEncoding();
            }
    
            audioParamCheck(attributes.getCapturePreset(), rate, encoding);
    
            if ((format.getPropertySetMask()
                    & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0) {
                mChannelIndexMask = format.getChannelIndexMask();
                mChannelCount = format.getChannelCount();
            }
            if ((format.getPropertySetMask()
                    & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0) {
                mChannelMask = getChannelMaskFromLegacyConfig(format.getChannelMask(), false);
                mChannelCount = format.getChannelCount();
            } else if (mChannelIndexMask == 0) {
                mChannelMask = getChannelMaskFromLegacyConfig(AudioFormat.CHANNEL_IN_DEFAULT, false);
                mChannelCount =  AudioFormat.channelCountFromInChannelMask(mChannelMask);
            }
    
            audioBuffSizeCheck(bufferSizeInBytes);
    
            int[] sampleRate = new int[] {mSampleRate};
            int[] session = new int[1];
            session[0] = sessionId;
            //TODO: update native initialization when information about hardware init failure
            //      due to capture device already open is available.
            int initResult = native_setup( new WeakReference<AudioRecord>(this),
                    mAudioAttributes, sampleRate, mChannelMask, mChannelIndexMask,
                    mAudioFormat, mNativeBufferSizeInBytes,
                    session, getCurrentOpPackageName(), 0 /*nativeRecordInJavaObj*/); // 真正实现的地方
            if (initResult != SUCCESS) {
                loge("Error code "+initResult+" when initializing native AudioRecord object.");
                return; // with mState == STATE_UNINITIALIZED
            }
    
            mSampleRate = sampleRate[0];
            mSessionId = session[0];
    
            mState = STATE_INITIALIZED;
        }
    
    

    可以看到Java层只是做了一个参数检查,实现还是在native,接着看下native_setup的实现:

    static jint
    android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
            jobject jaa, jintArray jSampleRate, jint channelMask, jint channelIndexMask,
            jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName,
            jlong nativeRecordInJavaObj)
    {
        audio_channel_mask_t localChanMask = inChannelMaskToNative(channelMask);
        jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
      
        audio_session_t sessionId = (audio_session_t) nSession[0];
        env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
        nSession = NULL;
    
        sp<AudioRecord> lpRecorder = 0;
        audiorecord_callback_cookie *lpCallbackData = NULL;
    
        jclass clazz = env->GetObjectClass(thiz);
        if (clazz == NULL) {
            ALOGE("Can't find %s when setting up callback.", kClassPathName);
            return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
        }
    
        // if we pass in an existing *Native* AudioRecord, we don't need to create/initialize one.
        if (nativeRecordInJavaObj == 0) {  // native的audio record还没创建,那么就需要创建
        
            jint elements[1];
            env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
            int sampleRateInHertz = elements[0];
    
            // channel index mask takes priority over channel position masks.
            if (channelIndexMask) {
                // Java channel index masks need the representation bits set.
                localChanMask = audio_channel_mask_from_representation_and_bits(
                        AUDIO_CHANNEL_REPRESENTATION_INDEX,
                        channelIndexMask);
            }
            // Java channel position masks map directly to the native definition
    
            if (!audio_is_input_channel(localChanMask)) {
                ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", localChanMask);
                return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
            }
            uint32_t channelCount = audio_channel_count_from_in_mask(localChanMask);
    
            // compare the format against the Java constants
            audio_format_t format = audioFormatToNative(audioFormat);
            if (format == AUDIO_FORMAT_INVALID) {
                ALOGE("Error creating AudioRecord: unsupported audio format %d.", audioFormat);
                return (jint) AUDIORECORD_ERROR_SETUP_INVALIDFORMAT;
            }
    
            size_t bytesPerSample = audio_bytes_per_sample(format);
    
            if (buffSizeInBytes == 0) {
                 ALOGE("Error creating AudioRecord: frameCount is 0.");
                return (jint) AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT;
            }
            size_t frameSize = channelCount * bytesPerSample;
            size_t frameCount = buffSizeInBytes / frameSize;
    
            ScopedUtfChars opPackageNameStr(env, opPackageName);
    
            // create an uninitialized AudioRecord object
            lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str())); // 创建AudioRecord
    
            // read the AudioAttributes values
            auto paa = JNIAudioAttributeHelper::makeUnique();
            jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
            if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
                return jStatus;
            }
            ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
    
            audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
            if (paa->flags & AUDIO_FLAG_HW_HOTWORD) {
                flags = AUDIO_INPUT_FLAG_HW_HOTWORD;
            }
            // create the callback information:
            // this data will be passed with every AudioRecord callback
            lpCallbackData = new audiorecord_callback_cookie;
            lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
            // we use a weak reference so the AudioRecord object can be garbage collected.
            lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
            lpCallbackData->busy = false;
    
            const status_t status = lpRecorder->set(paa->source, // set 配置
                sampleRateInHertz,
                format,        // word length, PCM
                localChanMask,
                frameCount,
                recorderCallback,// callback_t
                lpCallbackData,// void* user
                0,             // notificationFrames,
                true,          // threadCanCallJava
                sessionId,
                AudioRecord::TRANSFER_DEFAULT,
                flags,
                -1, -1,        // default uid, pid
                paa.get());
    
            if (status != NO_ERROR) {
                ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
                        status);
                goto native_init_failure;
            }
            // Set caller name so it can be logged in destructor.
            // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_JAVA
            lpRecorder->setCallerName("java");
        } else { // end if nativeRecordInJavaObj == 0) // 已经创建了native的AudioRecord
            lpRecorder = (AudioRecord*)nativeRecordInJavaObj;
    
            // create the callback information:
            // this data will be passed with every AudioRecord callback
            lpCallbackData = new audiorecord_callback_cookie;
            lpCallbackData->audioRecord_class = (jclass)env->NewGlobalRef(clazz);
            // we use a weak reference so the AudioRecord object can be garbage collected.
            lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
            lpCallbackData->busy = false;
        }
    
        nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
        if (nSession == NULL) {
            ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
            goto native_init_failure;
        }
        // read the audio session ID back from AudioRecord in case a new session was created during set()
        nSession[0] = lpRecorder->getSessionId();
        env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
        nSession = NULL;
    
        {
            const jint elements[1] = { (jint) lpRecorder->getSampleRate() };
            env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
        }
    
        {   // scope for the lock
            Mutex::Autolock l(sLock);
            sAudioRecordCallBackCookies.add(lpCallbackData);
        }
        // save our newly created C++ AudioRecord in the "nativeRecorderInJavaObj" field
        // of the Java object
        setAudioRecord(env, thiz, lpRecorder); // 关联Java对象
    
        // save our newly created callback information in the "nativeCallbackCookie" field
        // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
        env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
    
        return (jint) AUDIO_JAVA_SUCCESS;
    
        // failure:
    native_init_failure:
        env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
        env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
        delete lpCallbackData;
        env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
    
        // lpRecorder goes out of scope, so reference count drops to zero
        return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
    }
    

    可以看到一共做了一下几件事

    • 如果native的AudioRecord还没创建,那么就进行创建,创建后关联上Java对象
    • 如果native的AudioRecord已经创建了,那么就直接Java对象

    接下来看下AudioRecord的创建:

    AudioRecord::AudioRecord(
            audio_source_t inputSource,
            uint32_t sampleRate,
            audio_format_t format,
            audio_channel_mask_t channelMask,
            const String16& opPackageName,
            size_t frameCount,
            callback_t cbf,
            void* user,
            uint32_t notificationFrames,
            audio_session_t sessionId,
            transfer_type transferType,
            audio_input_flags_t flags,
            uid_t uid,
            pid_t pid,
            const audio_attributes_t* pAttributes,
            audio_port_handle_t selectedDeviceId,
            audio_microphone_direction_t selectedMicDirection,
            float microphoneFieldDimension)
        : mActive(false),
          mStatus(NO_INIT),
          mOpPackageName(opPackageName),
          mSessionId(AUDIO_SESSION_ALLOCATE),
          mPreviousPriority(ANDROID_PRIORITY_NORMAL),
          mPreviousSchedulingGroup(SP_DEFAULT),
          mProxy(NULL)
    {
        (void)set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
                notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
                uid, pid, pAttributes, selectedDeviceId,
                selectedMicDirection, microphoneFieldDimension);
    }
    

    可以看到具体实现就是set,这样就直接看set就可以了:

    
    status_t AudioRecord::set(
            audio_source_t inputSource,
            uint32_t sampleRate,
            audio_format_t format,
            audio_channel_mask_t channelMask,
            size_t frameCount,
            callback_t cbf,
            void* user,
            uint32_t notificationFrames,
            bool threadCanCallJava,
            audio_session_t sessionId,
            transfer_type transferType,
            audio_input_flags_t flags,
            uid_t uid,
            pid_t pid,
            const audio_attributes_t* pAttributes,
            audio_port_handle_t selectedDeviceId,
            audio_microphone_direction_t selectedMicDirection,
            float microphoneFieldDimension)
    {
        switch (transferType) {      // 传入的transfer是default,其余case可以先忽略
        case TRANSFER_DEFAULT:
            if (cbf == NULL || threadCanCallJava) {
                transferType = TRANSFER_SYNC;
            } else {
                transferType = TRANSFER_CALLBACK;
            }
            break;
        case TRANSFER_CALLBACK:
            if (cbf == NULL) {
                ALOGE("%s(): Transfer type TRANSFER_CALLBACK but cbf == NULL", __func__);
                status = BAD_VALUE;
                goto exit;
            }
            break;
        case TRANSFER_OBTAIN:
        case TRANSFER_SYNC:
            break;
        default:
            ALOGE("%s(): Invalid transfer type %d", __func__, transferType);
            status = BAD_VALUE;
            goto exit;
        }
        mTransfer = transferType;
        mSampleRate = sampleRate;
    
        // these below should probably come from the audioFlinger too...
        if (format == AUDIO_FORMAT_DEFAULT) {
            format = AUDIO_FORMAT_PCM_16_BIT;
        }
    
        // validate parameters
        // AudioFlinger capture only supports linear PCM
        if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) {
            ALOGE("%s(): Format %#x is not linear pcm", __func__, format);
            status = BAD_VALUE;
            goto exit;
        }
        mFormat = format;
    
        if (!audio_is_input_channel(channelMask)) {
            ALOGE("%s(): Invalid channel mask %#x", __func__, channelMask);
            status = BAD_VALUE;
            goto exit;
        }
        mChannelMask = channelMask;
        channelCount = audio_channel_count_from_in_mask(channelMask);
        mChannelCount = channelCount;
    
        if (audio_is_linear_pcm(format)) {
            mFrameSize = channelCount * audio_bytes_per_sample(format);
        } else {
            mFrameSize = sizeof(uint8_t);
        }
    
        // mFrameCount is initialized in createRecord_l
        mReqFrameCount = frameCount;
    
        mNotificationFramesReq = notificationFrames;
        // mNotificationFramesAct is initialized in createRecord_l
    
        mSessionId = sessionId;
        ALOGV("%s(): mSessionId %d", __func__, mSessionId);
    
        callingPid = IPCThreadState::self()->getCallingPid();
        myPid = getpid();
        if (uid == AUDIO_UID_INVALID || (callingPid != myPid)) {
            mClientUid = IPCThreadState::self()->getCallingUid();
        } else {
            mClientUid = uid;
        }
        if (pid == -1 || (callingPid != myPid)) {
            mClientPid = callingPid;
        } else {
            mClientPid = pid;
        }
    
        mOrigFlags = mFlags = flags;
        mCbf = cbf;
    
        if (cbf != NULL) {
            mAudioRecordThread = new AudioRecordThread(*this);  // 回调线程,这样采集好数据后,可以主动回调调用方
            mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
            // thread begins in paused state, and will not reference us until start()
        }
    
        // create the IAudioRecord
        {
            AutoMutex lock(mLock);
            status = createRecord_l(0 /*epoch*/, mOpPackageName); // 创建record
        }
    }
    

    可以看到set里面关键的就是createRecord_l,可以猜想到接下来就会和AudioFlinger交互,让AudioFlinger创建对应的Record,并且会拿到该Record的binder proxy, 下面看下代码:

    // must be called with mLock held
    status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName)
    {
        const int64_t beginNs = systemTime();
        const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
        IAudioFlinger::CreateRecordInput input;
        IAudioFlinger::CreateRecordOutput output;
        audio_session_t originalSessionId;
        sp<media::IAudioRecord> record;
        void *iMemPointer;
        audio_track_cblk_t* cblk;
        status_t status;
        static const int32_t kMaxCreateAttempts = 3;
        int32_t remainingAttempts = kMaxCreateAttempts;
    
    
        // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
        // After fast request is denied, we will request again if IAudioRecord is re-created.
    
        // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger,
        // we must release it ourselves if anything goes wrong.
    
        // Client can only express a preference for FAST.  Server will perform additional tests.
        if (mFlags & AUDIO_INPUT_FLAG_FAST) {
            bool useCaseAllowed =
                // any of these use cases:
                // use case 1: callback transfer mode
                (mTransfer == TRANSFER_CALLBACK) ||
                // use case 2: blocking read mode
                // The default buffer capacity at 48 kHz is 2048 frames, or ~42.6 ms.
                // That's enough for double-buffering with our standard 20 ms rule of thumb for
                // the minimum period of a non-SCHED_FIFO thread.
                // This is needed so that AAudio apps can do a low latency non-blocking read from a
                // callback running with SCHED_FIFO.
                (mTransfer == TRANSFER_SYNC) ||
                // use case 3: obtain/release mode
                (mTransfer == TRANSFER_OBTAIN);
            if (!useCaseAllowed) {
                ALOGD("%s(%d): AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s",
                      __func__, mPortId,
                      convertTransferToText(mTransfer));
                mFlags = (audio_input_flags_t) (mFlags & ~(AUDIO_INPUT_FLAG_FAST |
                        AUDIO_INPUT_FLAG_RAW));
            }
        }
    
        input.attr = mAttributes;
        input.config.sample_rate = mSampleRate;
        input.config.channel_mask = mChannelMask;
        input.config.format = mFormat;
        input.clientInfo.clientUid = mClientUid;
        input.clientInfo.clientPid = mClientPid;
        input.clientInfo.clientTid = -1;
        if (mFlags & AUDIO_INPUT_FLAG_FAST) {
            if (mAudioRecordThread != 0) {
                input.clientInfo.clientTid = mAudioRecordThread->getTid();
            }
        }
        input.opPackageName = opPackageName;
        input.riid = mTracker->getRiid();
    
        input.flags = mFlags;
        // The notification frame count is the period between callbacks, as suggested by the client
        // but moderated by the server.  For record, the calculations are done entirely on server side.
        input.frameCount = mReqFrameCount;
        input.notificationFrameCount = mNotificationFramesReq;
        input.selectedDeviceId = mSelectedDeviceId;
        input.sessionId = mSessionId;
        originalSessionId = mSessionId;
    
        do {
            record = audioFlinger->createRecord(input, output, &status); // 创建record
            if (status == NO_ERROR) {
                break;
            }
            if (status != FAILED_TRANSACTION || --remainingAttempts <= 0) {
                ALOGE("%s(%d): AudioFlinger could not create record track, status: %d",
                      __func__, mPortId, status);
                goto exit;
            }
            // FAILED_TRANSACTION happens under very specific conditions causing a state mismatch
            // between audio policy manager and audio flinger during the input stream open sequence
            // and can be recovered by retrying.
            // Leave time for race condition to clear before retrying and randomize delay
            // to reduce the probability of concurrent retries in locked steps.
            usleep((20 + rand() % 30) * 10000);
        } while (1);
    
        ALOG_ASSERT(record != 0);
    
        // AudioFlinger now owns the reference to the I/O handle,
        // so we are no longer responsible for releasing it.
    
        mAwaitBoost = false;
        if (output.flags & AUDIO_INPUT_FLAG_FAST) {
            ALOGI("%s(%d): AUDIO_INPUT_FLAG_FAST successful; frameCount %zu -> %zu",
                  __func__, mPortId,
                  mReqFrameCount, output.frameCount);
            mAwaitBoost = true;
        }
        mFlags = output.flags;
        mRoutedDeviceId = output.selectedDeviceId;
        mSessionId = output.sessionId;
        mSampleRate = output.sampleRate;
    
        if (output.cblk == 0) {
            ALOGE("%s(%d): Could not get control block", __func__, mPortId);
            status = NO_INIT;
            goto exit;
        }
        // TODO: Using unsecurePointer() has some associated security pitfalls
        //       (see declaration for details).
        //       Either document why it is safe in this case or address the
        //       issue (e.g. by copying).
        iMemPointer = output.cblk ->unsecurePointer(); // 获取共享内存
        if (iMemPointer == NULL) {
            ALOGE("%s(%d): Could not get control block pointer", __func__, mPortId);
            status = NO_INIT;
            goto exit;
        }
        cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
    
        // Starting address of buffers in shared memory.
        // The buffers are either immediately after the control block,
        // or in a separate area at discretion of server.
        void *buffers;
        if (output.buffers == 0) {
            buffers = cblk + 1;
        } else {
            // TODO: Using unsecurePointer() has some associated security pitfalls
            //       (see declaration for details).
            //       Either document why it is safe in this case or address the
            //       issue (e.g. by copying).
            buffers = output.buffers->unsecurePointer();
            if (buffers == NULL) {
                ALOGE("%s(%d): Could not get buffer pointer", __func__, mPortId);
                status = NO_INIT;
                goto exit;
            }
        }
    
        // invariant that mAudioRecord != 0 is true only after set() returns successfully
        if (mAudioRecord != 0) {
            IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
            mDeathNotifier.clear();
        }
        mAudioRecord = record;
        mCblkMemory = output.cblk;
        mBufferMemory = output.buffers;
        IPCThreadState::self()->flushCommands();
    
        mCblk = cblk;
        // note that output.frameCount is the (possibly revised) value of mReqFrameCount
        if (output.frameCount < mReqFrameCount || (mReqFrameCount == 0 && output.frameCount == 0)) {
            ALOGW("%s(%d): Requested frameCount %zu but received frameCount %zu",
                  __func__, output.portId,
                  mReqFrameCount,  output.frameCount);
        }
    
        // Make sure that application is notified with sufficient margin before overrun.
        // The computation is done on server side.
        if (mNotificationFramesReq > 0 && output.notificationFrameCount != mNotificationFramesReq) {
            ALOGW("%s(%d): Server adjusted notificationFrames from %u to %zu for frameCount %zu",
                    __func__, output.portId,
                    mNotificationFramesReq, output.notificationFrameCount, output.frameCount);
        }
        mNotificationFramesAct = (uint32_t)output.notificationFrameCount;
    
        //mInput != input includes the case where mInput == AUDIO_IO_HANDLE_NONE for first creation
        if (mDeviceCallback != 0) {
            if (mInput != AUDIO_IO_HANDLE_NONE) {
                AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
            }
            AudioSystem::addAudioDeviceCallback(this, output.inputId, output.portId);
        }
    
        mPortId = output.portId;
        // We retain a copy of the I/O handle, but don't own the reference
        mInput = output.inputId;
        mRefreshRemaining = true;
    
        mFrameCount = output.frameCount;
        // If IAudioRecord is re-created, don't let the requested frameCount
        // decrease.  This can confuse clients that cache frameCount().
        if (mFrameCount > mReqFrameCount) {
            mReqFrameCount = mFrameCount;
        }
    
        // update proxy
        mProxy = new AudioRecordClientProxy(cblk, buffers, mFrameCount, mFrameSize); // 共享内存proxy
        mProxy->setEpoch(epoch);
        mProxy->setMinimum(mNotificationFramesAct);
    
        mDeathNotifier = new DeathNotifier(this);
        IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
      
    exit:
        mStatus = status;
        // sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger
        return status;
    }
    

    可以看到这里面果然主要做了上面猜想的2件事,接下来主要看下调用AudioFlinger创建Record,在看之前可以继续猜想下在AudioFlinger中需要做哪些事情,当前可以想到的应该有以下几件:

    • 创建一个Record结构,并创建可以跨进城共享的内存
    • 将该Record和一个线程关联,这样这个线程可以一直loop,并调用hal层的采集接口进行采集
    • 把这个Record结构包装成一个binder,这样调用方可以直接操作该Record

    加下来就继续看代码验证下猜想吧

    // ----------------------------------------------------------------------------
    
    sp<media::IAudioRecord> AudioFlinger::createRecord(const CreateRecordInput& input,
                                                       CreateRecordOutput& output,
                                                       status_t *status)
    {
        sp<RecordThread::RecordTrack> recordTrack;
        sp<RecordHandle> recordHandle;
        sp<Client> client;
        status_t lStatus;
        audio_session_t sessionId = input.sessionId;
        audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
    
        output.cblk.clear();
        output.buffers.clear();
        output.inputId = AUDIO_IO_HANDLE_NONE;
    
        bool updatePid = (input.clientInfo.clientPid == -1);
        const uid_t callingUid = IPCThreadState::self()->getCallingUid();
        uid_t clientUid = input.clientInfo.clientUid;
        if (!isAudioServerOrMediaServerUid(callingUid)) {
            ALOGW_IF(clientUid != callingUid,
                    "%s uid %d tried to pass itself off as %d",
                    __FUNCTION__, callingUid, clientUid);
            clientUid = callingUid;
            updatePid = true;
        }
        pid_t clientPid = input.clientInfo.clientPid;
        const pid_t callingPid = IPCThreadState::self()->getCallingPid();
        if (updatePid) {
            ALOGW_IF(clientPid != -1 && clientPid != callingPid,
                     "%s uid %d pid %d tried to pass itself off as pid %d",
                     __func__, callingUid, callingPid, clientPid);
            clientPid = callingPid;
        }
    
        // we don't yet support anything other than linear PCM
        if (!audio_is_valid_format(input.config.format) || !audio_is_linear_pcm(input.config.format)) {
            ALOGE("createRecord() invalid format %#x", input.config.format);
            lStatus = BAD_VALUE;
            goto Exit;
        }
    
        // further channel mask checks are performed by createRecordTrack_l()
        if (!audio_is_input_channel(input.config.channel_mask)) {
            ALOGE("createRecord() invalid channel mask %#x", input.config.channel_mask);
            lStatus = BAD_VALUE;
            goto Exit;
        }
    
        if (sessionId == AUDIO_SESSION_ALLOCATE) {
            sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
        } else if (audio_unique_id_get_use(sessionId) != AUDIO_UNIQUE_ID_USE_SESSION) {
            lStatus = BAD_VALUE;
            goto Exit;
        }
    
        output.sessionId = sessionId;
        output.selectedDeviceId = input.selectedDeviceId;
        output.flags = input.flags;
    
        client = registerPid(clientPid);  //创建共享内存
    
        // Not a conventional loop, but a retry loop for at most two iterations total.
        // Try first maybe with FAST flag then try again without FAST flag if that fails.
        // Exits loop via break on no error of got exit on error
        // The sp<> references will be dropped when re-entering scope.
        // The lack of indentation is deliberate, to reduce code churn and ease merges.
        for (;;) {
        // release previously opened input if retrying.
        if (output.inputId != AUDIO_IO_HANDLE_NONE) {
            recordTrack.clear();
            AudioSystem::releaseInput(portId);
            output.inputId = AUDIO_IO_HANDLE_NONE;
            output.selectedDeviceId = input.selectedDeviceId;
            portId = AUDIO_PORT_HANDLE_NONE;
        }
        lStatus = AudioSystem::getInputForAttr(&input.attr, &output.inputId, // 调用hal层获取属性信息
                                          input.riid,
                                          sessionId,
                                        // FIXME compare to AudioTrack
                                          clientPid,
                                          clientUid,
                                          input.opPackageName,
                                          &input.config,
                                          output.flags, &output.selectedDeviceId, &portId);
        if (lStatus != NO_ERROR) {
            ALOGE("createRecord() getInputForAttr return error %d", lStatus);
            goto Exit;
        }
    
        {
            Mutex::Autolock _l(mLock);
            RecordThread *thread = checkRecordThread_l(output.inputId); // 获取采集线程,验证猜想2
            if (thread == NULL) {
                ALOGW("createRecord() checkRecordThread_l failed, input handle %d", output.inputId);
                lStatus = FAILED_TRANSACTION;
                goto Exit;
            }
    
            ALOGV("createRecord() lSessionId: %d input %d", sessionId, output.inputId);
    
            output.sampleRate = input.config.sample_rate;
            output.frameCount = input.frameCount;
            output.notificationFrameCount = input.notificationFrameCount;
    
            recordTrack = thread->createRecordTrack_l(client, input.attr, &output.sampleRate, // 在采集线程中创建Record,验证猜想1
                                                      input.config.format, input.config.channel_mask,
                                                      &output.frameCount, sessionId,
                                                      &output.notificationFrameCount,
                                                      callingPid, clientUid, &output.flags,
                                                      input.clientInfo.clientTid,
                                                      &lStatus, portId,
                                                      input.opPackageName);
            LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
    
            // lStatus == BAD_TYPE means FAST flag was rejected: request a new input from
            // audio policy manager without FAST constraint
            if (lStatus == BAD_TYPE) {
                continue;
            }
    
            if (lStatus != NO_ERROR) {
                goto Exit;
            }
    
            // Check if one effect chain was awaiting for an AudioRecord to be created on this
            // session and move it to this thread.
            sp<EffectChain> chain = getOrphanEffectChain_l(sessionId);
            if (chain != 0) {
                Mutex::Autolock _l(thread->mLock);
                thread->addEffectChain_l(chain);
            }
            break;
        }
        // End of retry loop.
        // The lack of indentation is deliberate, to reduce code churn and ease merges.
        }
    
        output.cblk = recordTrack->getCblk(); 
        output.buffers = recordTrack->getBuffers(); // 返回匿名共享内存操作符
        output.portId = portId;
    
        // return handle to client
        recordHandle = new RecordHandle(recordTrack); // 包装成binder, 证明了猜想3
    
    Exit:
        if (lStatus != NO_ERROR) {
            // remove local strong reference to Client before deleting the RecordTrack so that the
            // Client destructor is called by the TrackBase destructor with mClientLock held
            // Don't hold mClientLock when releasing the reference on the track as the
            // destructor will acquire it.
            {
                Mutex::Autolock _cl(mClientLock);
                client.clear();
            }
            recordTrack.clear();
            if (output.inputId != AUDIO_IO_HANDLE_NONE) {
                AudioSystem::releaseInput(portId);
            }
        }
    
        *status = lStatus;
        return recordHandle;
    }
    

    当前会有2个采集线程,一个是 RecordThread, 一个是MmapCaptureThread,从字面就可以理解这两个线程的区别,接下来直接看创建Record:

    // RecordThread::createRecordTrack_l() must be called with AudioFlinger::mLock held
    sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l(
            const sp<AudioFlinger::Client>& client,
            const audio_attributes_t& attr,
            uint32_t *pSampleRate,
            audio_format_t format,
            audio_channel_mask_t channelMask,
            size_t *pFrameCount,
            audio_session_t sessionId,
            size_t *pNotificationFrameCount,
            pid_t creatorPid,
            uid_t uid,
            audio_input_flags_t *flags,
            pid_t tid,
            status_t *status,
            audio_port_handle_t portId,
            const String16& opPackageName)
    {
        size_t frameCount = *pFrameCount;
        size_t notificationFrameCount = *pNotificationFrameCount;
        sp<RecordTrack> track;
        status_t lStatus;
        audio_input_flags_t inputFlags = mInput->flags;
        audio_input_flags_t requestedFlags = *flags;
        uint32_t sampleRate;
    
        lStatus = initCheck();
    
        if (*pSampleRate == 0) {
            *pSampleRate = mSampleRate;
        }
        sampleRate = *pSampleRate;
    
        // special case for FAST flag considered OK if fast capture is present
        if (hasFastCapture()) {
            inputFlags = (audio_input_flags_t)(inputFlags | AUDIO_INPUT_FLAG_FAST);
        }
    
        // Check if requested flags are compatible with input stream flags
        if ((*flags & inputFlags) != *flags) {
            ALOGW("createRecordTrack_l(): mismatch between requested flags (%08x) and"
                    " input flags (%08x)",
                  *flags, inputFlags);
            *flags = (audio_input_flags_t)(*flags & inputFlags);
        }
    
        // client expresses a preference for FAST, but we get the final say
        if (*flags & AUDIO_INPUT_FLAG_FAST) {
          if (
                // we formerly checked for a callback handler (non-0 tid),
                // but that is no longer required for TRANSFER_OBTAIN mode
                //
                // Frame count is not specified (0), or is less than or equal the pipe depth.
                // It is OK to provide a higher capacity than requested.
                // We will force it to mPipeFramesP2 below.
                (frameCount <= mPipeFramesP2) &&
                // PCM data
                audio_is_linear_pcm(format) &&
                // hardware format
                (format == mFormat) &&
                // hardware channel mask
                (channelMask == mChannelMask) &&
                // hardware sample rate
                (sampleRate == mSampleRate) &&
                // record thread has an associated fast capture
                hasFastCapture() &&
                // there are sufficient fast track slots available
                mFastTrackAvail
            ) {
              // check compatibility with audio effects.
              Mutex::Autolock _l(mLock);
              // Do not accept FAST flag if the session has software effects
              sp<EffectChain> chain = getEffectChain_l(sessionId);
              if (chain != 0) {
                  audio_input_flags_t old = *flags;
                  chain->checkInputFlagCompatibility(flags);
                  if (old != *flags) {
                      ALOGV("%p AUDIO_INPUT_FLAGS denied by effect old=%#x new=%#x",
                              this, (int)old, (int)*flags);
                  }
              }
              ALOGV_IF((*flags & AUDIO_INPUT_FLAG_FAST) != 0,
                       "%p AUDIO_INPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu",
                       this, frameCount, mFrameCount);
          } else {
            ALOGV("%p AUDIO_INPUT_FLAG_FAST denied: frameCount=%zu mFrameCount=%zu mPipeFramesP2=%zu "
                    "format=%#x isLinear=%d mFormat=%#x channelMask=%#x sampleRate=%u mSampleRate=%u "
                    "hasFastCapture=%d tid=%d mFastTrackAvail=%d",
                    this, frameCount, mFrameCount, mPipeFramesP2,
                    format, audio_is_linear_pcm(format), mFormat, channelMask, sampleRate, mSampleRate,
                    hasFastCapture(), tid, mFastTrackAvail);
            *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_FAST);
          }
        }
    
        // If FAST or RAW flags were corrected, ask caller to request new input from audio policy
        if ((*flags & AUDIO_INPUT_FLAG_FAST) !=
                (requestedFlags & AUDIO_INPUT_FLAG_FAST)) {
            *flags = (audio_input_flags_t) (*flags & ~(AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW));
            lStatus = BAD_TYPE;
            goto Exit;
        }
    
        // compute track buffer size in frames, and suggest the notification frame count
        if (*flags & AUDIO_INPUT_FLAG_FAST) {
            // fast track: frame count is exactly the pipe depth
            frameCount = mPipeFramesP2;
            // ignore requested notificationFrames, and always notify exactly once every HAL buffer
            notificationFrameCount = mFrameCount;
        } else {
            // not fast track: max notification period is resampled equivalent of one HAL buffer time
            //                 or 20 ms if there is a fast capture
            // TODO This could be a roundupRatio inline, and const
            size_t maxNotificationFrames = ((int64_t) (hasFastCapture() ? mSampleRate/50 : mFrameCount)
                    * sampleRate + mSampleRate - 1) / mSampleRate;
            // minimum number of notification periods is at least kMinNotifications,
            // and at least kMinMs rounded up to a whole notification period (minNotificationsByMs)
            static const size_t kMinNotifications = 3;
            static const uint32_t kMinMs = 30;
            // TODO This could be a roundupRatio inline
            const size_t minFramesByMs = (sampleRate * kMinMs + 1000 - 1) / 1000;
            // TODO This could be a roundupRatio inline
            const size_t minNotificationsByMs = (minFramesByMs + maxNotificationFrames - 1) /
                    maxNotificationFrames;
            const size_t minFrameCount = maxNotificationFrames *
                    max(kMinNotifications, minNotificationsByMs);
            frameCount = max(frameCount, minFrameCount);
            if (notificationFrameCount == 0 || notificationFrameCount > maxNotificationFrames) {
                notificationFrameCount = maxNotificationFrames;
            }
        }
        *pFrameCount = frameCount;
        *pNotificationFrameCount = notificationFrameCount;
    
        { // scope for mLock
            Mutex::Autolock _l(mLock);
    
            track = new RecordTrack(this, client, attr, sampleRate, // 创建Record
                          format, channelMask, frameCount,
                          nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, creatorPid, uid,
                          *flags, TrackBase::TYPE_DEFAULT, opPackageName, portId);
    
            lStatus = track->initCheck();
            if (lStatus != NO_ERROR) {
                ALOGE("createRecordTrack_l() initCheck failed %d; no control block?", lStatus);
                // track must be cleared from the caller as the caller has the AF lock
                goto Exit;
            }
            mTracks.add(track); // 将Record加入到列表中
    
            if ((*flags & AUDIO_INPUT_FLAG_FAST) && (tid != -1)) {
                pid_t callingPid = IPCThreadState::self()->getCallingPid();
                // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
                // so ask activity manager to do this on our behalf
                sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true /*forApp*/);
            }
        }
    
        lStatus = NO_ERROR;
    
    Exit:
        *status = lStatus;
        return track;
    }
    
    

    看到这儿,可以看出来AudioFlinger管理Record的模式如下:


    image.png

    接下来继续看下RecordTrack的创建:

    // RecordTrack constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
    AudioFlinger::RecordThread::RecordTrack::RecordTrack(
                RecordThread *thread,
                const sp<Client>& client,
                const audio_attributes_t& attr,
                uint32_t sampleRate,
                audio_format_t format,
                audio_channel_mask_t channelMask,
                size_t frameCount,
                void *buffer,
                size_t bufferSize,
                audio_session_t sessionId,
                pid_t creatorPid,
                uid_t uid,
                audio_input_flags_t flags,
                track_type type,
                const String16& opPackageName,
                audio_port_handle_t portId)
        :   TrackBase(thread, client, attr, sampleRate, format,
                      channelMask, frameCount, buffer, bufferSize, sessionId,
                      creatorPid, uid, false /*isOut*/,
                      (type == TYPE_DEFAULT) ?
                              ((flags & AUDIO_INPUT_FLAG_FAST) ? ALLOC_PIPE : ALLOC_CBLK) :
                              ((buffer == NULL) ? ALLOC_LOCAL : ALLOC_NONE),
                      type, portId,
                      std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD) + std::to_string(portId)),
            mOverflow(false),
            mFramesToDrop(0),
            mResamplerBufferProvider(NULL), // initialize in case of early constructor exit
            mRecordBufferConverter(NULL),
            mFlags(flags),
            mSilenced(false),
            mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(uid, attr, opPackageName))
    {
        if (mCblk == NULL) {
            return;
        }
    
        if (!isDirect()) {
            mRecordBufferConverter = new RecordBufferConverter(
                    thread->mChannelMask, thread->mFormat, thread->mSampleRate,
                    channelMask, format, sampleRate);
            // Check if the RecordBufferConverter construction was successful.
            // If not, don't continue with construction.
            //
            // NOTE: It would be extremely rare that the record track cannot be created
            // for the current device, but a pending or future device change would make
            // the record track configuration valid.
            if (mRecordBufferConverter->initCheck() != NO_ERROR) {
                ALOGE("%s(%d): RecordTrack unable to create record buffer converter", __func__, mId);
                return;
            }
        }
    
        mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
                mFrameSize, !isExternalTrack());
    
        mResamplerBufferProvider = new ResamplerBufferProvider(this);
    
        if (flags & AUDIO_INPUT_FLAG_FAST) {
            ALOG_ASSERT(thread->mFastTrackAvail);
            thread->mFastTrackAvail = false;
        } else {
            // TODO: only Normal Record has timestamps (Fast Record does not).
            mServerLatencySupported = checkServerLatencySupported(mFormat, flags);
        }
    #ifdef TEE_SINK
        mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
                + "_" + std::to_string(mId)
                + "_R");
    #endif
    
        // Once this item is logged by the server, the client can add properties.
        mTrackMetrics.logConstructor(creatorPid, uid);
    }
    

    这儿应该会感觉比较熟悉了,共享内存的构造依旧是在TrackBase里面,毕竟采集和播放都需要一个共享内存,这块就可以抽象出来了:

    AudioFlinger::ThreadBase::TrackBase::TrackBase(
                ThreadBase *thread,
                const sp<Client>& client,
                const audio_attributes_t& attr,
                uint32_t sampleRate,
                audio_format_t format,
                audio_channel_mask_t channelMask,
                size_t frameCount,
                void *buffer,
                size_t bufferSize,
                audio_session_t sessionId,
                pid_t creatorPid,
                uid_t clientUid,
                bool isOut,
                alloc_type alloc,
                track_type type,
                audio_port_handle_t portId,
                std::string metricsId)
        :   RefBase(),
            mThread(thread),
            mClient(client),
            mCblk(NULL),
            // mBuffer, mBufferSize
            mState(IDLE),
            mAttr(attr),
            mSampleRate(sampleRate),
            mFormat(format),
            mChannelMask(channelMask),
            mChannelCount(isOut ?
                    audio_channel_count_from_out_mask(channelMask) :
                    audio_channel_count_from_in_mask(channelMask)),
            mFrameSize(audio_has_proportional_frames(format) ?
                    mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)),
            mFrameCount(frameCount),
            mSessionId(sessionId),
            mIsOut(isOut),
            mId(android_atomic_inc(&nextTrackId)),
            mTerminated(false),
            mType(type),
            mThreadIoHandle(thread ? thread->id() : AUDIO_IO_HANDLE_NONE),
            mPortId(portId),
            mIsInvalid(false),
            mTrackMetrics(std::move(metricsId), isOut),
            mCreatorPid(creatorPid)
    {
        const uid_t callingUid = IPCThreadState::self()->getCallingUid();
        mUid = clientUid;
        size_t minBufferSize = buffer == NULL ? roundup(frameCount) : frameCount;
        // check overflow when computing bufferSize due to multiplication by mFrameSize.
        if (minBufferSize < frameCount  // roundup rounds down for values above UINT_MAX / 2
                || mFrameSize == 0   // format needs to be correct
                || minBufferSize > SIZE_MAX / mFrameSize) {
            android_errorWriteLog(0x534e4554, "34749571");
            return;
        }
        minBufferSize *= mFrameSize;
    
        if (buffer == nullptr) {
            bufferSize = minBufferSize; // allocated here.
        } else if (minBufferSize > bufferSize) {
            android_errorWriteLog(0x534e4554, "38340117");
            return;
        }
    
        size_t size = sizeof(audio_track_cblk_t);
        if (buffer == NULL && alloc == ALLOC_CBLK) {
            // check overflow when computing allocation size for streaming tracks.
            if (size > SIZE_MAX - bufferSize) {
                android_errorWriteLog(0x534e4554, "34749571");
                return;
            }
            size += bufferSize;
        }
    
        if (client != 0) {
            mCblkMemory = client->heap()->allocate(size);  // 分配共享内存,client携带了创建的共享内存信息
            if (mCblkMemory == 0 ||
                    (mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->unsecurePointer())) == NULL) {
                ALOGE("%s(%d): not enough memory for AudioTrack size=%zu", __func__, mId, size);
                client->heap()->dump("AudioTrack");
                mCblkMemory.clear();
                return;
            }
        } else {
            mCblk = (audio_track_cblk_t *) malloc(size);
            if (mCblk == NULL) {
                ALOGE("%s(%d): not enough memory for AudioTrack size=%zu", __func__, mId, size);
                return;
            }
        }
    
        // construct the shared structure in-place.
        if (mCblk != NULL) {
            new(mCblk) audio_track_cblk_t();
            switch (alloc) {
            case ALLOC_READONLY: {
                const sp<MemoryDealer> roHeap(thread->readOnlyHeap());
                if (roHeap == 0 ||
                        (mBufferMemory = roHeap->allocate(bufferSize)) == 0 ||
                        (mBuffer = mBufferMemory->unsecurePointer()) == NULL) {
                    ALOGE("%s(%d): not enough memory for read-only buffer size=%zu",
                            __func__, mId, bufferSize);
                    if (roHeap != 0) {
                        roHeap->dump("buffer");
                    }
                    mCblkMemory.clear();
                    mBufferMemory.clear();
                    return;
                }
                memset(mBuffer, 0, bufferSize);
                } break;
            case ALLOC_PIPE:
                mBufferMemory = thread->pipeMemory();
                // mBuffer is the virtual address as seen from current process (mediaserver),
                // and should normally be coming from mBufferMemory->unsecurePointer().
                // However in this case the TrackBase does not reference the buffer directly.
                // It should references the buffer via the pipe.
                // Therefore, to detect incorrect usage of the buffer, we set mBuffer to NULL.
                mBuffer = NULL;
                bufferSize = 0;
                break;
            case ALLOC_CBLK:
                // clear all buffers
                if (buffer == NULL) {
                    mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
                    memset(mBuffer, 0, bufferSize);
                } else {
                    mBuffer = buffer;
    #if 0
                    mCblk->mFlags = CBLK_FORCEREADY;    // FIXME hack, need to fix the track ready logic
    #endif
                }
                break;
            case ALLOC_LOCAL:
                mBuffer = calloc(1, bufferSize);
                break;
            case ALLOC_NONE:
                mBuffer = buffer;
                break;
            default:
                LOG_ALWAYS_FATAL("%s(%d): invalid allocation type: %d", __func__, mId, (int)alloc);
            }
            mBufferSize = bufferSize;
    
    #ifdef TEE_SINK
            mTee.set(sampleRate, mChannelCount, format, NBAIO_Tee::TEE_FLAG_TRACK);
    #endif
    
        }
    }
    

    这儿再次回顾下client:

    sp<AudioFlinger::Client> AudioFlinger::registerPid(pid_t pid)
    {
        Mutex::Autolock _cl(mClientLock);
        // If pid is already in the mClients wp<> map, then use that entry
        // (for which promote() is always != 0), otherwise create a new entry and Client.
        sp<Client> client = mClients.valueFor(pid).promote();
        if (client == 0) {
            client = new Client(this, pid);
            mClients.add(pid, client);
        }
    
        return client;
    }
    
    AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
        :   RefBase(),
            mAudioFlinger(audioFlinger),
            mPid(pid)
    {
        mMemoryDealer = new MemoryDealer(
                audioFlinger->getClientSharedHeapSize(),
                (std::string("AudioFlinger::Client(") + std::to_string(pid) + ")").c_str());
    }
    
    

    可以看到内存也是按照pid进行管理的。
    接下来再看下如何包装成binder, RecordHandle是支持binder的:

    AudioFlinger::RecordHandle::~RecordHandle() {
        stop_nonvirtual();
        mRecordTrack->destroy();
    }
    
    binder::Status AudioFlinger::RecordHandle::start(int /*AudioSystem::sync_event_t*/ event,
            int /*audio_session_t*/ triggerSession) {
        ALOGV("%s()", __func__);
        return binder::Status::fromStatusT(
            mRecordTrack->start((AudioSystem::sync_event_t)event, (audio_session_t) triggerSession));
    }
    
    binder::Status AudioFlinger::RecordHandle::stop() {
        stop_nonvirtual();
        return binder::Status::ok();
    }
    
    void AudioFlinger::RecordHandle::stop_nonvirtual() {
        ALOGV("%s()", __func__);
        mRecordTrack->stop();
    }
    
    binder::Status AudioFlinger::RecordHandle::getActiveMicrophones(
            std::vector<media::MicrophoneInfo>* activeMicrophones) {
        ALOGV("%s()", __func__);
        return binder::Status::fromStatusT(
                mRecordTrack->getActiveMicrophones(activeMicrophones));
    }
    
    binder::Status AudioFlinger::RecordHandle::setPreferredMicrophoneDirection(
            int /*audio_microphone_direction_t*/ direction) {
        ALOGV("%s()", __func__);
        return binder::Status::fromStatusT(mRecordTrack->setPreferredMicrophoneDirection(
                static_cast<audio_microphone_direction_t>(direction)));
    }
    
    binder::Status AudioFlinger::RecordHandle::setPreferredMicrophoneFieldDimension(float zoom) {
        ALOGV("%s()", __func__);
        return binder::Status::fromStatusT(mRecordTrack->setPreferredMicrophoneFieldDimension(zoom));
    }
    

    到了这儿就完成了AudioRecord的创建。

    相关文章

      网友评论

          本文标题:AudioRecord源码解读(3)

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