Android开发

android 6.0 AudioRecord 录音流程分析(一

2019-01-26  本文已影响0人  来吗这里有位置

先看一段android 应用调用java代码的例子

public class MicRecord extends Thread{
    AudioRecord audioRecord;
    AudioTrack audioTrack;
    volatile boolean canPlay = true;//个人推荐用带原子操作的对象AtomicBoolean代替

    @Override
    public void run() {
        final int recordbuffsize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_DEFAULT,
                AudioFormat.ENCODING_PCM_16BIT);
        audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100,
                AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, recordbuffsize);
        final int playBuffsize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO,
                AudioFormat.ENCODING_PCM_16BIT);
        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO,
                AudioFormat.ENCODING_PCM_16BIT, playBuffsize, AudioTrack.MODE_STREAM);

        audioRecord.startRecording();
        audioTrack.play();
        byte[] recordData = new byte[recordbuffsize];
        while(canPlay){
            int readSize = audioRecord.read(recordData, 0, recordbuffsize);
            audioTrack.write(recordData, 0, readSize);
        }
        audioRecord.stop();
        audioRecord.release();
        audioTrack.stop();
        audioTrack.release();
    }

    public void stopRecord(){
        canPlay = false;
    }
}

下面是个人空闲之余整理的简述AudioRecord 的初始化流程和跨进程和mediaserver 的audioFlinger,audioPolicy爱恨情仇。和startRecording开始录音的流程。如果不是底层系统工程师做HAL对接输入设备驱动的话,流程是大概懂了但是实际功能上是用不上改动这部分代码的。HAL的用法法则也稍懂些但可惜已经不在linux os岗位,故无需详细了解。熟悉底层原理对做出好应用是也是很有必要的。


AudioRecord流程图

AudioRecord初始化

说到AudioRecord.java 这个类就不得不提和它相应的注册native方法,在/base/core/jni/android_media_AudioRecord.cpp 文件中,具体这些native方法是什么时候load的呢?
int register_android_media_AudioRecord(JNIEnv *env)
这个要看由应用启动时zygote创建的AndroidRuntime由
int AndroidRuntime::startReg(JNIEnv * env) 接口注册了。jni注册数组固定在AndroidRuntime.cpp 里面的

static const RegJNIRec gRegJNI[] = {
....
    REG_JNI(register_android_media_AudioRecord),
    REG_JNI(register_android_media_AudioSystem),
    REG_JNI(register_android_media_AudioTrack),
....
};

所以在java类调用涉及到对象native 方法的都不需要重新加载so等。
AudioRecord对象的创建需要参数 音频audioSource,采集频率sampleRateInHz,通道模式channelConfig,音频格式audioFormat,采集数据保存区大小bufferSizeInBytes。
AudioRecord构造时对参数进行检查和进行native_setup

int initResult = native_setup( new WeakReference<AudioRecord>(this),
                mAudioAttributes, mSampleRate, mChannelMask, mChannelIndexMask,
                mAudioFormat, mNativeBufferSizeInBytes,
                session, ActivityThread.currentOpPackageName());

跳到android_media_AudioRecord.cpp去

static jint
android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
        jobject jaa, jint sampleRateInHertz, jint channelMask, jint channelIndexMask,
        jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName)
{
   ......
    // create an uninitialized AudioRecord object
    sp<AudioRecord> lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
  ......
    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,
        -1, -1,        // default uid, pid
        paa);
   ......
    // 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;
} 

static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioRecord>& ar)
{
    Mutex::Autolock l(sLock);
    sp<AudioRecord> old =
            (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
    if (ar.get()) {
        ar->incStrong((void*)setAudioRecord);
    }
    if (old != 0) {
        old->decStrong((void*)setAudioRecord);
    }
    env->SetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (jlong)ar.get());
    return old;
}

AudioRecord的native_setup初始化只截留重要部分分析,sp<AudioRecord> lpRecorder 是jni层的/av/media/libmedia/AudioRecord.cpp AudioRecord对象,创建后用一波反手骚操作,把这个对象的引用指针赋值给java AudioRecord的(long)mNativeRecorderInJavaObj 来保存,后面如果要用到lpRecorder则会直接获取该long型引用数据强转回jni的AudioRecord引用, jni使用的常用招式。

