转载自http://blog.axlecho.com/audioyin-liang-she-zhi-liu-cheng/

Audio音量调节是一级一级调节,而且分不同的流类型,如响铃,通话,多媒体等。不同的设备(蓝牙设备)的设置方法有所区别。

sdk的api,设置相应流的音量。不同的流index的范围不一样

//--->frameworks/base/media/java/android/media/AudioManager.java
public void setStreamVolume(int streamType, int index, int flags) {IAudioService service = getService();try {service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName());} catch (RemoteException e) {Log.e(TAG, "Dead object in setStreamVolume", e);}
}

java层Service实现,volume的调节的实现是用state模式来实现,可能需要原子性或不同的模式下调节音量的操作不同。

//--->frameworks/base/services/core/java/com/android/server/audio/AudioService.java
private void setStreamVolume(int streamType, int index, int flags, String callingPackage,String caller, int uid) {...(检查参数)...(转换参数)// 获取设备final int device = getDeviceForStream(streamType);...(特殊处理a2dp)...(检查uid,实体按键调节音量需要判断当前用户?)synchronized (mSafeMediaVolumeState) {mPendingVolumeCommand = null;oldIndex = streamState.getIndex(device);index = rescaleIndex(index * 10, streamType, streamTypeAlias);...(特殊处理a2dp)...(特殊处理HDMI)...(设置一些标志位,如标记一些不可调节音量的设备)//检查当前是否可设置音量if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {// 不可以则生成PendingCommand,等待合适的时机mVolumeController.postDisplaySafeVolumeWarning(flags);mPendingVolumeCommand = new StreamVolumeCommand(streamType, index, flags, device);} else {// 设置音量onSetStreamVolume(streamType, index, flags, device, caller);index = mStreamStates[streamType].getIndex(device);}}// 发送更新音量信息sendVolumeUpdate(streamType, oldIndex, index, flags);
}private void onSetStreamVolume(int streamType, int index, int flags, int device,String caller) {final int stream = mStreamVolumeAlias[streamType];// 设置音量setStreamVolumeInt(stream, index, device, false, caller);...(判断音量是否为0,调节模式(静音或响铃))mStreamStates[stream].mute(index == 0);
}private void setStreamVolumeInt(int streamType,int index,int device,boolean force,String caller) {VolumeStreamState streamState = mStreamStates[streamType];if (streamState.setIndex(index, device, caller) || force) {// Post message to set system volume (it in turn will post a message// to persist).sendMsg(mAudioHandler,MSG_SET_DEVICE_VOLUME,SENDMSG_QUEUE,device,0,streamState,0);}
}@Override
public void handleMessage(Message msg) {...switch (msg.what) {case MSG_SET_DEVICE_VOLUME:setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);break;...}...
}private void setDeviceVolume(VolumeStreamState streamState, int device) {synchronized (VolumeStreamState.class) {// 设置音量streamState.applyDeviceVolume_syncVSS(device);...(Apply change to all streams using this one as alias)}// Post a persist volume msgsendMsg(mAudioHandler,MSG_PERSIST_VOLUME,SENDMSG_QUEUE,device,0,streamState,PERSIST_DELAY);
}public void applyDeviceVolume_syncVSS(int device) {int index;if (mIsMuted) {index = 0;} else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) || ((device & mFullVolumeDevices) != 0)) {index = (mIndexMax + 5)/10;} else {index = (getIndex(device) + 5)/10;}AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
}

AudioSystem的setStreamVolumeIndex是个native函数,从这里到跳到c++代码

//--->frameworks/base/media/java/android/media/AudioSystem.java
public static native int setStreamVolumeIndex(int stream, int index,int device);

jni的代码没做处理,直接转发给c++层的AudioSystem

//--->frameworks/base/core/jni/android_media_AudioSystem.cpp
static JNINativeMethod gMethods[] = { ...{"setStreamVolumeIndex","(III)I",   (void *)android_media_AudioSystem_setStreamVolumeIndex},
...};static jint android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,jobject thiz,jint stream,jint index,jint device)
{return (jint) check_AudioSystem_Command(AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),index,(audio_devices_t)device));
}

