(二)Audio子系統之new AudioRecord()


在上一篇文章《(一)Audio子系統之AudioRecord.getMinBufferSize》中已經介紹了AudioRecord如何獲取最小緩沖區大小,接下來,繼續分析AudioRecorder方法中的new AudioRecorder的實現,本文基於Android5.1,Android4.4請戳這里

 

函數原型:

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

  作用:

    創建AudioRecord對象

  參數:

    audioSource:錄制源,這里設置MediaRecorder.AudioSource.MIC,其他請見MediaRecorder.AudioSource錄制源定義,比如MediaRecorder.AudioSource.FM_TUNER等;

    sampleRateInHz:默認采樣率,單位Hz,這里設置為44100,44100Hz是當前唯一能保證在所有設備上工作的采樣率;

    channelConfig: 描述音頻通道設置,這里設置為AudioFormat.CHANNEL_CONFIGURATION_MONO,CHANNEL_CONFIGURATION_MONO保證能在所有設備上工作;

    audioFormat:音頻數據保證支持此格式,這里設置為AudioFormat.ENCODING_16BIT;

    bufferSizeInBytes:在錄制過程中,音頻數據寫入緩沖區的總數(字節),即getMinVufferSize()獲取到的值。

  異常:

    當參數設置不正確或不支持的參數時,將會拋出IllegalArgumentException

 

接下來進入系統分析具體實現

frameworks/base/media/java/android/media/AudioRecord.java

    public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes)
    throws IllegalArgumentException {
        this((new AudioAttributes.Builder())
                    .setInternalCapturePreset(audioSource)
                    .build(),
                (new AudioFormat.Builder())
                    .setChannelMask(getChannelMaskFromLegacyConfig(channelConfig,//0x10
                                        true/*allow legacy configurations*/))
                    .setEncoding(audioFormat)
                    .setSampleRate(sampleRateInHz)
                    .build(),
                bufferSizeInBytes,
                AudioManager.AUDIO_SESSION_ID_GENERATE);
    }

調用相應的方法,檢查參數的合法性,然后對參數進行保存等操作,然后調用自己的構造函數this()

    public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
            int sessionId) throws IllegalArgumentException {
        mRecordingState = RECORDSTATE_STOPPED;

        if (attributes == null) {
            throw new IllegalArgumentException("Illegal null AudioAttributes");
        }
        if (format == null) {
            throw new IllegalArgumentException("Illegal null AudioFormat");
        }

        // 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 = 0;
        if ((format.getPropertySetMask()
                & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0)
        {
            rate = format.getSampleRate();
        } else {
            rate = AudioSystem.getPrimaryOutputSamplingRate();
            if (rate <= 0) {
                rate = 44100;
            }
        }

        int encoding = AudioFormat.ENCODING_DEFAULT;
        if ((format.getPropertySetMask() & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0)
        {
            encoding = format.getEncoding();
        }

        audioParamCheck(attributes.getCapturePreset(), rate, encoding);

        mChannelCount = AudioFormat.channelCountFromInChannelMask(format.getChannelMask());
        mChannelMask = getChannelMaskFromLegacyConfig(format.getChannelMask(), false);

        audioBuffSizeCheck(bufferSizeInBytes);

        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, mSampleRate, mChannelMask, mAudioFormat, mNativeBufferSizeInBytes,
                session);
        if (initResult != SUCCESS) {
            loge("Error code "+initResult+" when initializing native AudioRecord object.");
            return; // with mState == STATE_UNINITIALIZED
        }

        mSessionId = session[0];
	
        mState = STATE_INITIALIZED;
    }

在這個函數中,主要做了如下工作

    1.標記mRecordingState為stoped狀態;

    2.獲取一個MainLooper;

    3.判斷錄音源是否是REMOTE_SUBMIX,有興趣的童鞋可以深入研究;

    4.重新獲取rate與format參數,這里會根據AUDIO_FORMAT_HAS_PROPERTY_X來判斷從哪里獲取參數,而在之前的構造函數中,設置參數的時候已經標記了該標志位,所以這兩個參數還是我們設置的;

    5.調用audioParamCheck對參數再一次進行檢查合法性;

    6.獲取聲道數以及聲道掩碼,單聲道掩碼為0x10,雙聲道掩碼為0x0c;

    7.調用audioBuffSizeCheck檢查最小緩沖區大小是否合法

    8.調用native_setup的native函數,注意這里傳過去的參數包括:指向自己的指針,錄制源,rate,聲道掩碼,format,minBuffSize,session[];

    9.標記mRecordingState為inited狀態;

        注:關於SessionId
             一個Session就是一個會話,每個會話都有一個獨一無二的Id來標識。該Id的最終管理在AudioFlinger中。
             一個會話可以被多個AudioTrack對象和MediaPlayer共用。
             共用一個Session的AudioTrack和MediaPlayer共享相同的AudioEffect(音效)。

我們只分析native_setup函數

frameworks/base/core/jni/android_media_AudioRecord.cpp

static jint
android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
        jobject jaa, jint sampleRateInHertz, jint channelMask,
                // Java channel masks map directly to the native definition
        jint audioFormat, jint buffSizeInBytes, jintArray jSession)
{
    if (jaa == 0) {
        ALOGE("Error creating AudioRecord: invalid audio attributes");
        return (jint) AUDIO_JAVA_ERROR;
    }

    if (!audio_is_input_channel(channelMask)) {
        ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", channelMask);
        return (jint) AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
    }
    uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);

    // 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;

    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 (jSession == NULL) {
        ALOGE("Error creating AudioRecord: invalid session ID pointer");
        return (jint) AUDIO_JAVA_ERROR;
    }

    jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
    if (nSession == NULL) {
        ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
        return (jint) AUDIO_JAVA_ERROR;
    }
    int sessionId = nSession[0];
    env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
    nSession = NULL;

    // create an uninitialized AudioRecord object
    sp<AudioRecord> lpRecorder = new AudioRecord();

    audio_attributes_t *paa = NULL;
    // read the AudioAttributes values
    paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
    const jstring jtags =
            (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
    const char* tags = env->GetStringUTFChars(jtags, NULL);
    // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
    strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
    env->ReleaseStringUTFChars(jtags, tags);
    paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource);
    paa->flags = (audio_flags_mask_t)env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
    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
    audiorecord_callback_cookie *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,
        sampleRateInHertz,
        format,        // word length, PCM
        channelMask,
        frameCount,
        recorderCallback,// callback_t
        lpCallbackData,// void* user
        0,             // notificationFrames,
        true,          // threadCanCallJava
        sessionId,
        AudioRecord::TRANSFER_DEFAULT,
        flags,
        paa);

    if (status != NO_ERROR) {
        ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
                status);
        goto native_init_failure;
    }
    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;

    {   // 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);

    // 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);

    return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
}

在這個函數中主要工作如下:

    1.判斷聲道掩碼是否合法,然后通過掩碼計算出聲道數;

    2.由於最小緩沖區大小是采樣幀數量*每個采樣幀大小得出,每個采樣幀大小為所有聲道數所占的字節數,從而求出采樣幀數量frameCount;

    3.進行一系列的JNI處理錄音源,以及把AudioRecord.java的指針綁定到lpCallbackData回調數據中,這樣就能把數據通過回調的方式通知到上層;

    4.調用AudioRecord的set函數,這里注意下flags,他的類型為audio_input_flags_t,定義在system\core\include\system\audio.h中,作為音頻輸入的標志,這里設置為AUDIO_INPUT_FLAG_NONE

typedef enum {
    AUDIO_INPUT_FLAG_NONE       = 0x0,  // no attributes
    AUDIO_INPUT_FLAG_FAST       = 0x1,  // prefer an input that supports "fast tracks"
    AUDIO_INPUT_FLAG_HW_HOTWORD = 0x2,  // prefer an input that captures from hw hotword source
} audio_input_flags_t;

    5.把lpRecorder對象以及lpCallbackData回調保存到javaAudioRecordFields的相應字段中。

