audio-audioflinger-应用音量到活跃流

好的,这是一个非常深入的问题。我们来详细分析 AudioFlinger 如何将应用设置的音量应用到活跃的音频流上。

  1. 整体音量应用流程

应用设置音量 → AudioManager → AudioService → AudioSystem → AudioFlinger

AudioPolicyService (音量曲线管理) → AudioFlinger (混音处理)

AudioFlinger::PlaybackThread → 应用音量 + 设备音量 + 主音量

AudioMixer → 音量应用 → 输出到HAL

  1. 详细源码调用流程

步骤1: 应用层设置音量

// 应用调用

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);

// frameworks/base/media/java/android/media/AudioManager.java

public void setStreamVolume(int streamType, int index, int flags) {

// 通过Binder调用AudioService

IAudioService service = getService();

service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName());

}

步骤2: AudioService处理

// frameworks/base/services/core/java/com/android/server/audio/AudioService.java

public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {

// 1. 权限检查和音量范围验证

ensureValidStreamType(streamType);

index = rescaleIndex(index, streamType);

复制代码
// 2. 获取对应流的音量控制器
VolumeStreamState streamState = mStreamStates[streamType];

// 3. 设置设备索引
int device = getDeviceForStream(streamType);
streamState.setIndex(index, device, callingPackage);

// 4. 通知AudioSystem
mAudioSystem.setStreamVolumeIndex(streamType, index, device);

// 5. 发送音量更新广播
sendBroadcastToAll(new Intent(AudioManager.VOLUME_CHANGED_ACTION));

}

步骤3: AudioSystem到AudioFlinger

// frameworks/av/media/libaudioclient/AudioSystem.cpp

status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value, audio_io_handle_t output) {

// 通过Binder调用AudioFlinger

const sp& af = AudioSystem::get_audio_flinger();

return af->setStreamVolume(stream, value, output);

}

步骤4: AudioFlinger接收音量设置

// frameworks/av/services/audioflinger/AudioFlinger.cpp

status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, audio_io_handle_t output) {

// 1. 检查权限和参数有效性

if (!isStreamValid(stream)) return BAD_VALUE;

复制代码
// 2. 查找对应的播放线程
sp<PlaybackThread> thread = getPlaybackThread_l(output);
if (thread == 0) return BAD_VALUE;

// 3. 在线程中设置流音量
return thread->setStreamVolume(stream, value);

}

  1. PlaybackThread中的音量管理

PlaybackThread音量设置

// frameworks/av/services/audioflinger/Threads.cpp

status_t AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value) {

Mutex::Autolock _l(mLock);

复制代码
// 1. 存储流音量
mStreamTypes[stream].volume = value;

// 2. 立即应用到所有活跃的Track
for (size_t i = 0; i < mActiveTracks.size(); ++i) {
    sp<Track> track = mActiveTracks[i];
    if (track->streamType() == stream) {
        // 重新计算Track的音量
        track->setFinalVolume_l();
    }
}

// 3. 广播音量变化
broadcast_l();
return NO_ERROR;

}

Track音量计算

// frameworks/av/services/audioflinger/Tracks.cpp

void AudioFlinger::PlaybackThread::Track::setFinalVolume_l() {

// 1. 获取流类型音量

float streamVolume = mThread->mStreamTypes[mStreamType].volume;

复制代码
// 2. 获取主音量
float masterVolume = mThread->masterVolume();

// 3. 应用音频策略音量曲线
float volumeDb = AudioSystem::linearToLog(streamVolume * mVolume[0] * mVolume[1]);

// 4. 考虑静音状态
if (mThread->isStreamMuted(mStreamType)) {
    volumeDb = AUDIO_MIN_VOLUME;
}

// 5. 设置最终音量
mFinalVolume = AudioSystem::logToLinear(volumeDb) * masterVolume;

ALOGV("setFinalVolume_l: stream=%d, streamVol=%.3f, master=%.3f, final=%.3f",
      mStreamType, streamVolume, masterVolume, mFinalVolume);

}

  1. 混音时的音量应用

MixerThread处理

// frameworks/av/services/audioflinger/Threads.cpp - MixerThread

bool AudioFlinger::MixerThread::threadLoop() {

while (!exitPending()) {

// 1. 准备混音

processConfigEvents();

复制代码
    // 2. 准备活跃的Tracks
    prepareTracks_l(&tracks, &outputBuffer);
    
    // 3. 执行混音
    mAudioMixer->process();
    
    // 4. 输出到HAL
    threadLoop_write();
}
return false;

}

AudioMixer中的音量处理

// frameworks/av/services/audioflinger/AudioMixer.cpp

void AudioMixer::process() {

for (size_t i = 0; i < mActiveTracks.size(); ++i) {

int name = mActiveTracks[i];

track_t* track = &mTracks[name];

复制代码
    // 应用音量到每个Track
    if (track->needsVolume) {
        // 设置音量参数
        uint32_t vl = uint32_t(track->volume[0] * track->mFinalVolume * 0x1000);
        uint32_t vr = uint32_t(track->volume[1] * track->mFinalVolume * 0x1000);
        
        // 调用DSP处理函数应用音量
        track->hook(track, outputBuffer, numFrames);
    }
}

}

  1. 音量曲线和策略管理

