系统音量相关总结

修改系统默认音量值

  • 路径:framework/base/media/java/android/media/AudioSystem.java

    public static int[] DEFAULT_STREAM_VOLUME = new int[] {
          4,  // STREAM_VOICE_CALL
          7,  // STREAM_SYSTEM
          5,  // STREAM_RING
         // MStar Android Patch Begin
         //  this setting is subject to MAX_STREAM_VOLUME[STREAM_MUSIC] = 100 (in AudioService.java)
          35, // STREAM_MUSIC
         // MStar Android Patch End
          6,  // STREAM_ALARM
          5,  // STREAM_NOTIFICATION
          7,  // STREAM_BLUETOOTH_SCO
          7,  // STREAM_SYSTEM_ENFORCED
          11, // STREAM_DTMF
          11,  // STREAM_TTS
          15   //STREAM_MUSIC_SUB
      };
    

    由上可以看出,系统的各个通道的默认音量值会在这里定义,但是需要修改默认的音量值,仅仅在这里修改无法改变的,因为系统在其他地方默认的音量值进行了补充修改。具体可以看下面的代码:

  • 路径:framework/base/services/core/java/com/android/server/audio/AudioService

    /** @hide */
     public AudioService(Context context) {
         //省略部分代码
         int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
                 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
         if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
             MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
             AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
         }
         maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
                 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
         if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
             MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
             AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
         }
     }
    

    上面可以看出,在获取到系统的最大音量值的地方,系统队默认的音量值进行了重新定义。因此,如果需要对音量进行自定义修改,需要在这里进行适当的控制。

修改系统音量极值

  • 路径:framework/base/services/core/java/com/android/server/audio/AudioService
  1. 最大值定义代码

    /** Maximum volume index values for audio streams */
        private static int[] MAX_STREAM_VOLUME = new int[] {
            // MStar Android Patch Begin
            100,  // STREAM_VOICE_CALL
            100,  // STREAM_SYSTEM
            100,  // STREAM_RING
            100,  // STREAM_MUSIC
            100,  // STREAM_ALARM
            100,  // STREAM_NOTIFICATION
            100,  // STREAM_BLUETOOTH_SCO
            100,  // STREAM_SYSTEM_ENFORCED
            100,  // STREAM_DTMF
            100,  // STREAM_TTS
            100   // STREAM_MUSIC_SUB
            // MStar Android Patch End
        };
    
  2. 最小值定义代码

    /** Minimum volume index values for audio streams */
        private static int[] MIN_STREAM_VOLUME = new int[] {
            // MStar Android Patch Begin
            0,  // STREAM_VOICE_CALL
            // MStar Android Patch End
            0,  // STREAM_SYSTEM
            0,  // STREAM_RING
            0,  // STREAM_MUSIC
            0,  // STREAM_ALARM
            0,  // STREAM_NOTIFICATION
            // MStar Android Patch Begin
            0,  // STREAM_BLUETOOTH_SCO
            // MStar Android Patch End
            0,  // STREAM_SYSTEM_ENFORCED
            0,  // STREAM_DTMF
            0,   // STREAM_TTS
            0   //STREAM_MUSIC_SUB
        };
    

    上面定义了系统的各个通道的最大音量值和最小音量值。注意这里的最大最小只是划分的等级,如果划分等级变大了,单位调节音量时候,用户的感知就变小了,反之亦然。同时经过编译测试发现音量条会同步极值发生变化。

修改系统音量的两个方法说明

  • 路径:framework/base/services/core/java/com/android/server/audio/AudioService
  1. 渐进式:adjustStreamVolume
    根据音量键进行声音的递增和递减

  2. 跳跃式:setStreamVolume
    根据音量值,直接可以设置音量的大小

功放音量约束实现