AudioSystem又踢给AudioPolicyService(这里是binder通信,从这里跳到服务端处理)

//--->frameworks/av/media/libmedia/AudioSystem.cpp
status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,int index,audio_devices_t device)
{const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();if (aps == 0) return PERMISSION_DENIED;return aps->setStreamVolumeIndex(stream, index, device);
}

AudioPolicyService做了些权限和参数检查,转发给AudioPolicyManager

//---frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream,int index,audio_devices_t device)
{if (mAudioPolicyManager == NULL) return NO_INIT;if (!settingsAllowed()) return PERMISSION_DENIED;if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) return BAD_VALUE;Mutex::Autolock _l(mLock);return mAudioPolicyManager->setStreamVolumeIndex(stream,index,device);
}

AudioPolicyManager的处理比较复杂,主要是包括了音频策略的判断

//--->frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,int index,audio_devices_t device)
{...(检查音量及设备是否为audio设备)...(策略判断)if ((device != AUDIO_DEVICE_OUT_DEFAULT) && (device & (strategyDevice | accessibilityDevice)) == 0) {return NO_ERROR;}...(设置每个输出设备的音量)status_t volStatus = checkAndSetVolume(stream, index, desc, curDevice);...
}status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,int index,const sp<AudioOutputDescriptor>& outputDesc,audio_devices_t device,int delayMs,bool force)
{...(do not change actual stream volume if the stream is muted)...(do not change in call volume if bluetooth is connected and vice versa)// 声音等级与真正参数的转换float volumeDb = computeVolume(stream, index, device);  // 设置输出设备的声音outputDesc->setVolume(volumeDb, stream, device, delayMs, force);// 设置通话的音量??if (stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) {...mpClientInterface->setVoiceVolume(voiceVolume, delayMs);...}}return NO_ERROR;
}

AudioOutputDescriptor是音频设备描述符,outputDesc是SwAudioOutputDescriptor类型。

//--->/frameworks/av/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cppbool AudioOutputDescriptor::setVolume(float volume,audio_stream_type_t stream,audio_devices_t device __unused,uint32_t delayMs,bool force)
{// We actually change the volume if:// - the float value returned by computeVolume() changed// - the force flag is setif (volume != mCurVolume[stream] || force) {ALOGV("setVolume() for stream %d, volume %f, delay %d", stream, volume, delayMs);mCurVolume[stream] = volume;return true;}return false;
}bool SwAudioOutputDescriptor::setVolume(float volume,audio_stream_type_t stream,audio_devices_t device,uint32_t delayMs,bool force)
{bool changed = AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force);if (changed) {// Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is// enabledfloat volume = Volume::DbToAmpl(mCurVolume[stream]);if (stream == AUDIO_STREAM_BLUETOOTH_SCO) {mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volume,mIoHandle, delayMs);}mClientInterface->setStreamVolume(stream, volume, mIoHandle, delayMs);}return changed;
}

AudioOutputDescriptor的mClientInterface是AudioPolicyService,所以会转到AudioPolicyService的setStreamVolume
AudioPolicyService异步执行这个操作,最后会转到AudioSystem的setStreamVolume。

//--->frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
int AudioPolicyService::setStreamVolume(audio_stream_type_t stream,float volume,audio_io_handle_t output,int delayMs)
{return (int)mAudioCommandThread->volumeCommand(stream, volume,output, delayMs);
}status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type_t stream,float volume,audio_io_handle_t output,int delayMs)
{...(封装了一下data跟command)return sendCommand(command, delayMs);
}status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs) {...(一些命令队列的操作)}// 处理函数
bool AudioPolicyService::AudioCommandThread::threadLoop()
{...while (!exitPending()){...switch (command->mCommand) {...case SET_VOLUME: ...(Lock)VolumeData *data = (VolumeData *)command->mParam.get();command->mStatus = AudioSystem::setStreamVolume(data->mStream,data->mVolume,data->mIO);break;...}
}

AudioSystem又转到AudioFlinger

//--->frameworks/av/media/libmedia/AudioSystem.cpp
status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value,audio_io_handle_t output)
{...(权限参数检查)af->setStreamVolume(stream, value, output);return NO_ERROR;
}