AudioPolicyService参与

// frameworks/av/services/audiopolicy/AudioPolicyService.cpp

float AudioPolicyService::getStreamVolume(audio_stream_type_t stream,

audio_devices_t device,

audio_output_flags_t flags) {

// 1. 获取音量曲线

VolumeCurve curve = getVolumeCurve(stream, device);

复制代码
// 2. 应用音量曲线转换
float volumeDb = curve.mapVolume(mStreams[stream].getVolumeIndex());

// 3. 考虑安全音量限制
volumeDb = applyAllVolumes(volumeDb, stream, device);

return volumeDb;

}

音量曲线映射

// frameworks/av/services/audiopolicy/engine/VolumeCurve.cpp

float VolumeCurve::mapVolume(int index) const {

// 将音量索引转换为dB值

if (index <= mIndexMin) {

return mDbMin;

} else if (index >= mIndexMax) {

return mDbMax;

}

复制代码
// 线性或分段线性插值
float fraction = float(index - mIndexMin) / float(mIndexMax - mIndexMin);
return mDbMin + fraction * (mDbMax - mDbMin);

}

  1. 实时音量调整机制

淡入淡出处理

// frameworks/av/services/audioflinger/Tracks.cpp

void AudioFlinger::PlaybackThread::Track::setVolume(float left, float right) {

sp thread = mThread.promote();

if (thread != 0) {

Mutex::Autolock _l(thread->mLock);

复制代码
    // 设置目标音量
    mVolume[0] = left;
    mVolume[1] = right;
    
    // 如果需要淡入淡出
    if (mFramesCount == 0) {
        // 立即设置
        mFinalVolume = calculateFinalVolume();
    } else {
        // 启动淡入淡出
        startVolumeRamp();
    }
}

}

void AudioFlinger::PlaybackThread::Track::startVolumeRamp() {

// 计算淡入淡出步长

uint32_t sampleRate = mSampleRate;

uint32_t rampFrames = uint32_t((mRampDuration * sampleRate) / 1000);

复制代码
if (rampFrames > 0) {
    mVolumeInc[0] = (mVolume[0] - mPrevVolume[0]) / rampFrames;
    mVolumeInc[1] = (mVolume[1] - mPrevVolume[1]) / rampFrames;
    mRampFrames = rampFrames;
}

}

  1. 多设备音量管理

设备特定音量

// frameworks/av/services/audioflinger/AudioFlinger.cpp

status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream,

float value, audio_io_handle_t output,

audio_devices_t device) {

// 1. 查找对应设备和输出的线程

sp thread = checkPlaybackThread_l(output);

if (thread == 0) return BAD_VALUE;

复制代码
// 2. 设置设备特定的音量
if (device == AUDIO_DEVICE_NONE) {
    device = thread->outDevice();
}

// 3. 存储设备音量
mStreams[stream].setVolume(device, value);

// 4. 应用到活跃流
return thread->setStreamVolume(stream, value, device);

}

  1. 关键设计特点

  2. 分层音量控制

应用音量 → 流音量 → 设备音量 → 主音量 → 最终音量

  1. 实时性保证

• 音量变化立即生效

• 淡入淡出避免爆音

• 锁保护确保线程安全

  1. 策略灵活性

• 可配置的音量曲线

• 设备特定的音量设置

• 安全音量限制

  1. 性能优化

• 预计算最终音量

• 向量化音量处理

• 最小化锁竞争

这个流程展示了Android音频系统如何高效、灵活地管理应用音量,确保多应用、多设备的音频混合能够正确应用各自的音量设置。

相关推荐
天下无敌笨笨熊44 分钟前
kotlin常用语法点理解
android·开发语言·kotlin
赖small强1 小时前
【音视频开发】深度解析图像处理核心概念:饱和度、色度与对比度
图像处理·音视频·色度·对比度·饱和度
烂不烂问厨房1 小时前
支付宝小程序camera录制视频超过30秒无法触发cameraContext.stopRecord回调,也没报错
android·小程序
爱宇阳1 小时前
使用 PowerShell + ffmpeg 自动压缩视频(支持 CRF、无损、目标大小模式)
ffmpeg·音视频
技术小甜甜1 小时前
[Godot游戏开发] 安卓平台游戏如何设置窗口与分辨率:Viewport、Window Override与自适应窗口解析
android·游戏·godot
我血条子呢1 小时前
【Vue3组件示例】简单类甘特图组件
android·javascript·甘特图
c***212910 小时前
Springboot3学习(5、Druid使用及配置)
android·学习
修炼者10 小时前
【Android 进阶】别再强转 Context 了!手把手教你优雅解耦 View 与 Activity
android·android studio