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源码分析的主要内容,如果未能解决你的问题,请参考以下文章

Android 9.0 AAudio源码分析

Android 9.0 AAudio源码分析

Android 9.0 AAudio源码分析

Android 9.0 SQLiteCantOpenDatabaseException SQLITE_CANTOPEN(不支持WAL模式)源码分析定位

Android 9.0 SQLiteCantOpenDatabaseException SQLITE_CANTOPEN(不支持WAL模式)源码分析定位

Android 9.0 SQLiteCantOpenDatabaseException SQLITE_CANTOPEN(不支持WAL模式)源码分析定位