這里分析lpRecorder->set函數

frameworks\av\media\libmedia\AudioRecord.cpp

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,
        int sessionId,
        transfer_type transferType,
        audio_input_flags_t flags,
        const audio_attributes_t* pAttributes)
{
    switch (transferType) {
    case TRANSFER_DEFAULT:
        if (cbf == NULL || threadCanCallJava) {
            transferType = TRANSFER_SYNC;
        } else {
            transferType = TRANSFER_CALLBACK;
        }
        break;
    case TRANSFER_CALLBACK:
        if (cbf == NULL) {
            ALOGE("Transfer type TRANSFER_CALLBACK but cbf == NULL");
            return BAD_VALUE;
        }
        break;
    case TRANSFER_OBTAIN:
    case TRANSFER_SYNC:
        break;
    default:
        ALOGE("Invalid transfer type %d", transferType);
        return BAD_VALUE;
    }
    mTransfer = transferType;

    AutoMutex lock(mLock);

    // invariant that mAudioRecord != 0 is true only after set() returns successfully
    if (mAudioRecord != 0) {
        ALOGE("Track already in use");
        return INVALID_OPERATION;
    }

    if (pAttributes == NULL) {
        memset(&mAttributes, 0, sizeof(audio_attributes_t));
        mAttributes.source = inputSource;
    } else {
        // stream type shouldn't be looked at, this track has audio attributes
        memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
        ALOGV("Building AudioRecord with attributes: source=%d flags=0x%x tags=[%s]",
              mAttributes.source, mAttributes.flags, mAttributes.tags);
    }

    if (sampleRate == 0) {
        ALOGE("Invalid sample rate %u", sampleRate);
        return BAD_VALUE;
    }
    mSampleRate = sampleRate;

    // these below should probably come from the audioFlinger too...
    if (format == AUDIO_FORMAT_DEFAULT) {
        format = AUDIO_FORMAT_PCM_16_BIT;
    }

    // validate parameters
    if (!audio_is_valid_format(format)) {
        ALOGE("Invalid format %#x", format);
        return BAD_VALUE;
    }
    // Temporary restriction: AudioFlinger currently supports 16-bit PCM only
    if (format != AUDIO_FORMAT_PCM_16_BIT) {
        ALOGE("Format %#x is not supported", format);
        return BAD_VALUE;
    }
    mFormat = format;

    if (!audio_is_input_channel(channelMask)) {
        ALOGE("Invalid channel mask %#x", channelMask);
        return BAD_VALUE;
    }
    mChannelMask = channelMask;
    uint32_t 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 openRecord_l
    mReqFrameCount = frameCount;

    mNotificationFramesReq = notificationFrames;
    // mNotificationFramesAct is initialized in openRecord_l

    if (sessionId == AUDIO_SESSION_ALLOCATE) {
        mSessionId = AudioSystem::newAudioUniqueId();
    } else {
        mSessionId = sessionId;
    }
    ALOGV("set(): mSessionId %d", mSessionId);

    mFlags = flags;
    mCbf = cbf;

    if (cbf != NULL) {
        mAudioRecordThread = new AudioRecordThread(*this, threadCanCallJava);
        mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
    }

    // create the IAudioRecord
    status_t status = openRecord_l(0 /*epoch*/);

    if (status != NO_ERROR) {
        if (mAudioRecordThread != 0) {
            mAudioRecordThread->requestExit();   // see comment in AudioRecord.h
            mAudioRecordThread->requestExitAndWait();
            mAudioRecordThread.clear();
        }
        return status;
    }

    mStatus = NO_ERROR;
    mActive = false;
    mUserData = user;
    // TODO: add audio hardware input latency here
    mLatency = (1000*mFrameCount) / sampleRate;
    mMarkerPosition = 0;
    mMarkerReached = false;
    mNewPosition = 0;
    mUpdatePeriod = 0;
    AudioSystem::acquireAudioSessionId(mSessionId, -1);
    mSequence = 1;
    mObservedSequence = mSequence;
    mInOverrun = false;

    return NO_ERROR;
}

在這個函數中主要工作如下:

    1.在JNI中傳遞過來的參數:transferType為TRANSFER_DEFAULT,cbf!=null,threadCanCallJava=true,所以mTransfer設置為TRANSFER_SYNC,他是決定如何從AudioRecord傳輸數據方式,后面會用到;

    2.保存相關的參數,如錄制源mAttributes.source,采樣率mSampleRate,采樣精度mFormat,聲道掩碼mChannelMask,聲道數mChannelCount,采樣幀大小mFrameSize,采樣幀數量mReqFrameCount,通知幀計數mNotificationFramesReq,mSessionId在這里更新了,音頻輸入標志mFlags還是之前的AUDIO_INPUT_FLAG_NONE

    3.當cbf數據回調函數不為null時,開啟一個錄音線程AudioRecordThread;

    4.調用openRecord_l(0)創建IAudioRecord對象;

    5.如果建立失敗,就銷毀錄音線程AudioRecordThread,否則更新參數;

這里繼續分析如何創建IAudioRecord對象

