Android Framework 音频子系统(13)音量调节之基础

该系列文章总纲链接:专题分纲目录 Android Framework 音频子系统​​​​​​​


本章关键点总结 & 说明:

本章节主要关注➕ 以上思维导图左上 音量调节 部分 即可。说明了音量的基础知识和AudioFlinger调节音量流程,主要包括:

  • AudioFlinger对master volume, stream volume的初始化设置流程
  • AudioFlinger的setMasterVolume 主音量设置流程
  • AudioFlinger 的setStreamVolume 流音量设置流程
  • 播放线程 加载音量设置 流程

1 音量基础知识

@1 四大类Volume音量

  • master volume:设置它等于设置所有的stream volume和track volume。它可以写到声卡里面去,控制所有声音的音量。也可以不写到声卡里面去,而是作为一个乘数因子来影响所有的音量。换句话说:master volume 可以设置所有的AudioTrack volume和stream volume。
  • stream volume:设置某一stream的音量,Android系统中支持10种stream。各种stream的音量也可以单独设置、互不影响。比如"音乐音量"不应该影响到"来电振铃"、"闹钟"、"通话"的音量。
  • stream volume alias:设置的是同一组stream音量,分组在Android源码中称之为"别名",即alias。比如在电话中,5种stream(STREAM_SYSTEM、STREAM_RING、STREAM_NOTIFICATION、STREAM_SYSTEM_ENFORCED、STREAM_DTMF)的alias都是STREAM_RING,那么对应的滑动条即可控制这5种stream的音量。
  • AudioTrack  volume: 单个App设置音量时设置的是这个,它只影响本App的音量。

@2 十种stream

Android系统中有10种stream,在system/core/include/system/audio.h中定义,但把这10种stream分成组,属于同一组的stream具有相同的别名(alias)。在我们设置音量时,一个音量调节滑动条具有一个alias,具有相同alias的stream都会受到这个滑动条的影响。stream与alias的关系(参考)如下所示:

@3 声音播放的两种路径

  • MixerThread:APP对音量的设置不会影响到声卡的硬件音量,而只会影响APP的音频数据的幅值(变小或放大),这些音频数据最终被混合后传给声卡。
  • DirectOutputThread(比如HDMI,单个音频应用程序单独使用一个声卡):同一时间里只有一个APP、只有一个AudioTrack使用它,所以该AudioTrack的音量可以被DirectOutputThread直接用来设置硬件音量,这种声卡使用的不多。若配置文件中参数信息包含"flags AUDIO_OUTPUT_FLAG_DIRECT",则表示这个声卡可以被某个App独占。App就能以DirectOutputThread的形式来使用这个声卡。

@4 混音的逻辑

  • app1:混音数据1 =  音频数据1 * master_volume * stream1_volume * AudioTrack1_volume
  • app2:混音数据2 = 音频数据2 * master_volume * stream2_volume * AudioTrack2_volume
  • app3:混音数据3 = 音频数据3 * master_volume * stream3_volume * AudioTrack3_volume

混合在一起: 最终混音 =混音数据1+混音数据2+混音数据3,然后把混合后的数据写给硬件。

@5 音频系统中的一些关键变量说明:

AudioFlinger类中有关成员:

stream_type_t mStreamTypes[AUDIO_STREAM_CNT];
float mMasterVolume; //存储master volume
bool mMasterMute; //存储是否静音

playbackThread类中:

//为DuplicatingThread的OutputTrack多出一项, DuplicatingThread可以用于在两个声卡上播放出同样的声音
stream_type_t mStreamTypes[AUDIO_STREAM_CNT + 1]; 
bool mMasterMute;
float mMasterVolume; //来源于AudioFlinger中的同名的变量

AudioTrack类中(App端):

float mVolume[2]; //两项,分别表示App设置的左右声道的音量

说明:stream volume和audioTreack中的volume只是软件上的处理,masterVolue中保存的值若HAL提供了相应的写函数就会写给硬件。


2 AudioFlinger调节音量流程

2.1 AudioFlinger音量设置流程说明

音量设置是通过逻辑运算将音量值存放在变量中,之后再播放中重新进行一轮逻辑运算,最终和声音数据一起写入到声卡中,进而播放出合理的声音。

@1 AudioFlinger对master volume, stream volume的初始化设置流程