AudioFlinger会去获取output对应的PlaybackThread并设置PlaybackThread的音量,如果output == AUDIOIOHANDLE_NONE,则设置所有PlaybackThread的音量。

//--->frameworks/av/services/audioflinger/AudioFlinger.cpp
status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,audio_io_handle_t output)
{...(权限检查)...(流类型检查)AutoMutex lock(mLock);...(获取对应设备的PlaybackTread)// ???mStreamTypes[stream].volume = value;if (thread == NULL) {   // output == AUDIO_IO_HANDLE_NONEfor (size_t i = 0; i < mPlaybackThreads.size(); i++) {mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);}} else {thread->setStreamVolume(stream, value);}return NO_ERROR;
}

PlaybackThread设置mStreamTypes的volume。并唤醒PlaybackThread线程

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

不同类型的Thread貌似有不同使用方法 MixerThread是在prepareTracks_l里使用,最后会设置AudioMixer的参数

//--->frameworks/av/services/audioflinger/Threads.cpp
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(Vector< sp<Track> > *tracksToRemove) {...// FastTracktrack->mCachedVolume = masterVolume * mStreamTypes[track->streamType()].volume;...// NormalTrack// 这里涉及到了左右声道的音量的计算// compute volume for this trackuint32_t vl, vr;       // in U8.24 integer formatfloat vlf, vrf, vaf;   // in [0.0, 1.0] float formatfloat typeVolume = mStreamTypes[track->streamType()].volume;float v = masterVolume * typeVolume;...//计算完设置混音器的参数mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, &vlf);mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, &vrf);mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, &vaf);...
}// 最后会调用到mAudioMixer的setVolumeRampVariables
static inline bool setVolumeRampVariables(float newVolume, int32_t ramp,int16_t *pIntSetVolume, int32_t *pIntPrevVolume, int32_t *pIntVolumeInc,float *pSetVolume, float *pPrevVolume, float *pVolumeInc){...}

DirectOutputThread在processVolumel里使用(processVolumel在prepareTracksl中被调用)
processVolume
l直接设置了输出设备的volume

//--->frameworks/av/services/audioflinger/Threads.cpp
void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTrack) {...float typeVolume = mStreamTypes[track->streamType()].volume;float v = mMasterVolume * typeVolume;...(一系列的设置)if (mOutput->stream->set_volume) {mOutput->stream->set_volume(mOutput->stream, left, right);}
}

还有其他的几种Thread都是上面两种Thread的子类,处理方式是一致的