status_t AudioRecord::openRecord_l(size_t epoch)
{
    status_t status;
    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
    if (audioFlinger == 0) {
        ALOGE("Could not get audioflinger");
        return NO_INIT;
    }

    // Fast tracks must be at the primary _output_ [sic] sampling rate,
    // because there is currently no concept of a primary input sampling rate
    uint32_t afSampleRate = AudioSystem::getPrimaryOutputSamplingRate();
    if (afSampleRate == 0) {
        ALOGW("getPrimaryOutputSamplingRate failed");
    }

    // Client can only express a preference for FAST.  Server will perform additional tests.
    if ((mFlags & AUDIO_INPUT_FLAG_FAST) && !(
            // use case: callback transfer mode
            (mTransfer == TRANSFER_CALLBACK) &&
            // matching sample rate
            (mSampleRate == afSampleRate))) {
        ALOGW("AUDIO_INPUT_FLAG_FAST denied by client");
        // once denied, do not request again if IAudioRecord is re-created
        mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST);
    }

    IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;

    pid_t tid = -1;
    if (mFlags & AUDIO_INPUT_FLAG_FAST) {
        trackFlags |= IAudioFlinger::TRACK_FAST;
        if (mAudioRecordThread != 0) {
            tid = mAudioRecordThread->getTid();
        }
    }

    audio_io_handle_t input;
    status = AudioSystem::getInputForAttr(&mAttributes, &input, (audio_session_t)mSessionId,
                                        mSampleRate, mFormat, mChannelMask, mFlags);

    if (status != NO_ERROR) {
        ALOGE("Could not get audio input for record source %d, sample rate %u, format %#x, "
              "channel mask %#x, session %d, flags %#x",
              mAttributes.source, mSampleRate, mFormat, mChannelMask, mSessionId, mFlags);
        return BAD_VALUE;
    }
    {
    // 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.

    size_t frameCount = mReqFrameCount;
    size_t temp = frameCount;   // temp may be replaced by a revised value of frameCount,
                                // but we will still need the original value also
    int originalSessionId = mSessionId;

    // The notification frame count is the period between callbacks, as suggested by the server.
    size_t notificationFrames = mNotificationFramesReq;

    sp<IMemory> iMem;           // for cblk
    sp<IMemory> bufferMem;

	//return recordHandle = new RecordHandle(recordTrack);
	//class RecordHandle : public android::BnAudioRecord
    sp<IAudioRecord> record = audioFlinger->openRecord(input,
                                                       mSampleRate, mFormat,
                                                       mChannelMask,
                                                       &temp,
                                                       &trackFlags,
                                                       tid,
                                                       &mSessionId,
                                                       &notificationFrames,
                                                       iMem,
                                                       bufferMem,
                                                       &status);
    ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId,
            "session ID changed from %d to %d", originalSessionId, mSessionId);

    if (status != NO_ERROR) {
        ALOGE("AudioFlinger could not create record track, status: %d", status);
        goto release;
    }
    ALOG_ASSERT(record != 0);

    // AudioFlinger now owns the reference to the I/O handle,
    // so we are no longer responsible for releasing it.

    if (iMem == 0) {
        ALOGE("Could not get control block");
        return NO_INIT;
    }
    void *iMemPointer = iMem->pointer();
    if (iMemPointer == NULL) {
        ALOGE("Could not get control block pointer");
        return NO_INIT;
    }
    audio_track_cblk_t* 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 (bufferMem == 0) {
        buffers = cblk + 1;
    } else {
        buffers = bufferMem->pointer();
        if (buffers == NULL) {
            ALOGE("Could not get buffer pointer");
            return NO_INIT;
        }
    }

    // invariant that mAudioRecord != 0 is true only after set() returns successfully
    if (mAudioRecord != 0) {
        mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
        mDeathNotifier.clear();
    }
    mAudioRecord = record;
    mCblkMemory = iMem;
    mBufferMemory = bufferMem;
    IPCThreadState::self()->flushCommands();

    mCblk = cblk;
    // note that temp is the (possibly revised) value of frameCount
    if (temp < frameCount || (frameCount == 0 && temp == 0)) {
        ALOGW("Requested frameCount %zu but received frameCount %zu", frameCount, temp);
    }
    frameCount = temp;

    mAwaitBoost = false;
    if (mFlags & AUDIO_INPUT_FLAG_FAST) {
        if (trackFlags & IAudioFlinger::TRACK_FAST) {
            ALOGV("AUDIO_INPUT_FLAG_FAST successful; frameCount %zu", frameCount);
            mAwaitBoost = true;
        } else {
            ALOGV("AUDIO_INPUT_FLAG_FAST denied by server; frameCount %zu", frameCount);
            // once denied, do not request again if IAudioRecord is re-created
            mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST);
        }
    }

    // Make sure that application is notified with sufficient margin before overrun
    if (notificationFrames == 0 || notificationFrames > frameCount) {
        ALOGW("Received notificationFrames %zu for frameCount %zu", notificationFrames, frameCount);
    }
    mNotificationFramesAct = notificationFrames;

    // We retain a copy of the I/O handle, but don't own the reference
    mInput = input;
    mRefreshRemaining = true;

    mFrameCount = frameCount;
    // If IAudioRecord is re-created, don't let the requested frameCount
    // decrease.  This can confuse clients that cache frameCount().
    if (frameCount > mReqFrameCount) {
        mReqFrameCount = frameCount;
    }

    // update proxy
    mProxy = new AudioRecordClientProxy(cblk, buffers, mFrameCount, mFrameSize);
    mProxy->setEpoch(epoch);
    mProxy->setMinimum(mNotificationFramesAct);

    mDeathNotifier = new DeathNotifier(this);
    mAudioRecord->asBinder()->linkToDeath(mDeathNotifier, this);

    return NO_ERROR;
    }

release:
    AudioSystem::releaseInput(input, (audio_session_t)mSessionId);
    if (status == NO_ERROR) {
        status = NO_INIT;
    }
    return status;
}

在這個函數中主要工作如下:

    1.獲取IAudioFlinger對象,其通過binder和AudioFlinger通信,所以也就是相當於直接調用到AudioFlinger服務中了;

    2.判斷音頻輸入標志,是否需要清除AUDIO_INPUT_FLAG_FAST標志位,這里不需要,一直是AUDIO_INPUT_FLAG_NONE;

    3.調用AudioSystem::getInputForAttr獲取輸入流的句柄input;

    4.調用audioFlinger->openRecord創建IAudioRecord對象;

    5.通過IMemory共享內存,獲取錄音數據;

    6.更新AudioRecordClientProxy客戶端代理的錄音數據;

下面主要分析第3、4點:

    首先看下AudioRecord.cpp::openRecord_l(0)的第3步.獲取輸入流的句柄input

frameworks\av\media\libmedia\AudioSystem.cpp

status_t AudioSystem::getInputForAttr(const audio_attributes_t *attr,
                                audio_io_handle_t *input,
                                audio_session_t session,
                                uint32_t samplingRate,
                                audio_format_t format,
                                audio_channel_mask_t channelMask,
                                audio_input_flags_t flags)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    if (aps == 0) return NO_INIT;
    return aps->getInputForAttr(attr, input, session, samplingRate, format, channelMask, flags);
}

獲取AudioPolicy的服務,繼續調用AudioPolicyService的函數

frameworks\av\services\audiopolicy\AudioPolicyInterfaceImpl.cpp

