Android 9 Audio系统笔记:AudioFlinger音频流处理流程

这篇具有很好参考价值的文章主要介绍了Android 9 Audio系统笔记:AudioFlinger音频流处理流程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

好久没写了,今天碰巧有个小伙伴问我关于音频流这一块的,久了还有点记不起来,我就顺便写一下,后面就不用又找一遍代码了,所谓好记性不如烂笔头。

所以,这里是关于如何从AudioTrack 写入数据到audioflinger,以及audioflinger如何写入到hal层的音频流处理流程,主要写一下audioflinger处理流程,和写一些细节。

获取音频流

1、client写入数据:

app client 通过创建AudioTrack后,在播放的时候会不断的调用audiotrack的write方法,不断的向audioflinger写数据。

//frameworks\av\media\libaudioclient\AudioTrack.cpp
ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
{
    if (mTransfer != TRANSFER_SYNC) {
        return INVALID_OPERATION;
    }

    if (isDirect()) {
        AutoMutex lock(mLock);
        int32_t flags = android_atomic_and(
                            ~(CBLK_UNDERRUN | CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL | CBLK_BUFFER_END),
                            &mCblk->mFlags);
        if (flags & CBLK_INVALID) {
            return DEAD_OBJECT;
        }
    }
    if (ssize_t(userSize) < 0 || (buffer == NULL && userSize != 0)) {
        // Sanity-check: user is most-likely passing an error code, and it would
        // make the return value ambiguous (actualSize vs error).
        ALOGE("AudioTrack::write(buffer=%p, size=%zu (%zd)", buffer, userSize, userSize);
        return BAD_VALUE;
    }
    size_t written = 0;
    Buffer audioBuffer;
    while (userSize >= mFrameSize) {
        audioBuffer.frameCount = userSize / mFrameSize;
        status_t err = obtainBuffer(&audioBuffer,
                blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking);
        if (err < 0) {
            if (written > 0) {
                break;
            }
            if (err == TIMED_OUT || err == -EINTR) {
                err = WOULD_BLOCK;
            }
            return ssize_t(err);
        }
        size_t toWrite = audioBuffer.size;
        memcpy(audioBuffer.i8, buffer, toWrite);
        buffer = ((const char *) buffer) + toWrite;
        userSize -= toWrite;
        written += toWrite;
        releaseBuffer(&audioBuffer);
    }
    if (written > 0) {
        mFramesWritten += written / mFrameSize;
    }
    return written;
}

2、service端的写

作为service端,不断的接收并处理client写入的数据。

//frameworks/av/services/audioflinger/Tracks.cpp
bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames)
{
    Buffer *pInBuffer;
    Buffer inBuffer;
    bool outputBufferFull = false;
    inBuffer.frameCount = frames;
    inBuffer.raw = data;
    //处理客户端write数据,这个就不在这里细说了,这里不打算细讲这个环形缓冲,有兴趣的可以自行阅读代码
}

AudioFlinger音频流处理

主要处理流程:
track预处理
混音处理
向HAL输出数据

bool AudioFlinger::PlaybackThread::threadLoop()
{			//1、track预处理
			mMixerStatus = prepareTracks_l(&tracksToRemove);
			//2、混音处理
			threadLoop_mix();
            if (mMixerBufferValid) {
            	//
                void *buffer = mEffectBufferValid ? mEffectBuffer : mSinkBuffer;
                audio_format_t format = mEffectBufferValid ? mEffectBufferFormat : mFormat;
                // mono blend occurs for mixer threads only (not direct or offloaded)
                // and is handled here if we're going directly to the sink.
                if (requireMonoBlend() && !mEffectBufferValid) {
                    mono_blend(mMixerBuffer, mMixerBufferFormat, mChannelCount, mNormalFrameCount,
                               true /*limit*/);
                }
				//将mMixerBuffer 按hal 层格式 实际最终还是拷贝到 mSinkBuffer 对象上
                memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
                        mNormalFrameCount * mChannelCount);
            }
            //3、向HAL输出数据
			ret = threadLoop_write();
}

track预处理

向mAudioMixer更新track对象等操作