static sp<AudioRecord> getAudioRecord(JNIEnv* env, jobject thiz)
{
    Mutex::Autolock l(sLock);
    AudioRecord* const ar =
            (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
    return sp<AudioRecord>(ar);
}

lpRecorder->set(xx[])初始化则是整个录音流程重点,它会通过audioFlinger来获取audio_io_handle_t 输入输出handle,打开HAL的设备获取audio_stream_in_t 输入流,并且打开创建录音线程RecordThread等等。下面描述

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,
        int uid,
        pid_t pid,
        const audio_attributes_t* pAttributes)
{
    ......
    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

/**
和audioflinger绑定的会话id
**/
    if (sessionId == AUDIO_SESSION_ALLOCATE) {
        mSessionId = AudioSystem::newAudioUniqueId();
    } else {
        mSessionId = sessionId;
    }
    ALOGV("set(): mSessionId %d", mSessionId);

    int callingpid = IPCThreadState::self()->getCallingPid();
    int mypid = getpid();
    if (uid == -1 || (callingpid != mypid)) {
        mClientUid = IPCThreadState::self()->getCallingUid();
    } else {
        mClientUid = uid;
    }
    if (pid == -1 || (callingpid != mypid)) {
        mClientPid = callingpid;
    } else {
        mClientPid = pid;
    }

    mFlags = flags;
    mCbf = cbf;

    if (cbf != NULL) {
        mAudioRecordThread = new AudioRecordThread(*this, threadCanCallJava);
        mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
        // thread begins in paused state, and will not reference us until start()
    }

    // create the IAudioRecord
    status_t status = openRecord_l(0 /*epoch*/, mOpPackageName);
......
    AudioSystem::acquireAudioSessionId(mSessionId, -1);
  ......
    return NO_ERROR;
}

会话id mSessionId 默认是采用分配方式AUDIO_SESSION_ALLOCATE,再通过audioFlinger->newAudioUniqueId创建当前对象独一无二的id,然后audioFlinger->acquireAudioSessionId(int audioSession, pid_t pid) 会判断是否重复申请和用vector存放持有这俩个参数的对象AudioSessionRef。
只关注 status_t status = openRecord_l(0 /epoch/, mOpPackageName);

status_t AudioRecord::openRecord_l(size_t epoch, const String16& opPackageName)
{
    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
  /*IAudioFlinger实际获取的是跑在mediaServer里面的binder服务"media.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) && !((
            // either of these use cases:
            // use case 1: callback transfer mode
            (mTransfer == TRANSFER_CALLBACK) ||
            // use case 2: obtain/release mode
            (mTransfer == TRANSFER_OBTAIN)) &&
            // matching sample rate
            (mSampleRate == afSampleRate))) {
        ALOGW("AUDIO_INPUT_FLAG_FAST denied by client; transfer %d, track %u Hz, primary %u Hz",
                mTransfer, mSampleRate, afSampleRate);
        // 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();
        }
    }

    if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
    }

/*
在这里会先通过"media.audio_policy"  服务获取,
在/av/media/services/Audiopolicy/service/AudioPolicyInterfaceImpl.cpp 
的AudioPolicyService实现类,然后成员mAudioPolicyManager 
/av/media/services/Audiopolicy/managerdefault/AudioPolicyManager.cpp 根据参数
获取输入audio_io_handle_t 和设备的选取,再通过AudioFlinger 的openInput打开,
到最后真正实现录音线程RecordThread和AudioStreamIn。
*/
    audio_io_handle_t input;
    status_t status = AudioSystem::getInputForAttr(&mAttributes, &input,
                                        (audio_session_t)mSessionId,
                                        IPCThreadState::self()->getCallingUid(),
                                        mSampleRate, mFormat, mChannelMask,
                                        mFlags, mSelectedDeviceId);

    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;


/*IMemory 在里面起到共享内存作用,后期的音频数据有可以通过共享内存来get到。iMem的创建
初始化在AudioFlinger,同时会创建audio_track_cblk_t对象引用指针赋给iMem的iMem->pointer()。
audio_track_cblk_t作用下面细说,audioFlinger->openRecord最终返回的IAudioRecord
是控制整个录音流程的关键对象,比如开始录音,结束录音等等。
*/
    sp<IMemory> iMem;           // for cblk
    sp<IMemory> bufferMem;
    sp<IAudioRecord> record = audioFlinger->openRecord(input,
                                                       mSampleRate,
                                                       mFormat,
                                                       mChannelMask,
                                                       opPackageName,
                                                       &temp,
                                                       &trackFlags,
                                                       tid,
                                                       mClientUid,
                                                       &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) {
        IInterface::asBinder(mAudioRecord)->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 AudioRecord client代理,看到cblk这个参数就明白它是代理了一些音
频数据获取相关的功能。比如obtainBuffer,从cblk成员指针进行内存共享获取录音数据。*/
    mProxy = new AudioRecordClientProxy(cblk, buffers, mFrameCount, mFrameSize);
    mProxy->setEpoch(epoch);
    mProxy->setMinimum(mNotificationFramesAct);

    mDeathNotifier = new DeathNotifier(this);
/**
由于mAudioRecord是通过AudioFlinger获得的binder接口对象,所以还是要注册
死亡监听和通知释放资源
*/
    IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);

    if (mDeviceCallback != 0) {
        AudioSystem::addAudioDeviceCallback(mDeviceCallback, mInput);
    }

    return NO_ERROR;
    }

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

