Android AudioFlinger(五)—— 揭开AudioMixer面纱

前言:

在 Android 音频系统中,AudioMixer 是音频框架中一个关键的组件,用于处理多路音频流的混音操作。它主要存在于音频回放路径中,是 AudioFlinger 服务的一部分。

上一节我们讲threadloop的时候,提到了一个函数prepareTracks_l,在这个函数的最后就调用了 mAudioMixer->create、mAudioMixer->setParameter去设置参数,channel、format、volume等等。

AudioMixer继承自 AudioMixerBase,当我们去看AudioMixer的构造函数的时候发现并没有做任何操作

那他的初始化代码在哪里呢?

走进AudioMixer:

我们看prepareTracks_l内关于mAudioMixer的调用流程就可以发现,他首先调用了create函数,然而Audiomixer内部却没有实现create接口,我们追溯到它的父类,发现在AudioMixerBase对象种定义了create接口并且实现了。

我们粗略的看下create里主要做了什么,代码多我做了删减。

cpp 复制代码
status_t AudioMixerBase::create(
        int name, audio_channel_mask_t channelMask, audio_format_t format, int sessionId)
{
    LOG_ALWAYS_FATAL_IF(exists(name), "name %d already exists", name);

    if (!isValidChannelMask(channelMask)) {
        ALOGE("%s invalid channelMask: %#x", __func__, channelMask);
        return BAD_VALUE;
    }
    if (!isValidFormat(format)) {
        ALOGE("%s invalid format: %#x", __func__, format);
        return BAD_VALUE;
    }

    auto t = preCreateTrack();
    {
        t->needs = 0;
        t->volume[0] = 0;
        ...
        t->channelCount = audio_channel_count_from_out_mask(channelMask);
        t->enabled = false;
        t->channelMask = channelMask;
        t->sessionId = sessionId;
        t->hook = NULL;
        ...
        // setBufferProvider(name, AudioBufferProvider *) is required before enable(name)
        t->sampleRate = mSampleRate;
        t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
        t->mFormat = format;
        t->mMixerChannelCount = audio_channel_count_from_out_mask(t->mMixerChannelMask);
        t->mInputFrameSize = audio_bytes_per_frame(t->channelCount, t->mFormat);
        status_t status = postCreateTrack(t.get());
        if (status != OK) return status;
        mTracks[name] = t;
        return OK;
    }
}

可以看到除了一开始做了channel和format的判断,后面基本上就是对track的初始化,像volume、channel、format、sampleRate还有Hook的初始化。

初始化完成后就开始调用AudioMixer内部的接口了,我们依次往下看发现还有getUnreleasedFrames、setParameter、setBufferProvider、process等。

我们先看下setParameter,当属性变化的时候就会调用到这里。

cpp 复制代码
void AudioMixer::setParameter(int name, int target, int param, void *value)
{
    LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
    const std::shared_ptr<Track> &track = getTrack(name);

    int valueInt = static_cast<int>(reinterpret_cast<uintptr_t>(value));
    int32_t *valueBuf = reinterpret_cast<int32_t*>(value);

    switch (target) {

    case TRACK:
        switch (param) {
        case CHANNEL_MASK: {
            const audio_channel_mask_t trackChannelMask =
                static_cast<audio_channel_mask_t>(valueInt);
            if (setChannelMasks(name, trackChannelMask,
                    static_cast<audio_channel_mask_t>(
                            track->mMixerChannelMask | track->mMixerHapticChannelMask))) {
                ALOGV("setParameter(TRACK, CHANNEL_MASK, %x)", trackChannelMask);
                invalidate();
            }
            } break;
        case MAIN_BUFFER:
            if (track->mainBuffer != valueBuf) {
                track->mainBuffer = valueBuf;
                ALOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf);
                if (track->mKeepContractedChannels) {
                    track->prepareForAdjustChannels(mFrameCount);
                }
                invalidate();
            }
            break;
        case AUX_BUFFER:
            AudioMixerBase::setParameter(name, target, param, value);
            break;
        case FORMAT: {
            audio_format_t format = static_cast<audio_format_t>(valueInt);
            if (track->mFormat != format) {
                ALOG_ASSERT(audio_is_linear_pcm(format), "Invalid format %#x", format);
                track->mFormat = format;
                ALOGV("setParameter(TRACK, FORMAT, %#x)", format);
                track->prepareForReformat();
                invalidate();
            }
            } break;
        case MIXER_FORMAT: {
            audio_format_t format = static_cast<audio_format_t>(valueInt);
            if (track->mMixerFormat != format) {
                track->mMixerFormat = format;
                ALOGV("setParameter(TRACK, MIXER_FORMAT, %#x)", format);
                if (track->mKeepContractedChannels) {
                    track->prepareForAdjustChannels(mFrameCount);
                }
            }
            } break;
        case MIXER_CHANNEL_MASK: {
            const audio_channel_mask_t mixerChannelMask =
                    static_cast<audio_channel_mask_t>(valueInt);
            if (setChannelMasks(name, static_cast<audio_channel_mask_t>(
                                    track->channelMask | track->mHapticChannelMask),
                    mixerChannelMask)) {
                ALOGV("setParameter(TRACK, MIXER_CHANNEL_MASK, %#x)", mixerChannelMask);
                invalidate();
            }
            } break;
...
        default:
            LOG_ALWAYS_FATAL("setParameter track: bad param %d", param);
        }
        break;

    case RESAMPLE:
    case RAMP_VOLUME:
    case VOLUME:
        AudioMixerBase::setParameter(name, target, param, value);
        break;
    case TIMESTRETCH:
        switch (param) {
        case PLAYBACK_RATE: {
            const AudioPlaybackRate *playbackRate =
                    reinterpret_cast<AudioPlaybackRate*>(value);
...
        } break;
        default:
            LOG_ALWAYS_FATAL("setParameter timestretch: bad param %d", param);
        }
        break;

    default:
        LOG_ALWAYS_FATAL("setParameter: bad target %d", target);
    }
}