status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
                                             audio_io_handle_t *input,
                                             audio_session_t session,
                                             uint32_t samplingRate,
                                             audio_format_t format,
                                             audio_channel_mask_t channelMask,
                                             audio_input_flags_t flags)
{
    if (mAudioPolicyManager == NULL) {
        return NO_INIT;
    }

    // already checked by client, but double-check in case the client wrapper is bypassed
    if (attr->source >= AUDIO_SOURCE_CNT && attr->source != AUDIO_SOURCE_HOTWORD &&
        attr->source != AUDIO_SOURCE_FM_TUNER) {
        return BAD_VALUE;
    }

    if (((attr->source == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) ||
        ((attr->source == AUDIO_SOURCE_FM_TUNER) && !captureFmTunerAllowed())) {
        return BAD_VALUE;
    }
    sp<AudioPolicyEffects>audioPolicyEffects;
    status_t status;
    AudioPolicyInterface::input_type_t inputType;
    {
        Mutex::Autolock _l(mLock);
        // the audio_in_acoustics_t parameter is ignored by get_input()
        status = mAudioPolicyManager->getInputForAttr(attr, input, session,
                                                     samplingRate, format, channelMask,
                                                     flags, &inputType);
        audioPolicyEffects = mAudioPolicyEffects;

        if (status == NO_ERROR) {
            // enforce permission (if any) required for each type of input
            switch (inputType) {
            case AudioPolicyInterface::API_INPUT_LEGACY:
                break;
            case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
                if (!captureAudioOutputAllowed()) {
                    ALOGE("getInputForAttr() permission denied: capture not allowed");
                    status = PERMISSION_DENIED;
                }
                break;
            case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE:
                if (!modifyAudioRoutingAllowed()) {
                    ALOGE("getInputForAttr() permission denied: modify audio routing not allowed");
                    status = PERMISSION_DENIED;
                }
                break;
            case AudioPolicyInterface::API_INPUT_INVALID:
            default:
                LOG_ALWAYS_FATAL("getInputForAttr() encountered an invalid input type %d",
                        (int)inputType);
            }
        }

        if (status != NO_ERROR) {
            if (status == PERMISSION_DENIED) {
                mAudioPolicyManager->releaseInput(*input, session);
            }
            return status;
        }
    }

    if (audioPolicyEffects != 0) {
        // create audio pre processors according to input source
        status_t status = audioPolicyEffects->addInputEffects(*input, attr->source, session);
        if (status != NO_ERROR && status != ALREADY_EXISTS) {
            ALOGW("Failed to add effects on input %d", *input);
        }
    }
    return NO_ERROR;
}

在這個函數中主要的工作如下:

    1.對source為HOTWORD或FM_TUNER的錄音源,判斷是否具有相應的錄音權限(根據應用進程號);

    2.繼續調用AudioPolicyManager的方法獲取input以及inputType;

    3.檢查應用是否具有該inputType的錄音權限;

    4.判斷是否需要添加音效(audioPolicyEffects),需要則使用audioPolicyEffects->addInputEffects添加音效;

繼續分析第2步

frameworks\av\services\audiopolicy\AudioPolicyManager.cpp

status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
                                             audio_io_handle_t *input,
                                             audio_session_t session,
                                             uint32_t samplingRate,
                                             audio_format_t format,
                                             audio_channel_mask_t channelMask,
                                             audio_input_flags_t flags,
                                             input_type_t *inputType)
{
    *input = AUDIO_IO_HANDLE_NONE;
    *inputType = API_INPUT_INVALID;
    audio_devices_t device;
    // handle legacy remote submix case where the address was not always specified
    String8 address = String8("");
    bool isSoundTrigger = false;
    audio_source_t inputSource = attr->source;
    audio_source_t halInputSource;
    AudioMix *policyMix = NULL;

    if (inputSource == AUDIO_SOURCE_DEFAULT) {
        inputSource = AUDIO_SOURCE_MIC;
    }
    halInputSource = inputSource;

    if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
            strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {

        device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
        address = String8(attr->tags + strlen("addr="));
        ssize_t index = mPolicyMixes.indexOfKey(address);
        if (index < 0) {
            ALOGW("getInputForAttr() no policy for address %s", address.string());
            return BAD_VALUE;
        }
        if (mPolicyMixes[index]->mMix.mMixType != MIX_TYPE_PLAYERS) {
            ALOGW("getInputForAttr() bad policy mix type for address %s", address.string());
            return BAD_VALUE;
        }
        policyMix = &mPolicyMixes[index]->mMix;
        *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
    } else {
        device = getDeviceAndMixForInputSource(inputSource, &policyMix);
        if (device == AUDIO_DEVICE_NONE) {
            ALOGW("getInputForAttr() could not find device for source %d", inputSource);
            return BAD_VALUE;
        }
        if (policyMix != NULL) {
            address = policyMix->mRegistrationId;
            if (policyMix->mMixType == MIX_TYPE_RECORDERS) {
                // there is an external policy, but this input is attached to a mix of recorders,
                // meaning it receives audio injected into the framework, so the recorder doesn't
                // know about it and is therefore considered "legacy"
                *inputType = API_INPUT_LEGACY;
            } else {
                // recording a mix of players defined by an external policy, we're rerouting for
                // an external policy
                *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
            }
        } else if (audio_is_remote_submix_device(device)) {
            address = String8("0");
            *inputType = API_INPUT_MIX_CAPTURE;
        } else {
            *inputType = API_INPUT_LEGACY;
        }
        // adapt channel selection to input source
        switch (inputSource) {
        case AUDIO_SOURCE_VOICE_UPLINK:
            channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
            break;
        case AUDIO_SOURCE_VOICE_DOWNLINK:
            channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
            break;
        case AUDIO_SOURCE_VOICE_CALL:
            channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
            break;
        default:
            break;
        }
        if (inputSource == AUDIO_SOURCE_HOTWORD) {
            ssize_t index = mSoundTriggerSessions.indexOfKey(session);
            if (index >= 0) {
                *input = mSoundTriggerSessions.valueFor(session);
                isSoundTrigger = true;
                flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
                ALOGV("SoundTrigger capture on session %d input %d", session, *input);
            } else {
                halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
            }
        }
    }

    sp<IOProfile> profile = getInputProfile(device, address,
                                            samplingRate, format, channelMask,
                                            flags);
    if (profile == 0) {
		PLOGV("profile == 0");
        //retry without flags
        audio_input_flags_t log_flags = flags;
        flags = AUDIO_INPUT_FLAG_NONE;
        profile = getInputProfile(device, address,
                                  samplingRate, format, channelMask,
                                  flags);
        if (profile == 0) {
            ALOGW("getInputForAttr() could not find profile for device 0x%X, samplingRate %u,"
                    "format %#x, channelMask 0x%X, flags %#x",
                    device, samplingRate, format, channelMask, log_flags);
            return BAD_VALUE;
        }
    }

    if (profile->mModule->mHandle == 0) {
		PLOGV("getInputForAttr(): HW module %s not opened", profile->mModule->mName);
        ALOGE("getInputForAttr(): HW module %s not opened", profile->mModule->mName);
        return NO_INIT;
    }

    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
    config.sample_rate = samplingRate;
    config.channel_mask = channelMask;
    config.format = format;

    status_t status = mpClientInterface->openInput(profile->mModule->mHandle,
                                                   input,
                                                   &config,
                                                   &device,
                                                   address,
                                                   halInputSource,
                                                   flags);
    // only accept input with the exact requested set of parameters
    if (status != NO_ERROR || *input == AUDIO_IO_HANDLE_NONE ||
        (samplingRate != config.sample_rate) ||
        (format != config.format) ||
        (channelMask != config.channel_mask)) {
        ALOGW("getInputForAttr() failed opening input: samplingRate %d, format %d, channelMask %x",
                samplingRate, format, channelMask);
        if (*input != AUDIO_IO_HANDLE_NONE) {
            mpClientInterface->closeInput(*input);
        }
        return BAD_VALUE;
    }

    sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(profile);
    inputDesc->mInputSource = inputSource;
    inputDesc->mRefCount = 0;
    inputDesc->mOpenRefCount = 1;
    inputDesc->mSamplingRate = samplingRate;
    inputDesc->mFormat = format;
    inputDesc->mChannelMask = channelMask;
    inputDesc->mDevice = device;
    inputDesc->mSessions.add(session);
    inputDesc->mIsSoundTrigger = isSoundTrigger;
    inputDesc->mPolicyMix = policyMix;

    ALOGV("getInputForAttr() returns input type = %d", inputType);

    addInput(*input, inputDesc);
    mpClientInterface->onAudioPortListUpdate();
    return NO_ERROR;
}

在這個函數中主要工作如下:

    1.調用getDeviceAndMixForInputSource函數獲取policyMix設備以及對應的audio_device_t設備類型(device),device定義在system\core\include\system\audio.h中,這里使用了內置的MIC,所以device為AUDIO_DEVICE_IN_BUILTIN_MIC,另外如果還需要新增一種音頻設備的話,需要在這里增加;

enum {
    AUDIO_DEVICE_NONE                          = 0x0,
    /* reserved bits */
    AUDIO_DEVICE_BIT_IN                        = 0x80000000,
    AUDIO_DEVICE_BIT_DEFAULT                   = 0x40000000,
    /* output devices */
    AUDIO_DEVICE_OUT_EARPIECE                  = 0x1,
    AUDIO_DEVICE_OUT_SPEAKER                   = 0x2,
    AUDIO_DEVICE_OUT_WIRED_HEADSET             = 0x4,
...
    /* input devices */
    AUDIO_DEVICE_IN_COMMUNICATION         = AUDIO_DEVICE_BIT_IN | 0x1,
    AUDIO_DEVICE_IN_AMBIENT               = AUDIO_DEVICE_BIT_IN | 0x2,
    AUDIO_DEVICE_IN_BUILTIN_MIC           = AUDIO_DEVICE_BIT_IN | 0x4,
...
    AUDIO_DEVICE_IN_ALL     = (AUDIO_DEVICE_IN_COMMUNICATION |
                               AUDIO_DEVICE_IN_AMBIENT |
                               AUDIO_DEVICE_IN_BUILTIN_MIC |
                               AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET |
                               AUDIO_DEVICE_IN_WIRED_HEADSET |
                               AUDIO_DEVICE_IN_HDMI |
                               AUDIO_DEVICE_IN_TELEPHONY_RX |
                               AUDIO_DEVICE_IN_BACK_MIC |
                               AUDIO_DEVICE_IN_REMOTE_SUBMIX |
                               AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET |
                               AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET |
                               AUDIO_DEVICE_IN_USB_ACCESSORY |
                               AUDIO_DEVICE_IN_USB_DEVICE |
                               AUDIO_DEVICE_IN_FM_TUNER |
                               AUDIO_DEVICE_IN_TV_TUNER |
                               AUDIO_DEVICE_IN_LINE |
                               AUDIO_DEVICE_IN_SPDIF |
                               AUDIO_DEVICE_IN_BLUETOOTH_A2DP |
                               AUDIO_DEVICE_IN_LOOPBACK |
							   AUDIO_DEVICE_IN_AF |
                               AUDIO_DEVICE_IN_DEFAULT),
    AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
    AUDIO_DEVICE_IN_ALL_USB  = (AUDIO_DEVICE_IN_USB_ACCESSORY |
                                AUDIO_DEVICE_IN_USB_DEVICE),
};