AudioSystem::getInputForAttr这个接口填充一些flags参数,采样率,格式,通道和会话ID mSessionId, 进程uid等,接下的流程是到/av/media/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp的 "media.audio_policy"服务,audioPolicy->getInputForAttr 进行一些参数audio_attributes_t,uid的检验, 和还会对申请到的inputType 选择的类型进行"android.permission.MODIFY_AUDIO_ROUTING" 或"android.permission.CAPTURE_AUDIO_OUTPUT"权限检测。
l跑在android环境的linux应用要检测app应用权限的原理方式也很简单,利用"permission"这个跑在systemServer的binder服务跨进程检查App应用所带的权限,参数pid,uid,和权限字符串。
"permission"是在ActivityManagerService.java 里面注册进Servicemanager里的,实现类是

static class PermissionController extends IPermissionController.Stub{}

在这里class PermissionController实现的是相当于Bn端,而Bp端是实现定义在/framework/native/libs/binder/IPermissonController.cpp

status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
                                             audio_io_handle_t *input,
                                             audio_session_t session,
                                             uid_t uid,
                                             uint32_t samplingRate,
                                             audio_format_t format,
                                             audio_channel_mask_t channelMask,
                                             audio_input_flags_t flags,
                                             audio_port_handle_t selectedDeviceId)
{
    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()) {
        return BAD_VALUE;
    }
    sp<AudioPolicyEffects>audioPolicyEffects;
    status_t status;
    AudioPolicyInterface::input_type_t inputType;
    // if the caller is us, trust the specified uid
    if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) {
        uid_t newclientUid = IPCThreadState::self()->getCallingUid();
        if (uid != (uid_t)-1 && uid != newclientUid) {
            ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid);
        }
        uid = newclientUid;
    }

    {
        Mutex::Autolock _l(mLock);
        // the audio_in_acoustics_t parameter is ignored by get_input()
/**
默认的AudioPolicyManager实现在/av/services/audioPolicy/managerdefault/AudioPolicyManager.cpp
*/
        status = mAudioPolicyManager->getInputForAttr(attr, input, session, uid,
                                                     samplingRate, format, channelMask,
                                                     flags, selectedDeviceId,
                                                     &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_TELEPHONY_RX:
                // FIXME: use the same permission as for remote submix for now.
            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;
}

mAudioPolicyManager->getInputForAttr 这里进行策略性获得audio_devices_t 这个东西实则是uint32所以就可以说成是输入设备id。获取完该需要的device和audio_config_t配置和功能性flags参数,就又绕回到AudioFlinger去openInput该设备了。

status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
                                             audio_io_handle_t *input,
                                             audio_session_t session,
                                             uid_t uid,
                                             uint32_t samplingRate,
                                             audio_format_t format,
                                             audio_channel_mask_t channelMask,
                                             audio_input_flags_t flags,
                                             audio_port_handle_t selectedDeviceId,
                                             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;

    // Explicit routing?
    sp<DeviceDescriptor> deviceDesc;
    for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
        if (mAvailableInputDevices[i]->getId() == selectedDeviceId) {
            deviceDesc = mAvailableInputDevices[i];
            break;
        }
    }
    mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid);

    if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
            strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
        status_t ret = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
        if (ret != NO_ERROR) {
            return ret;
        }
        *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
        device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
        address = String8(attr->tags + strlen("addr="));
    } 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 if (device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
            *inputType = API_INPUT_TELEPHONY_RX;
        } 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;
            }
        }
    }

    // find a compatible input profile (not necessarily identical in parameters)
    sp<IOProfile> profile;
    // samplingRate and flags may be updated by getInputProfile
    uint32_t profileSamplingRate = samplingRate;
    audio_format_t profileFormat = format;
    audio_channel_mask_t profileChannelMask = channelMask;
    audio_input_flags_t profileFlags = flags;
    for (;;) {
/**
对当前确认好的设备id和配置地址flags进行功能检查
*/
        profile = getInputProfile(device, address,
                                  profileSamplingRate, profileFormat, profileChannelMask,
                                  profileFlags);
        if (profile != 0) {
            break; // success
        } else if (profileFlags != AUDIO_INPUT_FLAG_NONE) {
            profileFlags = AUDIO_INPUT_FLAG_NONE; // retry
        } else { // fail
            ALOGW("getInputForAttr() could not find profile for device 0x%X, samplingRate %u,"
                    "format %#x, channelMask 0x%X, flags %#x",
                    device, samplingRate, format, channelMask, flags);
            return BAD_VALUE;
        }
    }

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

    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
    config.sample_rate = profileSamplingRate;
    config.channel_mask = profileChannelMask;
    config.format = profileFormat;
    /**
    mpClientInterface就是AudioFlinger的客户端形式接口
  */
    status_t status = mpClientInterface->openInput(profile->getModuleHandle(),
                                                   input,
                                                   &config,
                                                   &device,
                                                   address,
                                                   halInputSource,
                                                   profileFlags);

    // only accept input with the exact requested set of parameters
    if (status != NO_ERROR || *input == AUDIO_IO_HANDLE_NONE ||
        (profileSamplingRate != config.sample_rate) ||
        (profileFormat != config.format) ||
        (profileChannelMask != 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 = profileSamplingRate;
    inputDesc->mFormat = profileFormat;
    inputDesc->mChannelMask = profileChannelMask;
    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;
}

回到AudioFlinger

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

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

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

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

根据input, audio_config_t,audio_devices_t, audio_input_flags_t,audio_source_t进行HAL打开输入流audio_stream_in_t *inStream的同时创建一个RecordThread管理这个输入流。

sp<AudioFlinger::RecordThread> AudioFlinger::openInput_l(audio_module_handle_t module,
                                                         audio_io_handle_t *input,
                                                         audio_config_t *config,
                                                         audio_devices_t devices,
                                                         const String8& address,
                                                         audio_source_t source,
                                                         audio_input_flags_t flags)
{
    AudioHwDevice *inHwDev = findSuitableHwDev_l(module, devices);
    .......
    audio_hw_device_t *inHwHal = inHwDev->hwDevice();
    audio_stream_in_t *inStream = NULL;
    status_t status = inHwHal->open_input_stream(inHwHal, *input, devices, &halconfig,
                                        &inStream, flags, address.string(), source);
    ......
    if (status == NO_ERROR && inStream != NULL) {
/**
tee_sink功能是官方开放用来拦截音频流管道的原始PCM数据,并且可以定义生成wav文件。官方功能使用自行百度,如果单是PCM数据想要截取的话,还不如直接在/av/services/audioflinger/Threads.cpp改代码RecordThread或PlaybackThread来read出PCM数据再存放到固定文件。
*/
#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
     ......
        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);
        /*
    tee sink 功能需要的管道
    */
            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单纯一个结构体存放inHwDev和inStream的
      */
        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(),
                                  devices,
                                  mSystemReady
#ifdef TEE_SINK
                                  , teeSink
#endif
                                  );
    /*  把当前的拿到的RecordThread依赖audio_io_handle_t input存到键值表KeyedVector里,等到客户端后续需要调用该线程做start,stop操作时,可以凭自身的input在mRecordThreads取得。
*/
        mRecordThreads.add(*input, thread);
        return thread;
    }
}