//prepareTracks_l
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
        Vector< sp<Track> > *tracksToRemove)
{
	.....
    for (size_t i=0 ; i<count ; i++) {
        const sp<Track> t = mActiveTracks[i];
        ....
		// if an active track doesn't exist in the AudioMixer, create it.
        if (!mAudioMixer->exists(name)) {
            status_t status = mAudioMixer->create(
                    name,
                    track->mChannelMask,
                    track->mFormat,
                    track->mSessionId);
            if (status != OK) {
                ALOGW("%s: cannot create track name"
                        " %d, mask %#x, format %#x, sessionId %d in AudioMixer",
                        __func__, name, track->mChannelMask, track->mFormat, track->mSessionId);
                tracksToRemove->add(track);
                track->invalidate(); // consider it dead.
                continue;
            }
        }
        ....
	}
	.....
}

混音处理

void AudioFlinger::MixerThread::threadLoop_mix()
{
    // mix buffers...
    mAudioMixer->process();
    mCurrentWriteLength = mSinkBufferSize;
    // increase sleep time progressively when application underrun condition clears.
    // Only increase sleep time if the mixer is ready for two consecutive times to avoid
    // that a steady state of alternating ready/not ready conditions keeps the sleep time
    // such that we would underrun the audio HAL.
    if ((mSleepTimeUs == 0) && (sleepTimeShift > 0)) {
        sleepTimeShift--;
    }
    mSleepTimeUs = 0;
    mStandbyTimeNs = systemTime() + mStandbyDelayNs;
    //TODO: delay standby when effects have a tail
}
//frameworks/av/media/libaudioprocessing/include/media/AudioMixerBase.h
	void process() {
        preProcess();
        //这里才是处理数据
        (this->*mHook)();
        postProcess();
    }

数据获取&混音处理 (this->*mHook)();
mHook 以process__genericResampling 为例:

//frameworks/av/media/libaudioprocessing/AudioMixerBase.cpp
// generic code with resampling
void AudioMixerBase::process__genericResampling()
{
    ALOGVV("process__genericResampling\n");
    int32_t * const outTemp = mOutputTemp.get(); // naked ptr
    size_t numFrames = mFrameCount;
    for (const auto &pair : mGroups) {
        const auto &group = pair.second;
        const std::shared_ptr<TrackBase> &t1 = mTracks[group[0]];
        // clear temp buffer
        memset(outTemp, 0, sizeof(*outTemp) * t1->mMixerChannelCount * mFrameCount);
        for (const int name : group) {
            const std::shared_ptr<TrackBase> &t = mTracks[name];
            int32_t *aux = NULL;
            if (CC_UNLIKELY(t->needs & NEEDS_AUX)) {
                aux = t->auxBuffer;
            }
            // this is a little goofy, on the resampling case we don't
            // acquire/release the buffers because it's done by
            // the resampler.
            if (t->needs & NEEDS_RESAMPLE) {
                (t.get()->*t->hook)(outTemp, numFrames, mResampleTemp.get() /* naked ptr */, aux);
            } else {
                size_t outFrames = 0;
                while (outFrames < numFrames) {
                    t->buffer.frameCount = numFrames - outFrames;
                    //获取client写入的数据
                    t->bufferProvider->getNextBuffer(&t->buffer);
                    t->mIn = t->buffer.raw;
                    // t->mIn == nullptr can happen if the track was flushed just after having
                    // been enabled for mixing.
                    if (t->mIn == nullptr) break;
                    (t.get()->*t->hook)(
                            outTemp + outFrames * t->mMixerChannelCount, t->buffer.frameCount,
                            mResampleTemp.get() /* naked ptr */,
                            aux != nullptr ? aux + outFrames : nullptr);
                    outFrames += t->buffer.frameCount;
                    //通知释放 通知client 有可以写入的buffer了
                    t->bufferProvider->releaseBuffer(&t->buffer);
                }
            }
        }
        /**
        
          这个mainBuffer与 mOutput->write((char *)mSinkBuffer, 0); 中的mSinkBuffer 相关联
          //相关代码如下:
          //frameworks\av\services\audioflinger\Threads.cpp
          AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
        Vector< sp<Track> > *tracksToRemove)
        {
        ........
                        mAudioMixer->setParameter(
                        name,
                        AudioMixer::TRACK,
                        AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
                mAudioMixer->setParameter(
                        name,
                        AudioMixer::TRACK,
                        AudioMixer::MAIN_BUFFER, (void *)mMixerBuffer);
        ........
		}
          */
        
        //这里是将outTemp 数据按最终输出格式拷贝给到 mainBuffer
        convertMixerFormat(t1->mainBuffer, t1->mMixerFormat,
                outTemp, t1->mMixerInFormat, numFrames * t1->mMixerChannelCount);
    }
}

