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

这次的分析是从setting设置开始,进入声音设置,然后进入音量设置!

先上传上来,后期进行整理吧

调用流程:

--------------------------------------------------------------------------------------------------------

Setting应用

... ...

RingerVolumePreference(DialogPreference).onClick()

→RingerVolumePreference(DialogPreference).showDialog(Bundle)

→RingerVolumePreference.onBindDialogView(View)

→RingerVolumePreference.updateSlidersAndMutedStates()

→mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);

→mAudioManager.getStreamVolume(streamType);

|

-------------------------|------------------------------------------------------------------------------

|                                                         AudioManager

getStreamVolume

|→IAudioService service = getService();

|→service.getStreamVolume(streamType);

|

---------------------------|-----------------------------------------------------------------------------

|                        AudioService.java               AudioService(JAVA层)

getStreamVolume

ensureValidStreamType(streamType);

(mStreamStates[streamType].mLastAudibleIndex + 5) / 10;

|

VolumeStreamState

|①从setting provider中读取上次保存的音量值

|→mLastAudibleIndex = Settings.System.getInt(cr,

|                            mLastAudibleVolumeIndexSettingName,

| (mIndex > 0) ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]);

|②初始化native层的音量值

|→AudioSystem.initStreamVolume(streamType, 0, mIndexMax);

|③设置native层的音量值

|→setStreamVolumeIndex(streamType, mIndex);

|

AudioSystem.setStreamVolumeIndex(stream, (index + 5)/10);

initStreamVolume                   setStreamVolumeIndex

|                                                      |

------------------JNI----------------------------------------------------JNI-------------------------------

|                        |              JNI层

android_media_AudioSystem_initStreamVolume     android_media_AudioSystem_setStreamVolumeIndex

|                        |

|  check_AudioSystem_Command                  |

|                        |

-------------------|---------------------------------------------------------------------------------------

|                        |  AudioPolicyService客户端

|               |

AudioSystem::initStreamVolume                          AudioSystem::setStreamVolumeIndex

|                        |

| aps = AudioSystem::get_audio_policy_service();    |

|               |

aps->initStreamVolume(stream, indexMin, indexMax);   aps->setStreamVolumeIndex(stream, index);

|               |

remote()->transact(INIT_STREAM_VOLUME, data, &reply);  remote()->transact(SET_STREAM_VOLUME, data, &reply);

|               |

-------------------|-------------------binder通信-------------------------|---------------------------------

|               |  AudioPolicyService服务端

|               |

AudioPolicyService::initStreamVolume       AudioPolicyService::setStreamVolumeIndex

|               |

mpAudioPolicy->init_stream_volum     mpAudioPolicy->set_stream_volume_index

|               |

-------------------|------------------------------------------------------|------------------------------------------

|               |      Audio policy HAL 硬件抽象层

|

ap_set_stream_volume_index

|

lap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream,index);

|

AudioPolicyManagerBase::setStreamVolumeIndex

|

checkAndSetVolume(stream, index, mOutputs.keyAt(i), mOutputs.valueAt(i)->device());

|

AudioPolicyManagerBase::checkAndSetVolume

|

mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);

|

AudioPolicyCompatClient::setStreamVolume

|

mServiceOps->set_stream_volume(mService, (audio_stream_type_t)stream,volume, output, delayMs);

|

aps_set_stream_volume    AudioPolicyService.cpp

|

audioPolicyService->setStreamVolume(stream, volume, output,delay_ms);

|

mAudioCommandThread->volumeCommand((int)stream, volume,(int)output, delayMs);

|

AudioPolicyService::AudioCommandThread::volumeCommand

|

insertCommand_l(command, delayMs);

至此,我们需要去分析执行command的后台线程,会如何执行这些命令的。

----------------------------------------AudioPolicyService::AudioCommandThread::threadLoop-----------------------------------------------------

bool AudioPolicyService::AudioCommandThread::threadLoop()