RecordThread类在/av/services/audioflinger/Thread.cpp里面,顺便一提播放音频线程PlaybackThread类也在Thread.cpp。
完成RecordThread录音线程创建和HAL输入流打开的后,
应用进程里面的Jni里的AudioRecord对象的初始化AudioSystem::getInputForAttr接口算是走完了。此时的AudioRecord初始化还并没有结束,还有

sp<IAudioRecord> record = audioFlinger->openRecord(input,mSampleRate,mFormat, mChannelMask,opPackageName,
  &temp,&trackFlags, tid,mClientUid,&mSessionId, &notificationFrames,iMem,
   bufferMem,&status);

IMemory iMem这个IInterface接口参数很重要。IAudioRecord是固定绑定上AudioFlinger操控录音线程RecordThread的接口对象,流程去到

sp<IAudioRecord> AudioFlinger::openRecord(
        audio_io_handle_t input,
        uint32_t sampleRate,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        const String16& opPackageName,
        size_t *frameCount,
        IAudioFlinger::track_flags_t *flags,
        pid_t tid,
        int clientUid,
        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();

    // 通过包名检测权限"android.permission.RECORD_AUDIO"
    if (!recordingAllowed(opPackageName)) {
        ALOGE("openRecord() permission denied: recording not allowed");
        lStatus = PERMISSION_DENIED;
        goto Exit;
    }
   ......
        Mutex::Autolock _l(mLock);
        RecordThread *thread = checkRecordThread_l(input);
  ......
        pid_t pid = IPCThreadState::self()->getCallingPid();
        client = registerPid(pid);
  ......
      /*
 recordTrack是录音线程内部类起核心作用的对象
*/
        // TODO: the uid should be passed in as a parameter to openRecord
        recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
                                                  frameCount, lSessionId, notificationFrames,
                                                  clientUid, flags, tid, &lStatus);
   ......
  /*
cblk是和共享内存相关的引用
*/
    cblk = recordTrack->getCblk();
    buffers = recordTrack->getBuffers();
  ......
    /**
    recordHandle 继承IAudioRecord,相当返回给应用调用端的客户端一个binder控制RecordTrack接口
  */
    // return handle to client
    recordHandle = new RecordHandle(recordTrack);
    return recordHandle;
}