typedef uint32_t audio_devices_t;

    2.獲取inputType的類型

    typedef enum {
        API_INPUT_INVALID = -1,
        API_INPUT_LEGACY  = 0,// e.g. audio recording from a microphone
        API_INPUT_MIX_CAPTURE,// used for "remote submix", capture of the media to play it remotely
        API_INPUT_MIX_EXT_POLICY_REROUTE,// used for platform audio rerouting, where mixes are
                                         // handled by external and dynamically installed
                                         // policies which reroute audio mixes
    } input_type_t;

    3.更新channelMask,適配聲道到輸入源

    4.調用getInputProfile,根據傳進來的采樣率/精度/掩碼等參數與獲得的設備支持的Input Profile比較,返回一個與設備Profile匹配的IOProfile對象,IOProfile是用來描述輸出或輸入流的能力,策略管理器使用它來確定輸出或輸入是否適合於給定的用例,相應地打開/關閉它,以及連接/斷開音頻軌道

    5.如果獲取失敗的話,則使用AUDIO_INPUT_FLAG_NONE再次獲取一遍,如果依然失敗,則return一個bad news;

    6.繼續調用mpClientInterface->openInput建立起輸入流;

    7.根據IOProfile對象構造AudioInputDescriptor,並綁定到input流中,最后更新AudioPortList;

這里我們着重分析下第1,6步

   首先看下AudioPolicyManager.cpp::getInputForAttr()的第1步.獲取policyMix設備以及對應的audio_device_t設備類型(device)

audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,
                                                            AudioMix **policyMix)
{
    audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() &
                                            ~AUDIO_DEVICE_BIT_IN;

    for (size_t i = 0; i < mPolicyMixes.size(); i++) {
        if (mPolicyMixes[i]->mMix.mMixType != MIX_TYPE_RECORDERS) {
            continue;
        }
        for (size_t j = 0; j < mPolicyMixes[i]->mMix.mCriteria.size(); j++) {
            if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
                    mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource == inputSource) ||
               (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
                    mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource != inputSource)) {
                if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
                    if (policyMix != NULL) {
                        *policyMix = &mPolicyMixes[i]->mMix;
                    }
                    return AUDIO_DEVICE_IN_REMOTE_SUBMIX;
                }
                break;
            }
        }
    }

    return getDeviceForInputSource(inputSource);
}

audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource)
{
    uint32_t device = AUDIO_DEVICE_NONE;
    audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() &
                                            ~AUDIO_DEVICE_BIT_IN;

    switch (inputSource) {
    case AUDIO_SOURCE_VOICE_UPLINK:
      if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
          device = AUDIO_DEVICE_IN_VOICE_CALL;
          break;
      }
      break;

    case AUDIO_SOURCE_DEFAULT:
    case AUDIO_SOURCE_MIC:
    if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
        device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
    } else if ((mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO) &&
        (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
        device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
        device = AUDIO_DEVICE_IN_WIRED_HEADSET;
    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
        device = AUDIO_DEVICE_IN_USB_DEVICE;
    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
        device = AUDIO_DEVICE_IN_BUILTIN_MIC;
    }
    break;

    case AUDIO_SOURCE_VOICE_COMMUNICATION:
        // Allow only use of devices on primary input if in call and HAL does not support routing
        // to voice call path.
        if ((mPhoneState == AUDIO_MODE_IN_CALL) &&
                (mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_TELEPHONY_TX) == 0) {
            availableDeviceTypes = availablePrimaryInputDevices() & ~AUDIO_DEVICE_BIT_IN;
        }

        switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
        case AUDIO_POLICY_FORCE_BT_SCO:
            // if SCO device is requested but no SCO device is available, fall back to default case
            if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
                device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
                break;
            }
            // FALL THROUGH

        default:    // FORCE_NONE
            if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                device = AUDIO_DEVICE_IN_WIRED_HEADSET;
            } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
                device = AUDIO_DEVICE_IN_USB_DEVICE;
            } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
                device = AUDIO_DEVICE_IN_BUILTIN_MIC;
            }
            break;

        case AUDIO_POLICY_FORCE_SPEAKER:
            if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
                device = AUDIO_DEVICE_IN_BACK_MIC;
            } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
                device = AUDIO_DEVICE_IN_BUILTIN_MIC;
            }
            break;
        }
        break;

    case AUDIO_SOURCE_VOICE_RECOGNITION:
    case AUDIO_SOURCE_HOTWORD:
        if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO &&
                availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
            device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
            device = AUDIO_DEVICE_IN_USB_DEVICE;
        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
        }
        break;
    case AUDIO_SOURCE_CAMCORDER:
        if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
            device = AUDIO_DEVICE_IN_BACK_MIC;
        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
        }
        break;
    case AUDIO_SOURCE_VOICE_DOWNLINK:
    case AUDIO_SOURCE_VOICE_CALL:
        if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
            device = AUDIO_DEVICE_IN_VOICE_CALL;
        }
        break;
    case AUDIO_SOURCE_REMOTE_SUBMIX:
        if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
            device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
        }
        break;
     case AUDIO_SOURCE_FM_TUNER:
        if (availableDeviceTypes & AUDIO_DEVICE_IN_FM_TUNER) {
            device = AUDIO_DEVICE_IN_FM_TUNER;
        }
        break;
    default:
        ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
        break;
    }
    ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
    return device;
}

   這里就是通過InputSource去獲取相應的policyMix與audio_device_t設備類型了,從這里也可以看出Android系統上對Audio設備的分類有多少種了。

然后再看下AudioPolicyManager.cpp::getInputForAttr()的第6步.mpClientInterface->openInput如何建立起輸入流

frameworks\av\services\audiopolicy\AudioPolicyClientImpl.cpp

status_t AudioPolicyService::AudioPolicyClient::openInput(audio_module_handle_t module,
                                                          audio_io_handle_t *input,
                                                          audio_config_t *config,
                                                          audio_devices_t *device,
                                                          const String8& address,
                                                          audio_source_t source,
                                                          audio_input_flags_t flags)
{
    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
    if (af == 0) {
        ALOGW("%s: could not get AudioFlinger", __func__);
        return PERMISSION_DENIED;
    }

    return af->openInput(module, input, config, device, address, source, flags);
}

這里就調用到了AF端的openInput函數了

frameworks\av\services\audioflinger\AudioFlinger.cpp

status_t AudioFlinger::openInput(audio_module_handle_t module,
                                          audio_io_handle_t *input,
                                          audio_config_t *config,
                                          audio_devices_t *device,
                                          const String8& address,
                                          audio_source_t source,
                                          audio_input_flags_t flags)
{
    Mutex::Autolock _l(mLock);

    if (*device == AUDIO_DEVICE_NONE) {
        return BAD_VALUE;
    }

    sp<RecordThread> thread = openInput_l(module, input, config, *device, address, source, flags);

    if (thread != 0) {
        // notify client processes of the new input creation
        thread->audioConfigChanged(AudioSystem::INPUT_OPENED);
        return NO_ERROR;
    }
    return NO_INIT;
}