Android Audio音量设置流程相关推荐

  1. Android Audio音量设置原理流程分析

    Android Audio音量设置原理流程分析 简介 本篇文章主要介绍Android音量设置从App应用层到framework层执行流程,以及相关的细节和原理分析,建议在阅读此文章前去看博主的混音理论 ...

  2. android audio 音量设置分析

    From audiod 中经常遇到的场景是音量调整与输出设备的切换,下面两篇文章 针对这两个场景分别分析一下 1.第一种情况,如果是多路(new多个AudioTrack线程)mix混音的情况,就是Mi ...

  3. android 声卡 音量控制,android audio 音量调节

    这次的分析是从setting设置开始,进入声音设置,然后进入音量设置! 先上传上来,后期进行整理吧 调用流程: -------------------------------------------- ...

  4. android 恢复出厂设置流程分析,基于Android系统快速恢复出厂设置方法实现.doc

    基于Android系统快速恢复出厂设置方法实现 基于Android系统快速恢复出厂设置方法实现 摘 要:针对使用Android系统的智能电视进行恢复出厂设置时重置速度慢的情况进行了研究和分析,从其重置 ...

  5. Android HDMI输出设置流程

    Android的Surface系统定义了一个DisplayType的枚举,其中有代表手机屏幕的DISPLAY_PRIMARY和代表HDMI等外接设备的DISPLAY_EXTERNAL,还有用于Wi-F ...

  6. android qq邮箱格式,android手机怎么使用QQ邮箱 android QQ邮箱设置流程图解

    大家在使用android手机时都发现,其邮箱功能是十分强大的,实时接收邮件,并有通知提醒,像看短信似的.这样方便的邮箱功能是每个邮箱使用者的福音.但是邮箱有那么多种,android手机上默认的是使用g ...

  7. Android Audio打开输出设备流程(十五)

    android audio 生产者与消费者 简介 全面接触生产者/消费者问题是在操作系统原理中,并发性原理讨论的问题 生产者/消费者问题.最近的工作偏向音频,接着上一篇文章,用生产者,消费者模型来理解 ...

  8. android 恢复出厂设置 界面,android恢复出厂设置流程概括

    恢复出厂设置流程概括 ============================================= 恢复出厂设置流程概括: 一. 设置模块中进行恢复出厂设置操作,系统一共做了两件事: 1 ...

  9. [RK3288][Android6.0] Audio的音量设置流程小结

    Platform: Rockchip OS: Android 6.0 Kernel: 3.10.92 说明一: AudioManager提供了两个调节音量接口 adjustSuggestedStrea ...

  10. Android音量设置流程干货版

    原址 1.     音量级数定义 在AudioService.Java中定义了最大音量MAX_STREAM_VOLUME,手机的设置property可以覆盖它. 2.     音量初始化 initSt ...

最新文章

  1. 修改Oracle中的某一带有数据的列的数据类型
  2. 转 C# 串口编程遇到的问题以及解决方法
  3. C++给函数传数组参数C++给函数传数组参数
  4. 【error】Invalid ADAPTORNAME specified. Type 'imaqhwinfo' for a list of available ADAPTORNAMEs.
  5. 前端学习(1487):axios介绍
  6. 泪目!连拿3份 offer,AI 程序员求职经历火爆 IT圈!
  7. 深度相机---(4)三种方案对比
  8. 惠普与4PS联络中心国际标准组织达成战略合作
  9. python pip_Python PIP
  10. STM32烧写程序:Keil5使用ST-link下载程序
  11. 11个优秀的交互设计作品集
  12. 【JAVA SE】三万字终极魔典 面向对象编程深度讲解(包+继承+多态+抽象类+接口 全面剖析)
  13. sqlitestudio和mysql_sqlitestudio怎么用 sqlitestudio使用方法图文详解
  14. 小米路由修改服务器密码,192.168.31.1小米路由器修改WIFI密码
  15. Android 自定义控件之画篮球
  16. [图] Google 迎来全新 Logo 启用无衬线字体
  17. 2020移动apn接入点哪个快_为什么别人的4g网总比你快? 手机这个设置没开启, 难怪网络差...
  18. ​华海诚科在科创板注册生效:预计年收入超3亿元,深圳哈勃为股东​
  19. 自学资源(视频+文本)
  20. Ubuntu系统性能优化详细教程

热门文章

  1. 一起学些LLVM(五): 学习lli/vmir
  2. Simulink高级应用—— Matlab Function中共享或使用全局变量或全局数据
  3. 验证苹果商店服务器通知 responseBodyV2
  4. 一文搞懂 deconvolution、transposed convolution、sub-­pixel or fractional convolution
  5. android 蓝牙发送失败怎么办,在Android中通过蓝牙发送文件时出错?
  6. linux常用命令与问题排查命令记录
  7. python解析HL7协议多方式对比
  8. 65883-12-7,PEG5-Ms带有甲磺酸基和羟基的PEG连接剂
  9. Linux命令英文全称
  10. 手机刷机后丢失照片恢复怎么做到?