上面代码把重要部分保留了,其他省略。checkRecordThread_l函数,按前面说的会根据audio_io_handle_t input来从键值表里拿出对应的录音线程RecordThread。RecordThread还要createRecordTrack_l 创建一个recordTrack。RecordTrack录音轨道里面又新创建了三个关键对象RecordBufferConverter 数据目标格式转换类,AudioRecordServerProxy 被AudioFlinger使用的录音服务代理和ResamplerBufferProvider看名字取义是重采样数据提供者。
RecordTrack的初始化

   mRecordBufferConverter = new RecordBufferConverter(
            thread->mChannelMask, thread->mFormat, thread->mSampleRate,
            channelMask, format, sampleRate);
    mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
                                              mFrameSize, !isExternalTrack());
    mResamplerBufferProvider = new ResamplerBufferProvider(this);

为什么说关键,mRecordBufferConverter有个转换接口
convert(void *dst, AudioBufferProvider *provider, size_t frames)
在RecordThread的threadLoop里面进行对HAL流读取到原始数据后,会通过mRecordBufferConverter将provider的 getNextBuffer 函数从RecordThread间接拿到原始数据转换成对应目标格式后拷贝到void *dst对应指向的内存。等下会介绍threadLoop函数的开始录音到读取原始数据和结束录音的流程。而mServerProxy的唯一目的是创造一个循环形式使用的内存buffer用于读取或写入录音数据。
另外RecordTrack初始化时还为App客户端AudioRecord初始化用于共享内存的cblk和buffers申请了共享内存堆。

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

就是RecordTrack申请完毕后返回的IMemory 引用。客户端会靠这个IMemory来read录音数据。返回的RecordHandle对象装载了recordTrack,不用想,这个只是集中外观模式的处理来自客户端的控制录音功能。

上一篇下一篇

猜你喜欢

热点阅读