sp<AudioFlinger::RecordThread> AudioFlinger::openInput_l(audio_module_handle_t module,
                                                         audio_io_handle_t *input,
                                                         audio_config_t *config,
                                                         audio_devices_t device,
                                                         const String8& address,
                                                         audio_source_t source,
                                                         audio_input_flags_t flags)
{
    AudioHwDevice *inHwDev = findSuitableHwDev_l(module, device);
    if (inHwDev == NULL) {
        *input = AUDIO_IO_HANDLE_NONE;
        return 0;
    }

    if (*input == AUDIO_IO_HANDLE_NONE) {
        *input = nextUniqueId();
    }

    audio_config_t halconfig = *config;
    audio_hw_device_t *inHwHal = inHwDev->hwDevice();
    audio_stream_in_t *inStream = NULL;
    //獲取inStream對象
    status_t status = inHwHal->open_input_stream(inHwHal, *input, device, &halconfig,
                                        &inStream, flags, address.string(), source);

    // If the input could not be opened with the requested parameters and we can handle the
    // conversion internally, try to open again with the proposed parameters. The AudioFlinger can
    // resample the input and do mono to stereo or stereo to mono conversions on 16 bit PCM inputs.
    if (status == BAD_VALUE &&
            config->format == halconfig.format && halconfig.format == AUDIO_FORMAT_PCM_16_BIT &&
        (halconfig.sample_rate <= 2 * config->sample_rate) &&
        (audio_channel_count_from_in_mask(halconfig.channel_mask) <= FCC_2) &&
        (audio_channel_count_from_in_mask(config->channel_mask) <= FCC_2)) {
        // FIXME describe the change proposed by HAL (save old values so we can log them here)
        ALOGV("openInput_l() reopening with proposed sampling rate and channel mask");
        inStream = NULL;
        status = inHwHal->open_input_stream(inHwHal, *input, device, &halconfig,
                                            &inStream, flags, address.string(), source);
        // FIXME log this new status; HAL should not propose any further changes
    }

    if (status == NO_ERROR && inStream != NULL) {

#ifdef TEE_SINK 
        // Try to re-use most recently used Pipe to archive a copy of input for dumpsys,
        // or (re-)create if current Pipe is idle and does not match the new format
        sp<NBAIO_Sink> teeSink;
        enum {
            TEE_SINK_NO,    // don't copy input
            TEE_SINK_NEW,   // copy input using a new pipe
            TEE_SINK_OLD,   // copy input using an existing pipe
        } kind;
        NBAIO_Format format = Format_from_SR_C(halconfig.sample_rate,
                audio_channel_count_from_in_mask(halconfig.channel_mask), halconfig.format);
        if (!mTeeSinkInputEnabled) {
            kind = TEE_SINK_NO;
        } else if (!Format_isValid(format)) {
            kind = TEE_SINK_NO;
        } else if (mRecordTeeSink == 0) {
            kind = TEE_SINK_NEW;
        } else if (mRecordTeeSink->getStrongCount() != 1) {
            kind = TEE_SINK_NO;
        } else if (Format_isEqual(format, mRecordTeeSink->format())) {
            kind = TEE_SINK_OLD;
        } else {
            kind = TEE_SINK_NEW;
        }
        switch (kind) {
        case TEE_SINK_NEW: {
            Pipe *pipe = new Pipe(mTeeSinkInputFrames, format);
            size_t numCounterOffers = 0;
            const NBAIO_Format offers[1] = {format};
            ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
            ALOG_ASSERT(index == 0);
            PipeReader *pipeReader = new PipeReader(*pipe);
            numCounterOffers = 0;
            index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
            ALOG_ASSERT(index == 0);
            mRecordTeeSink = pipe;
            mRecordTeeSource = pipeReader;
            teeSink = pipe;
            }
            break;
        case TEE_SINK_OLD:
            teeSink = mRecordTeeSink;
            break;
        case TEE_SINK_NO:
        default:
            break;
        }
#endif
        AudioStreamIn *inputStream = new AudioStreamIn(inHwDev, inStream);
        // Start record thread
        // RecordThread requires both input and output device indication to forward to audio
        // pre processing modules
        sp<RecordThread> thread = new RecordThread(this,
                                  inputStream,
                                  *input,
                                  primaryOutputDevice_l(),
                                  device
#ifdef TEE_SINK
                                  , teeSink
#endif
                                  );
        mRecordThreads.add(*input, thread);
        ALOGV("openInput_l() created record thread: ID %d thread %p", *input, thread.get());
        return thread;
    }

    *input = AUDIO_IO_HANDLE_NONE;
    return 0;
}

在這個函數中主要工作如下:

    1.findSuitableHwDev_l中通過IOProfile中的module.handle與audio_device_t設備類型找到Hw模塊;

    2.調用HAL層inHwHal->open_input_stream打開輸入流;

    3.如果失敗了,再繼續調用一次;

    4.根據inHwDev與inStream創建AudioStreamIn對象,如此,就建立起了一個輸入流了,AudioStreamIn定義在frameworks\av\services\audioflinger\AudioFlinger.h;

    5.創建一個RecordThread線程,並把該線程加入到mRecordThreads線程中,這個線程是在AudioRecord.cpp::set()函數中創建的;

這里我們着重分析第2、5步:

首先看下AudioFlinger.cpp::openInput()的第2步:打開輸入流

hardware\aw\audio\tulip\audio_hw.c

static int adev_open_input_stream(struct audio_hw_device *dev,
                                  audio_io_handle_t handle,
                                  audio_devices_t devices,
                                  struct audio_config *config,
                                  struct audio_stream_in **stream_in)
{
    struct sunxi_audio_device *ladev = (struct sunxi_audio_device *)dev;
    struct sunxi_stream_in *in;
    int ret;
    int channel_count = popcount(config->channel_mask);

    *stream_in = NULL;

    if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
        return -EINVAL;

    in = (struct sunxi_stream_in *)calloc(1, sizeof(struct sunxi_stream_in));
    if (!in)
        return -ENOMEM;

    in->stream.common.get_sample_rate 	= in_get_sample_rate;
    in->stream.common.set_sample_rate 	= in_set_sample_rate;
    in->stream.common.get_buffer_size 	= in_get_buffer_size;
    in->stream.common.get_channels 		= in_get_channels;
    in->stream.common.get_format 		= in_get_format;
    in->stream.common.set_format 		= in_set_format;
    in->stream.common.standby 			= in_standby;
    in->stream.common.dump 				= in_dump;
    in->stream.common.set_parameters 	= in_set_parameters;
    in->stream.common.get_parameters 	= in_get_parameters;
    in->stream.common.add_audio_effect 	= in_add_audio_effect;
    in->stream.common.remove_audio_effect = in_remove_audio_effect;
    in->stream.set_gain = in_set_gain;
    in->stream.read 	= in_read;
    in->stream.get_input_frames_lost = in_get_input_frames_lost;

    in->requested_rate 	= config->sample_rate;

    // default config
    memcpy(&in->config, &pcm_config_mm_in, sizeof(pcm_config_mm_in));
    in->config.channels = channel_count;
    //in->config.in_init_channels = channel_count;

    in->buffer = malloc(in->config.period_size *
                        audio_stream_frame_size(&in->stream.common) * 8);

    if (!in->buffer) {
        ret = -ENOMEM;
        goto err;
    }
    memset(in->buffer, 0, in->config.period_size *
                audio_stream_frame_size(&in->stream.common) * 8); //mute

    ladev->af_capture_flag = false;
    //devices = AUDIO_DEVICE_IN_WIFI_DISPLAY;//for test