{

nsecs_t waitTime = INT64_MAX;

mLock.lock();

while (!exitPending())

{

while(!mAudioCommands.isEmpty()) {

... ...

switch (command->mCommand) {

... ...

case SET_VOLUME: {

VolumeData *data = (VolumeData *)command->mParam;

LOGV("AudioCommandThread() processing set volume stream %d, \

volume %f, output %d", data->mStream, data->mVolume, data->mIO);

command->mStatus = AudioSystem::setStreamVolume(data->mStream,

|        data->mVolume,

|        data->mIO);

if (command->mWaitStatus) {    |

command->mCond.signal();   |

mWaitWorkCV.wait(mLock);   |

}          |

delete data;       |

}break;         |

... ...          |

}               |

|

AudioSystem::setStreamVolume

|

|

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

|→af->setStreamVolume(stream, value, output);

|

|

------------------------------------------------------------|--------------------------------------------------------------------

|        AudioFlinger

AudioFlinger::setStreamVolume

|

thread->setStreamVolume(stream, value);

|

AudioFlinger::PlaybackThread::setStreamVolume

|

mStreamTypes[stream].volume = value;         至此音量设置完毕

接下来分析下上面遗留的Init相关的流程:

AudioPolicyService::initStreamVolume

|

----------------------现在有必要搞清楚mpAudioPolicy到底是怎么来的----------------------------------------------------

AudioPolicyService是Android音频系统的两大服务之一,另一个服务是AudioFlinger,这两大服务都在系统启动时由MediaSever加载,

加载的代码位于:frameworks/base/media/mediaserver/main_mediaserver.cpp。AudioFlinger主要负责管理音频数据处理以及和硬件

抽象层相关的工作。下面研究下AudioPolicyService。

AudioPolicyService主要完成以下任务:

JAVA应用层通过JNI,经由IAudioPolicyService接口,访问AudioPolicyService提供的服务

输入输出设备的连接状态

系统的音频策略(strategy)的切换

音量/音频参数的设置

AudioPolicyService有一个内部线程类AudioCommandThread,顾名思义,所有的命令(音量控制,输入、输出的切换等)最终都会在该线程中排队执行;

AudioPolicyService的很大一部分管理工作都是在AudioPolicyManager中完成的。包括音量管理,音频策略(strategy)管理,输入输出设备管理。

我们现在比较关心的是音量的控制,所以我们还是到AudioCommandThread线程中了解一下。

AudioCommandThread线程是在AudioPolicyService的构造函数中创建的。

AudioPolicyService::AudioPolicyService()

→mAudioCommandThread = new AudioCommandThread(String8("ApmCommandThread"));

AudioCommandThread线程的主要工作是在bool AudioPolicyService::AudioCommandThread::threadLoop()中完成的。

threadLoop中主要处理音频设置相关的命令:

▲START_TONE/STOP_TONE:播放电话系统中常用的特殊音调,例如:TONE_DTMF_0,TONE_SUP_BUSY等等。

▲SET_VOLUME:最终会调用AudioFlinger进行音量设置

▲SET_PARAMETERS:最终会调用AudioFlinger进行电话音量设置

▲SET_VOICE_VOLUME:通过一个KeyValuePairs形式的字符串进行参数设置

我们比较关心"音量设置"相关,所以只关注SET_VOLUME.

case SET_VOLUME: {

VolumeData *data = (VolumeData *)command->mParam;

command->mStatus = AudioSystem::setStreamVolume(data->mStream,data->mVolume,data->mIO);

---------------------------------------------------------------------------------------------------------------------------------------------

下面研究一下AudioPolicyManager:

AudioPolicyManager是在AudioPolicyService的构造函数中创建的。

AudioPolicyService::AudioPolicyService

|→hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);

|(获得AudioPolicyHardwareModule,根据模块ID找到硬件模块动态链接库的地址,然后调用load去打开动态链接库并从中获取硬件模块结构体地址。)

|struct legacy_ap_module HAL_MODULE_INFO_SYM = {

|module: {

|    common: {

|        tag: HARDWARE_MODULE_TAG,

|        version_major: 1,

|        version_minor: 0,

|        id: AUDIO_POLICY_HARDWARE_MODULE_ID, //ID

|        name: "LEGACY Audio Policy HAL",

|        author: "The Android Open Source Project",

|        methods: &legacy_ap_module_methods,

|        dso : NULL,

|        reserved : {0},

|    },

|},

|};

|

|→audio_policy_dev_open(module, &mpAudioPolicyDev); //打开 audio policy device

|→mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,&mpAudioPolicy);

| |static int legacy_ap_dev_open(const hw_module_t* module, const char* name,

|   |                             hw_device_t** device)

| |{

| | struct legacy_ap_device *dev;

| |

| | if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0)

|   |   return -EINVAL;

| |

| | dev = (struct legacy_ap_device *)calloc(1, sizeof(*dev));

| | if (!dev)

|   |   return -ENOMEM;

| |

| | dev->device.common.tag = HARDWARE_DEVICE_TAG;

| | dev->device.common.version = 0;

| | dev->device.common.module = const_cast(module);

| | dev->device.common.close = legacy_ap_dev_close;

| | dev->device.create_audio_policy = create_legacy_ap;//create_audio_policy对应的操作函数。

| | dev->device.destroy_audio_policy = destroy_legacy_ap;

| |

| | *device = &dev->device.common;

| |

| | return 0;

| |}

| |

| |→create_legacy_ap

|  |→lap->policy.init_check = ap_init_check;

|  |→lap->policy.init_stream_volume = ap_init_stream_volume;

|  |→lap->policy.set_stream_volume_index = ap_set_stream_volume_index;

|  |→... ...

|  |→ap->apm = createAudioPolicyManager(lap->service_client);//创建AudioPolicyManager

|     |→new AudioPolicyManagerDefault(clientInterface);

|        |→AudioPolicyManagerBase::AudioPolicyManagerBase

|         |→mpClientInterface = clientInterface;

|

### RK3326 平台 Android 9.0 音量调节 ADC 配置教程 在 RK3326 平台上实现 Android 9.0 的音量调节功能涉及多个层面的配置,包括硬件抽象层 (HAL) 和驱动程序的支持。以下是关于如何完成此任务的具体说明。 #### HAL 库支持 为了使音频设备能够正常工作,需要确保 HAL 层已经正确编译并部署到目标设备上。对于 RK3326 而言,其 HAL 文件路径可能类似于 `./out/target/product/rk3326/vendor/lib/hw/audio.primary.rk30board.so`[^1]。如果该文件不存在,则需重新构建项目以生成所需的 HAL 库。 将新生成的 HAL 库替换至设备中的对应位置: ```bash adb push audio.primary.rk30board.so /vendor/lib/hw/ ``` #### 设备树配置 音量调节通常依赖于特定的寄存器设置来控制模拟数字转换器 (ADC),这些设置可以通过修改设备树 (Device Tree, DTB) 来完成。具体操作如下: 1. 找到当前使用的设备树源码文件(通常是 `.dts` 文件)。例如,在 RK3326 上可能是 `rk3326-evb.dts`。 2. 添加或调整与 ES7210 或其他声卡芯片相关的节点定义。以下是一个示例片段: ```dts sound { compatible = "simple-audio-card"; simple-audio-card,name = "ES7210 Audio"; /* 定义输入输出端口 */ simple-audio-card,format = "i2s"; simple-audio-card,mclk-fs = <256>; /* 连接 CPU DAI 到 Codec */ simple-audio-card,cpu { sound-dai = <&i2s>; }; simple-audio-card,codec { sound-dai = <&es7210_codec>; // 声卡对应的 codec 名称 }; }; ``` 3. 编译更新后的设备树文件,并将其刷入设备中。 #### 驱动调试与错误排查 当遇到音量调节失败或其他问题时,可以按照以下方法进行排查: - **日志分析** 使用 ADB 工具捕获系统日志,重点关注音频子系统的消息输出: ```bash adb logcat | grep -i audio ``` 如果发现异常提示,比如找不到指定的 HAL 模块或者无法初始化某些资源,则表明可能存在未满足的依赖项。 - **权限验证** 确认应用程序具有访问麦克风和扬声器所需的所有必要权限。可以在应用清单文件 (`AndroidManifest.xml`) 中声明如下权限: ```xml <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> ``` - **参数校准** 对于基于 ADC 实现的功能来说,精确设定增益范围至关重要。通过实验确定最佳数值组合后写入固件代码里保存下来供后续调用即可。 --- ### 示例代码:动态改变媒体音量水平 下面给出一段用于演示如何编程方式更改全局音乐播放响度等级的例子: ```java import android.media.AudioManager; public class VolumeController { private AudioManager mAudioMgr; public void adjustVolume(int direction){ mAudioMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE); if(direction > 0){ mAudioMgr.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI); } else{ mAudioMgr.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值