Android 9.0 AAudio源码分析

Posted ……蓦然回首

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 9.0 AAudio源码分析相关的知识,希望对你有一定的参考价值。

android AAudio源码分析(二)



前言

在之前的章节中我们分析了AAudioservice的启动以及openStream这个方法
本章将继续分析AAdioService之中其他几个重要的方法


一、Start

经过前一节对AAudioService里面openStream的分析,相信已经对这个服务不那么陌生了

1.startStream分析

开始
xref: /frameworks/av/services/oboeservice/AAudioService.cpp

//它的功能就是启动数据流
//可以看出来这这个操作是异步的,完成后,服务将发送一个已启动的事件
aaudio_result_t AAudioService::startStream(aaudio_handle_t streamHandle) {
    //根据之前创建好的流的句柄,来获取到serviceStream
    sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
    if (serviceStream.get() == nullptr) {
        ALOGE("startStream(), illegal stream handle = 0x%0x", streamHandle);
        return AAUDIO_ERROR_INVALID_HANDLE;
    }

    //然后根据拿到的serviceStream来执行start
    aaudio_result_t result = serviceStream->start();
    return checkForPendingClose(serviceStream, result);
}

又到了我们之前看过的AAudioServiceStreamBase这个类中
每一个AAudioServiceStreamBase相当于一个client
xref: /frameworks/av/services/oboeservice/AAudioServiceStreamBase.cpp

/**
 * Start the flow of audio data.
 *
 * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
 */
aaudio_result_t AAudioServiceStreamBase::start() {
    aaudio_result_t result = AAUDIO_OK;

    //已经运行,直接返回就可
    if (isRunning()) {
        return AAUDIO_OK;
    }

    //流启动时设置为false
    //首次从流中读取数据时设置为true
    setFlowing(false);

    // Start with fresh presentation timestamps.
    //计时器重置
    mAtomicTimestamp.clear();

    mClientHandle = AUDIO_PORT_HANDLE_NONE;
    //内部调用startDevice
    result = startDevice();
    if (result != AAUDIO_OK) goto error;

    // This should happen at the end of the start.
    //在start完之后应该发送一个AAUDIO_SERVICE_EVENT_STARTED事件给客户端
    //设置状态AAUDIO_STREAM_STATE_STARTED
    sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED);
    setState(AAUDIO_STREAM_STATE_STARTED);
    mThreadEnabled.store(true);
    result = mTimestampThread.start(this);
    if (result != AAUDIO_OK) goto error;

    return result;

error:
    disconnect();
    return result;
}

aaudio_result_t AAudioServiceStreamBase::startDevice() {
    mClientHandle = AUDIO_PORT_HANDLE_NONE;
    //获取到可以操作的AAudioServiceEndpoint对象
    sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
    if (endpoint == nullptr) {
        ALOGE("%s() has no endpoint", __func__);
        return AAUDIO_ERROR_INVALID_STATE;
    }
    return endpoint->startStream(this, &mClientHandle);
}

前面这两个部分的调用很简单,没有涉及到什么复杂的逻辑
startStream是AAudioServiceEndpoint.h定义的虚函数
AAudioServiceEndpointShared和AAudioServiceEndpointMMAP都继承了这个类
所以也就都实现了这个startStream方法
所以这里面的startStream会通过这两个类来实现
我们这里主要看AAudioServiceEndpointMMAP也就是独占模式下startStream
xref: /frameworks/av/services/oboeservice/AAudioServiceEndpointMMAP.cpp

aaudio_result_t AAudioServiceEndpointMMAP::startStream(sp<AAudioServiceStreamBase> stream,
                                                   audio_port_handle_t *clientHandle __unused) {
    // Start the client on behalf of the AAudio service.
    // Use the port handle that was provided by openMmapStream().
    //利用之前打开流时得到的mPortHandle来作为参数传入startClient方法
    audio_port_handle_t tempHandle = mPortHandle;
    aaudio_result_t result = startClient(mMmapClient, &tempHandle);
    // When AudioFlinger is passed a valid port handle then it should not change it.
    //当AudioFlinger被传递一个有效的端口句柄时,它不应该改变它。
    LOG_ALWAYS_FATAL_IF(tempHandle != mPortHandle,
                        "%s() port handle not expected to change from %d to %d",
                        __func__, mPortHandle, tempHandle);
    ALOGV("%s(%p) mPortHandle = %d", __func__, stream.get(), mPortHandle);
    return result;
}

aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
                                                       audio_port_handle_t *clientHandle) {
    if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
    ALOGD("%s(%p(uid=%d, pid=%d))", __func__, &client, client.clientUid, client.clientPid);
    audio_port_handle_t originalHandle =  *clientHandle;
    //这个mMmapStream可以当成AudioFlinger
    //在这里面根据启动流的客户端和保存的句柄为参数来调用start
    status_t status = mMmapStream->start(client, clientHandle);
    aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
    ALOGD("%s() , portHandle %d => %d, returns %d", __func__, originalHandle, *clientHandle, result);
    return result;
}

继续看AudioFlinger里面
xref: /frameworks/av/services/audioflinger/Threads.cpp

status_t AudioFlinger::MmapThread::start(const AudioClient& client,
                                         audio_port_handle_t *handle)
{
    ALOGV("%s clientUid %d mStandby %d mPortId %d *handle %d", __FUNCTION__,
          client.clientUid, mStandby, mPortId, *handle);
    if (mHalStream == 0) {
        return NO_INIT;
    }

    status_t ret;

    if (*handle == mPortId) {
        // for the first track, reuse portId and session allocated when the stream was opened
        return exitStandby();
    }

    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;

    audio_io_handle_t io = mId;
    //判断是输出流还是输入流
    if (isOutput()) {
        audio_config_t config = AUDIO_CONFIG_INITIALIZER;
        config.sample_rate = mSampleRate;
        config.channel_mask = mChannelMask;
        config.format = mFormat;
        audio_stream_type_t stream = streamType();
        audio_output_flags_t flags =
                (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
        audio_port_handle_t deviceId = mDeviceId;
        //获取到之前创建好的句柄
        ret = AudioSystem::getOutputForAttr(&mAttr, &io,
                                            mSessionId,
                                            &stream,
                                            client.clientPid,
                                            client.clientUid,
                                            &config,
                                            flags,
                                            &deviceId,
                                            &portId);
    } else {
        audio_config_base_t config;
        config.sample_rate = mSampleRate;
        config.channel_mask = mChannelMask;
        config.format = mFormat;
        audio_port_handle_t deviceId = mDeviceId;
        ret = AudioSystem::getInputForAttr(&mAttr, &io,
                                              mSessionId,
                                              client.clientPid,
                                              client.clientUid,
                                              client.packageName,
                                              &config,
                                              AUDIO_INPUT_FLAG_MMAP_NOIRQ,
                                              &deviceId,
                                              &portId);
    }
    // APM should not chose a different input or output stream for the same set of attributes
    // and audo configuration
    if (ret != NO_ERROR || io != mId) {
        ALOGE("%s: error getting output or input from APM (error %d, io %d expected io %d)",
              __FUNCTION__, ret, io, mId);
        return BAD_VALUE;
    }

    bool silenced = false;
    //开始start了
    if (isOutput()) {
        ret = AudioSystem::startOutput(mId, streamType(), mSessionId);
    } else {
        ret = AudioSystem::startInput(portId, &silenced);
    }

    Mutex::Autolock _l(mLock);
    // abort if start is rejected by audio policy manager
    if (ret != NO_ERROR) {
        ALOGE("%s: error start rejected by AudioPolicyManager = %d", __FUNCTION__, ret);
        if (mActiveTracks.size() != 0) {
            mLock.unlock();
            if (isOutput()) {
                AudioSystem::releaseOutput(mId, streamType(), mSessionId);
            } else {
                AudioSystem::releaseInput(portId);
            }
            mLock.lock();
        } else {
            mHalStream->stop();
        }
        return PERMISSION_DENIED;
    }

    //音量设置
    if (isOutput()) {
        // force volume update when a new track is added
        mHalVolFloat = -1.0f;
    } else if (!silenced) {
        for (const sp<MmapTrack> &track : mActiveTracks) {
            if (track->isSilenced_l() && track->uid() != client.clientUid)
                track->invalidate();
        }
    }

    // Given that MmapThread::mAttr is mutable, should a MmapTrack have attributes ?
    sp<MmapTrack> track = new MmapTrack(this, mAttr, mSampleRate, mFormat, mChannelMask, mSessionId,
                                        client.clientUid, client.clientPid, portId);

    track->setSilenced_l(silenced);
    mActiveTracks.add(track);
    sp<EffectChain> chain = getEffectChain_l(mSessionId);
    if (chain != 0) {
        chain->setStrategy(AudioSystem::getStrategyForStream(streamType()));
        chain->incTrackCnt();
        chain->incActiveTrackCnt();
    }

    *handle = portId;
    broadcast_l();

    ALOGV("%s DONE handle %d stream %p", __FUNCTION__, *handle, mHalStream.get());

    return NO_ERROR;
}

看完上一章的open函数之后,再看start就没那么困难了
其实内部和audioTrack和audioRecord的方法实现差不多
只不过AAudio这边到底层数据通信时用的是MMAP
因此可以被称为高性能音频

其他的方法就不予在这边分析了
相信读者可以再看完这两章后自己去深入研究
会更有收获呦!


总结

关于AAudioService

AAudioService这个服务属于安卓原生后来才出现的一个服务
其存在的意义就是为了满足我们安卓手机中低延迟音频的需要
在苹果手机中好像早就有这样的功能了
安卓目前占据主流,但是目前我却已经嗅到了一丝丝不安
或许有些已经坐好了准备,有些已经吹起了号角

安卓作为一个开源项目,而且其底层是linux内核
其内部还是有非常多的编码精髓值得我们去学习
未来仍旧可期


觉得看完有帮助的请一键三连吧!
您的支持将是我继续下去的动力

以上是关于Android 9.0 AAudio源码分析的主要内容,如果未能解决你的问题,请参考以下文章