    if (devices == AUDIO_DEVICE_IN_AF) {
		ALOGV("to malloc PcmManagerBuffer: Buffer_size: %d", AF_BUFFER_SIZE);
		ladev->PcmManager.BufStart= (unsigned char *)malloc(AF_BUFFER_SIZE);

		if(!ladev->PcmManager.BufStart) {
			ret = -ENOMEM;
			goto err;
   		}

		ladev->PcmManager.BufExist 		= true;
		ladev->PcmManager.BufTotalLen 	= AF_BUFFER_SIZE;
		ladev->PcmManager.BufWritPtr 	= ladev->PcmManager.BufStart;
		ladev->PcmManager.BufReadPtr 	= ladev->PcmManager.BufStart;
		ladev->PcmManager.BufValideLen	= ladev->PcmManager.BufTotalLen;
		ladev->PcmManager.DataLen 		= 0;
		ladev->PcmManager.SampleRate 	= config->sample_rate;
		ladev->PcmManager.Channel 		= 2;
		ladev->af_capture_flag 			= true;

		ladev->PcmManager.dev 			= (struct sunxi_audio_device *)ladev;
    }

    in->dev 	= ladev;
    in->standby = 1;
    in->device 	= devices & ~AUDIO_DEVICE_BIT_IN;

    *stream_in 	= &in->stream;
    return 0;

err:
    if (in->resampler)
        release_resampler(in->resampler);

    free(in);
    return ret;
}

在這個函數中主要工作如下:

    1.檢查rate,format,channel參數是否支持;

    2.給sunxi_stream_in輸入流對象分配內存空間;

    3.綁定相應參數的獲取/設置方法;

    4.為輸入流創建buff空間:in->config.period_size *audio_stream_frame_size(&in->stream.common) * 8;

    5.如果是AUDIO_DEVICE_IN_AF類型的設備的話,則對PcmManager做相應處理;

這個輸入流對象會綁定到AF中的AudioStreamIn對象中,所以到這里,輸入流對象就已經完全創建好了。

然后繼續分析AudioFlinger.cpp::openInput()的第5步:創建RecordThread線程:

frameworks\av\services\audioflinger\Threads.cpp

AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
                                         AudioStreamIn *input,
                                         audio_io_handle_t id,
                                         audio_devices_t outDevice,
                                         audio_devices_t inDevice
#ifdef TEE_SINK
                                         , const sp<NBAIO_Sink>& teeSink
#endif
                                         ) :
    ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD),
    mInput(input), mActiveTracksGen(0), mRsmpInBuffer(NULL),
    // mRsmpInFrames and mRsmpInFramesP2 are set by readInputParameters_l()
    mRsmpInRear(0)
#ifdef TEE_SINK
    , mTeeSink(teeSink)
#endif
    , mReadOnlyHeap(new MemoryDealer(kRecordThreadReadOnlyHeapSize,
            "RecordThreadRO", MemoryHeapBase::READ_ONLY))
    // mFastCapture below
    , mFastCaptureFutex(0)
    // mInputSource
    // mPipeSink
    // mPipeSource
    , mPipeFramesP2(0)
    // mPipeMemory
    // mFastCaptureNBLogWriter
    , mFastTrackAvail(false)
{
    snprintf(mName, kNameLength, "AudioIn_%X", id);
    mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName);

    readInputParameters_l();
    // create an NBAIO source for the HAL input stream, and negotiate
    mInputSource = new AudioStreamInSource(input->stream);
    size_t numCounterOffers = 0;
    const NBAIO_Format offers[1] = {Format_from_SR_C(mSampleRate, mChannelCount, mFormat)};
    ssize_t index = mInputSource->negotiate(offers, 1, NULL, numCounterOffers);
    ALOG_ASSERT(index == 0);

    // initialize fast capture depending on configuration
    bool initFastCapture;
    switch (kUseFastCapture) {
    case FastCapture_Never:
        initFastCapture = false;
        break;
    case FastCapture_Always:
        initFastCapture = true;
        break;
    case FastCapture_Static:
        uint32_t primaryOutputSampleRate;
        {
            AutoMutex _l(audioFlinger->mHardwareLock);
            primaryOutputSampleRate = audioFlinger->mPrimaryOutputSampleRate;
        }
        initFastCapture =
                // either capture sample rate is same as (a reasonable) primary output sample rate
                (((primaryOutputSampleRate == 44100 || primaryOutputSampleRate == 48000) &&
                    (mSampleRate == primaryOutputSampleRate)) ||
                // or primary output sample rate is unknown, and capture sample rate is reasonable
                ((primaryOutputSampleRate == 0) &&
                    ((mSampleRate == 44100 || mSampleRate == 48000)))) &&
                // and the buffer size is < 12 ms
                (mFrameCount * 1000) / mSampleRate < 12;
        break;
    // case FastCapture_Dynamic:
    }

    if (initFastCapture) {
        // create a Pipe for FastMixer to write to, and for us and fast tracks to read from
        NBAIO_Format format = mInputSource->format();
        size_t pipeFramesP2 = roundup(mSampleRate / 25);    // double-buffering of 20 ms each
        size_t pipeSize = pipeFramesP2 * Format_frameSize(format);
        void *pipeBuffer;
        const sp<MemoryDealer> roHeap(readOnlyHeap());
        sp<IMemory> pipeMemory;
        if ((roHeap == 0) ||
                (pipeMemory = roHeap->allocate(pipeSize)) == 0 ||
                (pipeBuffer = pipeMemory->pointer()) == NULL) {
            ALOGE("not enough memory for pipe buffer size=%zu", pipeSize);
            goto failed;
        }
        // pipe will be shared directly with fast clients, so clear to avoid leaking old information
        memset(pipeBuffer, 0, pipeSize);
        Pipe *pipe = new Pipe(pipeFramesP2, format, pipeBuffer);
        const NBAIO_Format offers[1] = {format};
        size_t numCounterOffers = 0;
        ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
        ALOG_ASSERT(index == 0);
        mPipeSink = pipe;
        PipeReader *pipeReader = new PipeReader(*pipe);
        numCounterOffers = 0;
        index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
        ALOG_ASSERT(index == 0);
        mPipeSource = pipeReader;
        mPipeFramesP2 = pipeFramesP2;
        mPipeMemory = pipeMemory;

        // create fast capture
        mFastCapture = new FastCapture();
        FastCaptureStateQueue *sq = mFastCapture->sq();
#ifdef STATE_QUEUE_DUMP
        // FIXME
#endif
        FastCaptureState *state = sq->begin();
        state->mCblk = NULL;
        state->mInputSource = mInputSource.get();
        state->mInputSourceGen++;
        state->mPipeSink = pipe;
        state->mPipeSinkGen++;
        state->mFrameCount = mFrameCount;
        state->mCommand = FastCaptureState::COLD_IDLE;
        // already done in constructor initialization list
        //mFastCaptureFutex = 0;
        state->mColdFutexAddr = &mFastCaptureFutex;
        state->mColdGen++;
        state->mDumpState = &mFastCaptureDumpState;
#ifdef TEE_SINK
        // FIXME
#endif
        mFastCaptureNBLogWriter = audioFlinger->newWriter_l(kFastCaptureLogSize, "FastCapture");
        state->mNBLogWriter = mFastCaptureNBLogWriter.get();
        sq->end();
        sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);

        // start the fast capture
        mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO);
        pid_t tid = mFastCapture->getTid();
        int err = requestPriority(getpid_cached, tid, kPriorityFastMixer);
        if (err != 0) {
            ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
                    kPriorityFastCapture, getpid_cached, tid, err);
        }

#ifdef AUDIO_WATCHDOG
        // FIXME
#endif

        mFastTrackAvail = true;
    }
failed: ;

    // FIXME mNormalSource
}

在這個線程中主要工作如下:

    1.調用readInputParameters_l函數把錄音參數讀取到線程空間中;

    2.創建AudioStreamInSource對象,作為線程中間中的輸入流,其實現是在frameworks\av\media\libnbaio\AudioStreamInSource.cpp;