向HAL输出数据

  // frameworks\av\services\audioflinger\Threads.cpp
    ssize_t AudioFlinger::MixerThread::threadLoop_write()
{
    // FIXME we should only do one push per cycle; confirm this is true
    // Start the fast mixer if it's not already running
    if (mFastMixer != 0) {
        FastMixerStateQueue *sq = mFastMixer->sq();
        FastMixerState *state = sq->begin();
        if (state->mCommand != FastMixerState::MIX_WRITE &&
                (kUseFastMixer != FastMixer_Dynamic || state->mTrackMask > 1)) {
            if (state->mCommand == FastMixerState::COLD_IDLE) {
                // FIXME workaround for first HAL write being CPU bound on some devices
                ATRACE_BEGIN("write");
                 //AudioStreamOut  *mOutput;
                 //致此,audioflinger的写入流程基本结束,剩下的就是写入到audiohal层,
                 //最后在audiohal处理之后就会通过tinyalsa写入到驱动完成了声音流的输出过程了
                mOutput->write((char *)mSinkBuffer, 0);
                ATRACE_END();
                int32_t old = android_atomic_inc(&mFastMixerFutex);
                if (old == -1) {
                    (void) syscall(__NR_futex, &mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1);
                }
#ifdef AUDIO_WATCHDOG
                if (mAudioWatchdog != 0) {
                    mAudioWatchdog->resume();
                }
#endif
            }
            state->mCommand = FastMixerState::MIX_WRITE;
#ifdef FAST_THREAD_STATISTICS
            mFastMixerDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ?
                FastThreadDumpState::kSamplingNforLowRamDevice : FastThreadDumpState::kSamplingN);
#endif
            sq->end();
            sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
            if (kUseFastMixer == FastMixer_Dynamic) {
                mNormalSink = mPipeSink;
            }
        } else {
            sq->end(false /*didModify*/);
        }
    }
    return PlaybackThread::threadLoop_write();
}

补充

每个client 创建audiotrack的时候都是要通过AudioFlinger来创建的。audioflinger交给Threads.cpp这边创建,创建完毕后会保存在Threads 的mTracks 对象里面,当每次loop的时候会先调用prepareTracks_l 来准备数据,此时会及时将mTracks 同步到AudioMixer(不是将对象直接赋值给AudioMixer对象,AudioMixer会同步创建一个AudioMixer::Track来与mTracks对应,这个AudioMixer::Track然后再包含Track,最后实际获取数据的时候是通过这个Track来获取到client数据的)。

sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input,
                                          CreateTrackOutput& output,
                                          status_t *status)
{
......
        track = thread->createTrack_l(client, streamType, input.attr, &output.sampleRate,
                                      input.config.format, input.config.channel_mask,
                                      &output.frameCount, &output.notificationFrameCount,
                                      input.notificationsPerBuffer, input.speed,
                                      input.sharedBuffer, sessionId, &output.flags,
                                      input.clientInfo.clientTid, clientUid, &lStatus, portId);
......
}


sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(
        const sp<AudioFlinger::Client>& client,
        audio_stream_type_t streamType,
        const audio_attributes_t& attr,
        uint32_t *pSampleRate,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        size_t *pFrameCount,
        size_t *pNotificationFrameCount,
        uint32_t notificationsPerBuffer,
        float speed,
        const sp<IMemory>& sharedBuffer,
        audio_session_t sessionId,
        audio_output_flags_t *flags,
        pid_t tid,
        uid_t uid,
        status_t *status,
        audio_port_handle_t portId)
{
......
        track = new Track(this, client, streamType, attr, sampleRate, format,
                          channelMask, frameCount,
                          nullptr /* buffer */, (size_t)0 /* bufferSize */, sharedBuffer,
                          sessionId, uid, *flags, TrackBase::TYPE_DEFAULT, portId);

        lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY;
        if (lStatus != NO_ERROR) {
            ALOGE("createTrack_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);
        sp<EffectChain> chain = getEffectChain_l(sessionId);
        if (chain != 0) {
            ALOGV("createTrack_l() setting main buffer %p", chain->inBuffer());
            track->setMainBuffer(chain->inBuffer());
            chain->setStrategy(AudioSystem::getStrategyForStream(track->streamType()));
            chain->incTrackCnt();
        }
......
}

最后

sourceinside阅读有些跳转不了,有点恼火。文章来源地址https://www.toymoban.com/news/detail-401624.html

到了这里,关于Android 9 Audio系统笔记:AudioFlinger音频流处理流程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Android Audio Focus 音频焦点】

    Android 中的音频焦点(Audio Focus)是一种机制,用于管理应用程序之间的音频资源竞争。当多个应用程序同时请求使用音频设备时,通过音频焦点机制可以确保最终用户的体验不受影响。 两个或两个以上的 Android 应用可同时向同一输出流播放音频。系统会将所有音频流混合在

    2024年02月03日
    浏览(47)
  • BES音频框架分析---Audioflinger

    音频策略的执行者,负责输入输出流设备的管理及音频流数据的处理传输。 Audioflinger.c完成af创建及音频流管理。 函数的调用:app_init(void)---af_open(); 函数内流程: (1)初始化struct af_stream_cfg_t *role相关参数 (2)创建af_thread,并使用信号量机制完成线程同步,同时af线程内a

    2023年04月14日
    浏览(44)
  • 探索音频预处理的艺术:Audio-Preprocessing-Scripts

    项目地址:https://gitcode.com/innnky/audio-preprocessing-scripts 在数据科学和人工智能领域,尤其是语音识别和音乐分析中,高质量的音频预处理是成功的关键步骤。今天,我们要介绍的是一个名为 Audio-Preprocessing-Scripts 的开源项目,它提供了丰富的工具和脚本,旨在帮助开发者和研究人

    2024年04月27日
    浏览(35)
  • Android Audio播放流程详解

    本文涉及的所有代码都是AOSP源码 Class Name Description AudioTrack Audio子系统对外提供的API类,用于音频数据的播放 AudioPolicyService Audio子系统的策略控制中心,控制设备的选择或者切换,以及音量控制 AudioFlinger Audio子系统的工作引擎,管理输入输出的音频流,音频数据的混音,以及

    2023年04月08日
    浏览(45)
  • 音频处理:Audio DJ Studio for .NET-Crack

    Audio DJ Studio for .NET  is a .NET Windows Forms custom control developed by MultiMedia Soft that makes it easy to add sound playback and mixing capabilities to  Winform  and  WPF applications  written with  Microsoft Visual Studio ; thanks to the integration with DirectShow codecs and with the BASS library, both allowing decoding capabilities for the

    2024年01月23日
    浏览(39)
  • Android Audio音量设置原理流程分析

    本篇文章主要介绍Android音量设置从App应用层到framework层执行流程,以及相关的细节和原理分析,建议在阅读此文章前去看博主的混音理论篇的声音的音量属性和声音相关公式的推导章节,这对阅读时理解音量等级、音量分贝计算有着很大的益处;如果阅读时发现文章有错误,

    2024年02月15日
    浏览(53)
  • 【海思SS528 | MPP】音频例程 sample_audio.c 源码阅读笔记

    上篇文章 【海思SS528】MPP媒体处理软件V5.0 | 音频模块 - 学习笔记 学习了海思MPP媒体处理平台的一小部分音频知识,这篇文章继续学习与音频相关的例程,这样可以更好理解《MPP 媒体处理软件 V5.0 开发参考.pdf》中的音频模块知识。 本篇文章涉及到的SDK文件及路径说明: 《

    2024年02月12日
    浏览(81)
  • 笔记:Android 9系统启动流程

    当电源键按下时,引导芯片代码(汇编指令)会从预定的地方(固化在ROM)开始执行,将引导程序 BootLoader 加载到 RAM中,然后执行 BootLoader 是在 Android 操作系统开始前的一个小程序,主要作用是把系统OS拉起来并运行 位置: bootablebootloader 当 Linux系统被 BootLoader 程序拉起,

    2024年02月14日
    浏览(40)
  • VQE音频处理流程

    RES RES 模块为重采样(Resampler)模块。当AI上行或AO下行通路中开启VQE 各功能 模块时,在处理前后各存在一次重采样,第一次的作用是将输入采样率下的音频数据转换成功能模块所支持的工作采样率(8kHz/16kHz/48kHz),第二次则将工作采样率下的数据转换成输出采样率。 HPF H

    2024年01月19日
    浏览(29)
  • 【Audio音频开发】音频基础知识及PCM技术详解

    个人主页:董哥聊技术 我是董哥,嵌入式领域新星创作者 创作理念:专注分享高质量嵌入式文章,让大家读有所得! 现实生活中,我们听到的声音都是时间连续的,我们称为这种信号叫 模拟信号 。模拟信号需要进行 数字化 以后才能在计算机中使用。 目前我们在计算机上

    2024年02月03日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包