最开始MasterVolume,、MasterMute、StreamVolume、StreamMute的初始化是在AudioFlinger对象创建时初始化的,MasterVolume,、MasterMute是在构造器中直接初始化,代码如下:

AudioFlinger::AudioFlinger()
    : BnAudioFlinger(),
      mPrimaryHardwareDev(NULL),
      mAudioHwDevs(NULL),
      mHardwareStatus(AUDIO_HW_IDLE),
      mMasterVolume(1.0f),//初值1.0f
      mMasterMute(false),//静音初值
      mNextUniqueId(1),
      mMode(AUDIO_MODE_INVALID),
      mBtNrecIsOff(false),
      mIsLowRamDevice(true),
      mIsDeviceTypeKnown(false),
      mGlobalEffectEnableTime(0),
      mPrimaryOutputSampleRate(0)
{
//...
}

而StreamVolume、StreamMute的初始化则是在成员变量结构体中初始化的,代码如下:

//在创建结构体的时候 直接初始化
struct  stream_type_t {
    stream_type_t()
        :   volume(1.0f),
            mute(false)
    {
    }
    float       volume;
    bool        mute;
};

这一阶段初始化后,在加载音频库的时候执行loadHwModule,代码如下:

audio_module_handle_t AudioFlinger::loadHwModule(const char *name)
{
    if (name == NULL) {
        return 0;
    }
    if (!settingsAllowed()) {
        return 0;
    }
    Mutex::Autolock _l(mLock);
    return loadHwModule_l(name);
}

继续分析loadHwModule_l,代码实现如下:

// loadHwModule_l() must be called with AudioFlinger::mLock held
audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
{
    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
        if (strncmp(mAudioHwDevs.valueAt(i)->moduleName(), name, strlen(name)) == 0) {
            ALOGW("loadHwModule() module %s already loaded", name);
            return mAudioHwDevs.keyAt(i);
        }
    }

    audio_hw_device_t *dev;
    //获取audio_hw_device_t类型设备dev,可以直接操作HAL层
    int rc = load_audio_interface(name, &dev);
    mHardwareStatus = AUDIO_HW_INIT;
    rc = dev->init_check(dev);
    mHardwareStatus = AUDIO_HW_IDLE;

    AudioHwDevice::Flags flags = static_cast<AudioHwDevice::Flags>(0);
    {  // scope for auto-lock pattern
        AutoMutex lock(mHardwareLock);

        if (0 == mAudioHwDevs.size()) {
            mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
            //只要dev中含有get_master_volume,表明可以从库中获取master_volume的初值
            if (NULL != dev->get_master_volume) {
                float mv;
                if (OK == dev->get_master_volume(dev, &mv)) {
                    mMasterVolume = mv;
                }
            }

            mHardwareStatus = AUDIO_HW_GET_MASTER_MUTE;
            //只要dev中含有get_master_mute,表明可以从库中获取master_mute的初值
            if (NULL != dev->get_master_mute) {
                bool mm;
                if (OK == dev->get_master_mute(dev, &mm)) {
                    mMasterMute = mm;
                }
            }
        }

        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
        //设置master_volume的初值 到硬件中
        if ((NULL != dev->set_master_volume) &&
            (OK == dev->set_master_volume(dev, mMasterVolume))) {
            flags = static_cast<AudioHwDevice::Flags>(flags |
                    AudioHwDevice::AHWD_CAN_SET_MASTER_VOLUME);
        }
        mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
        //设置master_mute的初值 到硬件中
        if ((NULL != dev->set_master_mute) &&
            (OK == dev->set_master_mute(dev, mMasterMute))) {
            flags = static_cast<AudioHwDevice::Flags>(flags |
                    AudioHwDevice::AHWD_CAN_SET_MASTER_MUTE);
        }
        mHardwareStatus = AUDIO_HW_IDLE;
    }

    audio_module_handle_t handle = nextUniqueId();
    mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));
    return handle;
}

这里对MasterVolume,、MasterMute进行二次初始化,即如果音频库是支持初值设置的,则以音频库中的值为主,否则就是AudioFlinger创建时的初始值。

@2 AudioFlinger::setMasterVolume 主音量设置流程

AudioFlinger::setMasterVolume的代码实现如下:

status_t AudioFlinger::setMasterVolume(float value)
{
    status_t ret = initCheck();
    //...
    Mutex::Autolock _l(mLock);
    mMasterVolume = value;
    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
        AutoMutex lock(mHardwareLock);
        AudioHwDevice *dev = mAudioHwDevs.valueAt(i);

        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
        //直接将master_volume的值设置到硬件中
        if (dev->canSetMasterVolume()) {
            dev->hwDevice()->set_master_volume(dev->hwDevice(), value);
        }
        mHardwareStatus = AUDIO_HW_IDLE;
    }
    //将master_volume的值设置到各个播放线程中
    for (size_t i = 0; i < mPlaybackThreads.size(); i++)
        mPlaybackThreads.valueAt(i)->setMasterVolume(value);

    return NO_ERROR;
}

这里PlaybackThread::setMasterVolume的代码实现如下:

void AudioFlinger::PlaybackThread::setMasterVolume(float value)
{
    Mutex::Autolock _l(mLock);
    // Don't apply master volume in SW if our HAL can do it for us.
    if (mOutput && mOutput->audioHwDev &&
        mOutput->audioHwDev->canSetMasterVolume()) {
        mMasterVolume = 1.0;
    } else {
        mMasterVolume = value;
    }
}

可以看到都是直接操作HAL层的接口进行参数设置。

@3 AudioFlinger::setStreamVolume 流音量设置流程

 AudioFlinger::setStreamVolume的 代码实现如下:

status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
        audio_io_handle_t output)
{
    status_t status = checkStreamType(stream);
    AutoMutex lock(mLock);
    PlaybackThread *thread = NULL;
    if (output != AUDIO_IO_HANDLE_NONE) {
        thread = checkPlaybackThread_l(output);
        if (thread == NULL) {
            return BAD_VALUE;
        }
    }

    mStreamTypes[stream].volume = value;
    if (thread == NULL) {
        //未指定线程则全部播放线程 均设置
        for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
            mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);
        }
    } else {
        //指定线程则直接设置
        thread->setStreamVolume(stream, value);
    }
    return NO_ERROR;
}

继续分析播放线程的setStreamVolume方法,代码实现如下:

void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
{
    Mutex::Autolock _l(mLock);
    mStreamTypes[stream].volume = value;//赋值
    broadcast_l();
}

实际上 每个播放线程中都有 mStreamTypes[stream].volume,和 AudioFlinger的mStreamTypes[stream].volume是一致的。

@4 AudioTrack volume的设置

 AudioTrack::setVolume的代码实现如下:

status_t AudioTrack::setVolume(float volume)
{
    return setVolume(volume, volume);
}

status_t AudioTrack::setVolume(float left, float right)
{
    //...
    AutoMutex lock(mLock);
    mVolume[AUDIO_INTERLEAVE_LEFT] = left;
    mVolume[AUDIO_INTERLEAVE_RIGHT] = right;
    //这里会通过ClientProxy将音量参数设置到共享内存中
    //这里的mProxy = 
    //new AudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF);
    mProxy->setVolumeLR(gain_minifloat_pack(gain_from_float(left), gain_from_float(right)));

    if (isOffloaded_l()) {
        mAudioTrack->signal();
    }
    return NO_ERROR;
}

这里是把这个数据记录在mVolumeLR域中,创建Proxy时传递的Cblk参数就是共享内存的头部。

2.2 播放线程 加载音量设置 流程

@1 源码流程分析说明

这里分析时主要针对音量部分相关代码进行分析,代码实现如下:

// prepareTracks_l() must be called with ThreadBase::mLock held
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
        Vector< sp<Track> > *tracksToRemove)
{
    //...
    float masterVolume = mMasterVolume;
    bool masterMute = mMasterMute;
    if (masterMute) {//如果静音条件为真,则设置masterVolume=0
        masterVolume = 0;
    }
    //...
    mMixerBufferValid = false;  // mMixerBuffer has no valid data until appropriate tracks found.
    mEffectBufferValid = false; // mEffectBuffer has no valid data until tracks found.

    for (size_t i=0 ; i<count ; i++) {
        const sp<Track> t = mActiveTracks[i].promote();
        if (t == 0) {
            continue;
        }

        // this const just means the local variable doesn't change
        Track* const track = t.get();
        //...
        {   // local variable scope to avoid goto warning
        audio_track_cblk_t* cblk = track->cblk();
        int name = track->name();
        size_t desiredFrames;
        uint32_t sr = track->sampleRate();
        if (sr == mSampleRate) {
            desiredFrames = mNormalFrameCount;
        } else {
            // +1 for rounding and +1 for additional sample needed for interpolation
            desiredFrames = (mNormalFrameCount * sr) / mSampleRate + 1 + 1;
            desiredFrames += mAudioMixer->getUnreleasedFrames(track->name());
        }
        uint32_t minFrames = 1;
        if ((track->sharedBuffer() == 0) && !track->isStopped() && !track->isPausing() &&
                (mMixerStatusIgnoringFastTracks == MIXER_TRACKS_READY)) {
            minFrames = desiredFrames;
        }

        size_t framesReady = track->framesReady();
        if ((framesReady >= minFrames) && track->isReady() &&
                !track->isPaused() && !track->isTerminated())
        {
            mixedTracks++;
            //...
            // compute volume for this track
            uint32_t vl, vr;       // in U8.24 integer format
            float vlf, vrf, vaf;   // in [0.0, 1.0] float format
            if (track->isPausing() || mStreamTypes[track->streamType()].mute) {
                vl = vr = 0;
                vlf = vrf = vaf = 0.;
                if (track->isPausing()) {
                    track->setPaused();
                }
            } else {
                // read original volumes with volume control
                //获取 StreamType Volume
                float typeVolume = mStreamTypes[track->streamType()].volume;
                float v = masterVolume * typeVolume;
                //获取共享内存代理
                AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy;
                //从共享内存中获得左右声道
                gain_minifloat_packed_t vlr = proxy->getVolumeLR();
                vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
                vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
                // track volumes come from shared memory, so can't be trusted and must be clamped
                //边界判断
                if (vlf > GAIN_FLOAT_UNITY) {
                    ALOGV("Track left volume out of range: %.3g", vlf);
                    vlf = GAIN_FLOAT_UNITY;
                }
                if (vrf > GAIN_FLOAT_UNITY) {
                    ALOGV("Track right volume out of range: %.3g", vrf);
                    vrf = GAIN_FLOAT_UNITY;
                }
                // now apply the master volume and stream type volume
                //放大系数:master_volume * stream_volume * AudioTrack_volume
                vlf *= v;
                vrf *= v;
                // assuming master volume and stream type volume each go up to 1.0,
                // then derive vl and vr as U8.24 versions for the effect chain
                //下面主要是左右声道转换成AUX单声道的一些逻辑运算
                const float scaleto8_24 = MAX_GAIN_INT * MAX_GAIN_INT;
                vl = (uint32_t) (scaleto8_24 * vlf);
                vr = (uint32_t) (scaleto8_24 * vrf);
                // vl and vr are now in U8.24 format
                uint16_t sendLevel = proxy->getSendLevel_U4_12();
                // send level comes from shared memory and so may be corrupt
                if (sendLevel > MAX_GAIN_INT) {
                    ALOGV("Track send level out of range: %04X", sendLevel);
                    sendLevel = MAX_GAIN_INT;
                }
                // vaf is represented as [0.0, 1.0] float by rescaling sendLevel
                vaf = v * sendLevel * (1. / MAX_GAIN_INT);
            }

            // Delegate volume control to effect in track effect chain if needed
            if (chain != 0 && chain->setVolume_l(&vl, &vr)) {
                // Do not ramp volume if volume is controlled by effect
                param = AudioMixer::VOLUME;
                // Update remaining floating point volume levels
                vlf = (float)vl / (1 << 24);
                vrf = (float)vr / (1 << 24);
                track->mHasVolumeController = true;
            } else {
                // force no volume ramp when volume controller was just disabled or removed
                // from effect chain to avoid volume spike
                if (track->mHasVolumeController) {
                    param = AudioMixer::VOLUME;
                }
                track->mHasVolumeController = false;
            }

            // XXX: these things DON'T need to be done each time
            mAudioMixer->setBufferProvider(name, track);
            mAudioMixer->enable(name);
            //关键点:通过参数设置将音量信息传递出去
            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, &vlf);
            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, &vrf);
            mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, &vaf);
            //设置其他参数
            //...
            // reset retry count
            track->mRetryCount = kMaxTrackRetries;
            if (mMixerStatusIgnoringFastTracks != MIXER_TRACKS_READY ||
                    mixerStatus != MIXER_TRACKS_ENABLED) {
                mixerStatus = MIXER_TRACKS_READY;
            }
        } else {
            //...
        }

        }   // local variable scope to avoid goto warning
track_is_ready: ;
    }
    //...
    return mixerStatus;
}

这里专注分析AudioMixer的 参数设置setParameter方法,代码实现如下:

void AudioMixer::setParameter(int name, int target, int param, void *value)
{
    name -= TRACK0;
    track_t& track = mState.tracks[name];
    int valueInt = static_cast<int>(reinterpret_cast<uintptr_t>(value));
    int32_t *valueBuf = reinterpret_cast<int32_t*>(value);

    switch (target) {
    //...
    case RAMP_VOLUME:
    case VOLUME:
        switch (param) {
        case AUXLEVEL:
            if (setVolumeRampVariables(*reinterpret_cast<float*>(value),
                    target == RAMP_VOLUME ? mState.frameCount : 0,
                    &track.auxLevel, &track.prevAuxLevel, &track.auxInc,
                    &track.mAuxLevel, &track.mPrevAuxLevel, &track.mAuxInc)) {
                invalidateState(1 << name);
            }
            break;
        default:
            if ((unsigned)param >= VOLUME0 && (unsigned)param < VOLUME0 + MAX_NUM_VOLUMES) {
                //setVolumeRampVariables主要是 float和int类型之间的转换的一些逻辑操作
                if (setVolumeRampVariables(*reinterpret_cast<float*>(value),
                        target == RAMP_VOLUME ? mState.frameCount : 0,
                        &track.volume[param - VOLUME0], &track.prevVolume[param - VOLUME0],
                        &track.volumeInc[param - VOLUME0],
                        &track.mVolume[param - VOLUME0], &track.mPrevVolume[param - VOLUME0],
                        &track.mVolumeInc[param - VOLUME0])) {
                    invalidateState(1 << name);
                }
            } else {
                LOG_ALWAYS_FATAL("setParameter volume: bad param %d", param);
            }
        }
        break;
    default:
        LOG_ALWAYS_FATAL("setParameter: bad target %d", target);
    }
}

这里专注 invalidateState的实现,代码如下:

void AudioMixer::invalidateState(uint32_t mask)
{
    if (mask != 0) {
        mState.needsChanged |= mask;
        mState.hook = process__validate;
    }
}

process__validate的实现如下:

void AudioMixer::process__validate(state_t* state, int64_t pts)
{
    //...
    // compute everything we need...
    while (en) {
        //...
        if (n & NEEDS_MUTE) {
            t.hook = track__nop;
        } else {
            if (n & NEEDS_AUX) {
                all16BitsStereoNoResample = false;
            }
            if (n & NEEDS_RESAMPLE) {
                all16BitsStereoNoResample = false;
                resampling = true;
                t.hook = getTrackHook(TRACKTYPE_RESAMPLE, t.mMixerChannelCount,
                        t.mMixerInFormat, t.mMixerFormat);
            } else {
                if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
                    t.hook = getTrackHook(
                            t.mMixerChannelCount == 2 // TODO: MONO_HACK.
                                ? TRACKTYPE_NORESAMPLEMONO : TRACKTYPE_NORESAMPLE,
                            t.mMixerChannelCount,
                            t.mMixerInFormat, t.mMixerFormat);
                    all16BitsStereoNoResample = false;
                }
                if ((n & NEEDS_CHANNEL_COUNT__MASK) >= NEEDS_CHANNEL_2){
                    t.hook = getTrackHook(TRACKTYPE_NORESAMPLE, t.mMixerChannelCount,
                            t.mMixerInFormat, t.mMixerFormat);
                }
            }
        }
    }
    //...
}

这里主要关注getTrackHook函数,代码实现如下:

AudioMixer::hook_t AudioMixer::getTrackHook(int trackType, uint32_t channelCount,
        audio_format_t mixerInFormat, audio_format_t mixerOutFormat __unused)
{
    if (!kUseNewMixer && channelCount == FCC_2 && mixerInFormat == AUDIO_FORMAT_PCM_16_BIT) {
        switch (trackType) {
        //...
        case TRACKTYPE_NORESAMPLE:
            return track__16BitsStereo;
        default:
            break;
        }
    }
    //...
    return NULL;
}

这里以关注TRACKTYPE_NORESAMPLE为例,最终会调用到track__16BitsStereo,代码实现如下:

void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount,
        int32_t* temp __unused, int32_t* aux)
{
    ALOGVV("track__16BitsStereo\n");
    const int16_t *in = static_cast<const int16_t *>(t->in);

    if (CC_UNLIKELY(aux != NULL)) {
        //忽略AUX相关处理
    } else {
        // ramp gain
        if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) {
            int32_t vl = t->prevVolume[0];
            int32_t vr = t->prevVolume[1];
            const int32_t vlInc = t->volumeInc[0];左声道音量
            const int32_t vrInc = t->volumeInc[1];右声道音量

            do {
                *out++ += (vl >> 16) * (int32_t) *in++;
                *out++ += (vr >> 16) * (int32_t) *in++;
                vl += vlInc;
                vr += vrInc;
            } while (--frameCount);

            t->prevVolume[0] = vl;
            t->prevVolume[1] = vr;
            t->adjustVolumeRamp(false);
        }

        // constant gain
        else {
            const uint32_t vrl = t->volumeRL;
            do {
                uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
                in += 2;
                out[0] = mulAddRL(1, rl, vrl, out[0]);
                out[1] = mulAddRL(0, rl, vrl, out[1]);
                out += 2;
            } while (--frameCount);
        }
    }
    t->in = in;
}

最终我们把数据存储到out中,这里的mulAddRL有三个,这里以下面的这个实现为例,代码如下:

//另外2种实现模式类似
static inline
int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
{
#if USE_INLINE_ASSEMBLY
    int32_t out;
    if (left) {
        asm( "smlawb %[out], %[v], %[inRL], %[a] \n"
             : [out]"=r"(out)
             : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
             : );
    } else {
        asm( "smlawt %[out], %[v], %[inRL], %[a] \n"
             : [out]"=r"(out)
             : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
             : );
    }
    return out;
#else
    int16_t s = left ? int16_t(inRL) : int16_t(inRL>>16);
    return a + int32_t((int64_t(v) * s) >> 16);
#endif
}

虽然有可能会使用汇编语句来优化,但实际上逻辑是一致的(这里用outL表示左声道,outR表示右声道):

  • 左声道:outL = (inRL&0xffff * v) + outL //前16位
  • 右声道:outR = (inRL>>16    * v) + outR //后16位

最后outL 和 outR 合并成一个值(低16bit是左声道数据,高16bit是右声道数据)并返回。这里实际上是属于播放音频中MixerThread::prepareTracks_l中 tracks[x].hook中的一个操作,通过这操作有了prepareTrack_l设置的参数,在threadLoop_mix中进行混音。最后通过threadLoop_write用于混音后的音频输出,最后将填充好的Buffer写入到硬件中。

@2 关于MixerThread::prepareTracks_l涉及的track_t结构体的说明

代码实现如下:

struct track_t {
	//...
    // TODO: Eventually remove legacy integer volume settings
	//int类型 普通声音
    union {
    int16_t     volume[MAX_NUM_VOLUMES]; // U4.12 fixed point (top bit should be zero)
    int32_t     volumeRL;
    };
    int32_t     prevVolume[MAX_NUM_VOLUMES];
    int32_t     volumeInc[MAX_NUM_VOLUMES];
	//...
	//int类型 aux声音
    int32_t     auxInc;
    int32_t     prevAuxLevel;
	int16_t     auxLevel;       // 0 <= auxLevel <= MAX_GAIN_INT, but signed for mul performance
	//...
	//float类型 普通声音
    float          mVolume[MAX_NUM_VOLUMES];     // floating point set volume
    float          mPrevVolume[MAX_NUM_VOLUMES]; // floating point previous volume
    float          mVolumeInc[MAX_NUM_VOLUMES];  // floating point volume increment
	//...
	//float类型 aux声音
    float          mAuxLevel;                     // floating point set aux level
    float          mPrevAuxLevel;                 // floating point prev aux level
    float          mAuxInc;                       // floating point aux increment
	//...
};

这里aux的数据实际上就是 左右声道叠加在一起,通过特定处理后转换成 特定声道的方式。
这里我们可以发现,track_t结构体中共有4组音量变量。都是PreVolume,VolumeInc,Volume这种模式,这三种变量的意义如下图所示:

解读如下:

  • PreVolume:之前的音量初始值
  • VolumeInc:表示每次调节的步长
  • Volume:当前的音量 = master_volume * stream_volume * AudioTrack_volume
 
发布了290 篇原创文章 · 获赞 47 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/vviccc/article/details/105437166