所以可以猜到,后續在啟動錄音時,RecordThread中將會通過AudioStreamInSource對象進行獲取數據,實時更新共享內存中的數據。

再回到AudioRecord.cpp::openRecord_l(0)的第4步.創建IAudioRecord對象

sp<IAudioRecord> AudioFlinger::openRecord(
        audio_io_handle_t input,
        uint32_t sampleRate,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        size_t *frameCount,
        IAudioFlinger::track_flags_t *flags,
        pid_t tid,
        int *sessionId,
        size_t *notificationFrames,
        sp<IMemory>& cblk,
        sp<IMemory>& buffers,
        status_t *status)
{
    sp<RecordThread::RecordTrack> recordTrack;
    sp<RecordHandle> recordHandle;
    sp<Client> client;
    status_t lStatus;
    int lSessionId;

    cblk.clear();	
    buffers.clear();

    // check calling permissions
    if (!recordingAllowed()) {
        ALOGE("openRecord() permission denied: recording not allowed");
        lStatus = PERMISSION_DENIED;
        goto Exit;
    }

    // further sample rate checks are performed by createRecordTrack_l()
    if (sampleRate == 0) {
        ALOGE("openRecord() invalid sample rate %u", sampleRate);
        lStatus = BAD_VALUE;
        goto Exit;
    }

    // we don't yet support anything other than 16-bit PCM
    if (!(audio_is_valid_format(format) &&
            audio_is_linear_pcm(format) && format == AUDIO_FORMAT_PCM_16_BIT)) {
        ALOGE("openRecord() invalid format %#x", format);
        lStatus = BAD_VALUE;
        goto Exit;
    }

    // further channel mask checks are performed by createRecordTrack_l()
    if (!audio_is_input_channel(channelMask)) {
        ALOGE("openRecord() invalid channel mask %#x", channelMask);
        lStatus = BAD_VALUE;
        goto Exit;
    }

    {
        Mutex::Autolock _l(mLock);
        RecordThread *thread = checkRecordThread_l(input);
        if (thread == NULL) {
            ALOGE("openRecord() checkRecordThread_l failed");
            lStatus = BAD_VALUE;
            goto Exit;
        }

        pid_t pid = IPCThreadState::self()->getCallingPid();
        client = registerPid(pid);

        if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) {
            lSessionId = *sessionId;
        } else {
            // if no audio session id is provided, create one here
            lSessionId = nextUniqueId();
            if (sessionId != NULL) {
                *sessionId = lSessionId;
            }
        }

        // TODO: the uid should be passed in as a parameter to openRecord
        recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
                                                  frameCount, lSessionId, notificationFrames,
                                                  IPCThreadState::self()->getCallingUid(),
                                                  flags, tid, &lStatus);
        LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));

        if (lStatus == NO_ERROR) {
            // 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((audio_session_t)lSessionId);
            if (chain != 0) {
                Mutex::Autolock _l(thread->mLock);
                thread->addEffectChain_l(chain);
            }
        }
    }

    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();
        goto Exit;
    }

    cblk = recordTrack->getCblk();
    buffers = recordTrack->getBuffers();

    // return handle to client
    recordHandle = new RecordHandle(recordTrack);

Exit:
    *status = lStatus;
    return recordHandle;
}

在這個函數中主要工作如下:

    1.調用recordingAllowed檢查錄音權限;

    2.判斷參數是否非法;

    3.調用checkRecordThread_l函數,根據input從AudioRecordThread線程中獲取該input的RecordThread,在前面的分析中可以得知,這個RecordThread是在AudioFlinger.cpp::openInput函數中創建並添加到AudioRecordThread中的;

    4.調用createRecordTrack_l方法創建一個RecordTrack對象,RecordThread::RecordTrack對象的作用是管理RecordThread中的音頻數據;

    5.通過SessionId獲取是否存在effect chain,若有,則加到RecordThread中;

    6.通過RecordTrack獲取cblk以及buffers,他們就是CblkMemory以及BufferMemory;

    7.根據recordTrack,創建RecordHandle對象,實現位置:frameworks\av\services\audioflinger\Tracks.cpp,也就完成了IAudioRecord對象的創建了,也就是說IAudioRecord的方法是在Tracks.cpp中實現的;

這里再看下第2步:createRecordTrack_l函數

sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l(
        const sp<AudioFlinger::Client>& client,
        uint32_t sampleRate,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        size_t *pFrameCount,
        int sessionId,
        size_t *notificationFrames,
        int uid,
        IAudioFlinger::track_flags_t *flags,
        pid_t tid,
        status_t *status)
{
    size_t frameCount = *pFrameCount;
    sp<RecordTrack> track;
    status_t lStatus;

    // client expresses a preference for FAST, but we get the final say
    if (*flags & IAudioFlinger::TRACK_FAST) {
      if (
            // use case: callback handler
            (tid != -1) &&
            // frame count is not specified, or is exactly the pipe depth
            ((frameCount == 0) || (frameCount == mPipeFramesP2)) &&
            // PCM data
            audio_is_linear_pcm(format) &&
            // native format
            (format == mFormat) &&
            // native channel mask
            (channelMask == mChannelMask) &&
            // native hardware sample rate
            (sampleRate == mSampleRate) &&
            // record thread has an associated fast capture
            hasFastCapture() &&
            // there are sufficient fast track slots available
            mFastTrackAvail
        ) {
        ALOGV("AUDIO_INPUT_FLAG_FAST accepted: frameCount=%u mFrameCount=%u",
                frameCount, mFrameCount);
      } else {
        ALOGV("AUDIO_INPUT_FLAG_FAST denied: frameCount=%u mFrameCount=%u mPipeFramesP2=%u "
                "format=%#x isLinear=%d channelMask=%#x sampleRate=%u mSampleRate=%u "
                "hasFastCapture=%d tid=%d mFastTrackAvail=%d",
                frameCount, mFrameCount, mPipeFramesP2,
                format, audio_is_linear_pcm(format), channelMask, sampleRate, mSampleRate,
                hasFastCapture(), tid, mFastTrackAvail);
        *flags &= ~IAudioFlinger::TRACK_FAST;
      }
    }

    // compute track buffer size in frames, and suggest the notification frame count
    if (*flags & IAudioFlinger::TRACK_FAST) {
        // fast track: frame count is exactly the pipe depth
        frameCount = mPipeFramesP2;
        // ignore requested notificationFrames, and always notify exactly once every HAL buffer
        *notificationFrames = 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 (*notificationFrames == 0 || *notificationFrames > maxNotificationFrames) {
            *notificationFrames = maxNotificationFrames;
        }
    }
    *pFrameCount = frameCount;

    lStatus = initCheck();
    if (lStatus != NO_ERROR) {
        ALOGE("createRecordTrack_l() audio driver not initialized");
        goto Exit;
    }

    { // scope for mLock
        Mutex::Autolock _l(mLock);

        track = new RecordTrack(this, client, sampleRate,
                      format, channelMask, frameCount, NULL, sessionId, uid,
                      *flags, TrackBase::TYPE_DEFAULT);

        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);

        // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
        bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
                        mAudioFlinger->btNrecIsOff();
        setEffectSuspended_l(FX_IID_AEC, suspend, sessionId);
        setEffectSuspended_l(FX_IID_NS, suspend, sessionId);

        if ((*flags & IAudioFlinger::TRACK_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);
        }
    }

    lStatus = NO_ERROR;

Exit:
    *status = lStatus;
    return track;
}

這個函數重要的一點就是重新計算了frameCount大小,然后根據新的參數創建了RecordTrack對象,然后return。

 

總結:

    當應用層new AudioRecord時,系統建立起了輸入流,並創建了RecordThread線程,現在錄音的准備工作已經完成,就等待應用層開啟錄音了。

 

由於作者內功有限,若文章中存在錯誤或不足的地方,還請給位大佬指出,不勝感激!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM