Android12 rk3588解决静音后按音量减声音恢复,但界面显示静音的问题

问题:算力主机项目(RK3588s Android 12),在播放页面按静音键,静音成功后,按音量减,界面显示静音,但有声音输出。但是按音量加,有声音输出,界面不显示静音。

目标:使得静音后按音量减可以恢复ui,界面不显示静音。

原因:可能在某处会有静音后的音量调整逻辑判断,在静音后按音量加的时候,恢复了声音以及重新设置了ui,但是在静音后按音量减的时候只恢复了声音没有恢复ui。

分析过程:

从抓取日志开始入手,首先复现一次在静音后按音量加的操作,将抓取的日志导出

可以看到在按下静音减后STREAM_MUSIC被设置为了静音,并且当前活跃的音频流是STREAM_MUSIC,按下静音是音量为7,随后按下音量加。

可以看到修改后的音量为8,并且日志表明STREAM_MUSIC被解除静音了。

复现一次在静音后按音量减的操作,将抓取的日志导出

可以看到静音时音量为7,按下音量减键后

音量被设置为了6,但是没有打印出解除静音的日志信息,此时屏幕上的音量条还是静音图标,但是声音却恢复了。所以必定是在静音后按音量加减有不同的操作,并且打印出解除静音的位置应该会有关于ui绘制的内容。然后直接在framework中搜索writeEvent mute_changed STREAM_MUSIC

发现这句话在EventsTest.java的这个列表中被定义,随后检索这句话的句柄,检查这句信息在哪里被调用了。发现打印出解除静音的位置是在updateStreamMuteW()函数,这个函数在VolumeDialogControllerImpl.java文件中,这个文件专门处理ui相关的内容会判断是否显示ui。这个函数接收音频流类型和静音状态,会根据传入的参数进行判断静音状态是否改变,最终会返回一个bool值。

接下来要找到调用这个函数的位置

可以看到上面的函数在onReceive()中被调用,这是一个用于接收广播事件的方法。上面函数被调用的分支是静音修改,调用后返回了一个change,这个变量决定了是否更新ui的状态。

如果change为真表示ui状态需要修改,会调用onStateChange函数,最终会调用VolumeDialogImpl.java文件中的回调函数onStateChangedH,最终在这个函数中完成ui状态的修改。

所以修改ui的位置已经找到了,现在的目标就是找到调用onReceive()函数的位置,即发送静音状态修改广播的位置。查找发送广播的位置可以搜索action,STREAM_MUTE_CHANGED_ACTION。

然后发现发送广播的位置在AudioService.java中的mute函数中。

在change为真的时候会发送静音修改的广播,state为false时change会被修改为真。关于发送广播一般过程是new一个Intent,用action初始化,这里为EXTRA_VOLUME_STREAM_TYPE和EXTRA_STREAM_VOLUME_MUTED设置为mStreamType和state,原因是在onReceive()中处理这个action时要获取这两个变量的参数。最后sendBroadcast发送广播就行了。

所以现在要找到调用mute的地方,并且那个位置是跟静音后的音量修改有关。

最终发现调用mute的位置是

这个函数比较长,主要处理音量调整的相关内容

调用mute的位置在这个else if分支中,表示不是全音量设备且调整了音量索引值,或者是静音状态,首先处理已被静音后的修改,如果是音量加,就调用mute发送广播修改ui,同时在mute’中也用了sendMsg恢复音量。如果是音量减就发送解除静音的消息。

       以上就是问题追踪的流程了,虽然这部分调用关系并不是特别复杂,但是在追踪代码的过程中并不是特别轻松,因为之前对音频不了解,以及Android广播,JNI,音量曲线,音量管理这些概念不是很清楚,导致阅读这些代码比较困难,在音频处理的过程中大量使用了回调,JNI,binder,AIDL,广播这些方法,导致摸清调用关系花了很久。

修改方案:

上面的代码在静音后的音量减操作中缺少了发送广播更新ui的操作,所以解决问题的方法就是加上发送广播的代码。

False表示解除静音。