根据公司的需求,在设置电视外放的功放时候,要求音量极值100情况下65为最大,否则电视外放会出现破音、失真情况。这种情况下,我们需要监控所有的音量控制接口,使得其音量控制均系统程序控制内。第三方app也要受到约束。为此,我们需要找到音量控制相对应的aidl文件,根据aidl文件找到其映射的c++文件,直接在底层c++修改约束条件。

  • 在设置音量值,我们会首先回去到AudioManager服务,这个服务在安卓系统启动的时候,已经通过system_server注册过。在AudioManager中的控制音量方法代码如下:
  1. 渐进式:

    public void adjustStreamVolume(int streamType, int direction, int flags) {

    IAudioService service = getService();
    try {
        service.adjustStreamVolume(streamType, direction, flags,
                getContext().getOpPackageName());
    } catch (RemoteException e) {
        Log.e(TAG, "Dead object in adjustStreamVolume", e);
    }
    

    }

  2. 跳跃式:

    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);
    }
    

    }

由上面可以看出,其最终是通过从Server端获取到的IAudioService(service)对象,调用其声的aidl接口方法。

  • IAudioService的aidl接口文件

    interface IAudioService {
    
        oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
                String callingPackage, String caller);
    
        void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage);
    
        void setStreamVolume(int streamType, int index, int flags, String callingPackage);
    
        //省略部分
    }
    

    Client端根据定义好的aidl文件,对应Server端的c++文件,通过binder机制远程调用,jni实现底层音量的控制。
    在查找过程中发现有些文件方法没有写全,是因为在IAudioService.aidl文件中,import了其他的aidl文件,因此这里的aidl文件是总文件,所以我们根据这个aidl文件,找到对应的c++文件即可。
    根据其定义native方法的包名、类名,可以对应拼出其jni的实现文件名为android_media_AudioSystem.cpp

  • 音量控制jni文件android_media_AudioSystem.cpp,在gMethods中,定义了方法的一一映射关系

    static JNINativeMethod gMethods[] = {
        //省略部分
        {"setParameters",        "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
        {"initStreamVolume",    "(III)I",   (void *)android_media_AudioSystem_initStreamVolume},
        {"setStreamVolumeIndex","(III)I",   (void *)android_media_AudioSystem_setStreamVolumeIndex},
        //省略部分
    }
    
  • 修改C++层其最终调用的方法

    static jint
    android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
                                                   jobject thiz,
                                                   jint stream,
                                                   jint index,
                                                   jint device)
    {
    
        //new code for restraining volume
        index = jint(index * 65 / 100);
    
        return (jint) check_AudioSystem_Command(
                AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
                                                  index,
                                                  (audio_devices_t)device));
    }
    

    在这里我们增加约束条件即可实现从最底层修改声音的控制,无论是系统还是第三方应用均会受到制约

修改音量条

  • 路径:framework/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java

  • 减少音量通道

    addRow(AudioManager.STREAM_RING,
                R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true);
    addRow(AudioManager.STREAM_MUSIC,
            R.drawable.ic_volume_hint, R.drawable.ic_volume_hint, true);
    addRow(AudioManager.STREAM_ALARM,
            R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, false);
    addRow(AudioManager.STREAM_VOICE_CALL,
            R.drawable.ic_volume_voice, R.drawable.ic_volume_voice, false);
    addRow(AudioManager.STREAM_BLUETOOTH_SCO,
            R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false);
    addRow(AudioManager.STREAM_SYSTEM,
            R.drawable.ic_volume_system, R.drawable.ic_volume_system_mute, false);
    

addRow方法实现了音量条下多通道声音控制的加载

  • 音量条样式自定义

    修改对应文件加下res/layout布局文件,在make之前,先make res一下,将res资源更新,否则会找不到资源,出现编译错误

  • 修改音量动画

    修改其文件夹中的VolumeDialogMotion.java文件即可

  • 监测控制音量按键

    其文件夹下的VolumeDialogController实现了广播的监听,修改这里即可

  • 修改音量策略(增加音量跳出静音模式等)

    修改文件夹下的VolumeDialogComponent文件中的VolumePolicy即可

坚持原创技术分享,您的支持将鼓励我继续创作!