函数的主要结构就是一个switch,首先通过trackId找到对应的track对象,然后去设置对应track的parameter参数,例如 CHANNEL_MASK、FORMAT、MAIN_BUFFER等。

这只是设置参数,那混音在哪里呢?我们继续往下看process

cpp 复制代码
void process() {
    preProcess();
    (this->*mHook)();
    postProcess();
}

这里主要就是调用mHook,mHook是一个函数指针,他会根据不同的场景分别调用不同的函数。

  • process__nop:初始值
  • process__genericResampling:对两路以上的track进行重采样操作
  • process__genericNoResampling:对两路以上的track不进行重采样操作
  • process__validate:这个函数就是根据当前的不同情况将mHook指向不同的函数
  • process__oneTrack16BitsStereoNoResampling:只有一路track,16bit,立体声的时候不进行重采样
cpp 复制代码
process_hook_t mHook = &AudioMixerBase::process__nop;

mHook初始化的时候指向的是process__nop

cpp 复制代码
void invalidate() {
        mHook = &AudioMixerBase::process__validate;
    }

process__validate是在invalidate函数里幅值给了mHook 指针。

cpp 复制代码
void AudioMixerBase::process__validate()
{

    // select the processing hooks
    mHook = &AudioMixerBase::process__nop;
    if (mEnabled.size() > 0) {
        if (resampling) {
            if (mOutputTemp.get() == nullptr) {
                mOutputTemp.reset(new int32_t[MAX_NUM_CHANNELS * mFrameCount]);
            }
            if (mResampleTemp.get() == nullptr) {
                mResampleTemp.reset(new int32_t[MAX_NUM_CHANNELS * mFrameCount]);
            }
            mHook = &AudioMixerBase::process__genericResampling;
        } else {
            // we keep temp arrays around.
            mHook = &AudioMixerBase::process__genericNoResampling;
            if (all16BitsStereoNoResample && !volumeRamp) {
                if (mEnabled.size() == 1) {
                    const std::shared_ptr<TrackBase> &t = mTracks[mEnabled[0]];
                    if ((t->needs & NEEDS_MUTE) == 0) {
                        // The check prevents a muted track from acquiring a process hook.
                        //
                        // This is dangerous if the track is MONO as that requires
                        // special case handling due to implicit channel duplication.
                        // Stereo or Multichannel should actually be fine here.
                        mHook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK,
                                t->mMixerChannelCount, t->mMixerInFormat, t->mMixerFormat,
                                t->useStereoVolume());
                    }
                }
            }
        }
    }
}

这个函数首先使用while循环来遍历每一个track,然后通过 NEEDS_RESAMPLE、NEEDS_AUX、NEEDS_CHANNEL_1、NEEDS_MUTE等判断,最终得到resampling、all16BitsStereoNoResample、volumeRamp的值,然后基于这几个值来决定调用,mHook来指向哪一个函数。

至于音频流数据是如何混到一起的,我们后面章节再来进一步分析。

相关推荐
Mr -老鬼11 分钟前
Android studio 最新Gradle 8.13版本“坑点”解析与避坑指南
android·ide·android studio
xiaolizi5674898 小时前
安卓远程安卓(通过frp与adb远程)完全免费
android·远程工作
阿杰100018 小时前
ADB(Android Debug Bridge)是 Android SDK 核心调试工具,通过电脑与 Android 设备(手机、平板、嵌入式设备等)建立通信,对设备进行控制、文件传输、命令等操作。
android·adb
梨落秋霜9 小时前
Python入门篇【文件处理】
android·java·python
遥不可及zzz11 小时前
Android 接入UMP
android
Coder_Boy_13 小时前
基于SpringAI的在线考试系统设计总案-知识点管理模块详细设计
android·java·javascript
冬奇Lab14 小时前
【Kotlin系列03】控制流与函数:从if表达式到Lambda的进化之路
android·kotlin·编程语言
冬奇Lab14 小时前
稳定性性能系列之十二——Android渲染性能深度优化:SurfaceFlinger与GPU
android·性能优化·debug
冬奇Lab15 小时前
稳定性性能系列之十一——Android内存优化与OOM问题深度解决
android·性能优化