在车机 Audio 开发中,设置音量默认值是必要的,很多时候也需要定制化开发。还有很多场景需要设置音量的最大值和最小值问题,例如通话模式通常是禁止静音的,耳机模式调整到较大音量时开机后会恢复一个最大默认值等问题。而且通常情况下不通车型的默认值可能会不同,这篇文章就来看一下如何在一套代码中维护不同车型的默认音量。
一、系统默认音量
1、默认音量
源码位置:frameworks/base/media/java/android/media/AudioSystem.java
java
public static int[] DEFAULT_STREAM_VOLUME = new int[] {
4, // STREAM_VOICE_CALL
7, // STREAM_SYSTEM
5, // STREAM_RING
5, // STREAM_MUSIC
6, // STREAM_ALARM
5, // STREAM_NOTIFICATION
7, // STREAM_BLUETOOTH_SCO
7, // STREAM_SYSTEM_ENFORCED
5, // STREAM_DTMF
5, // STREAM_TTS
5, // STREAM_ACCESSIBILITY
5, // STREAM_ASSISTANT
};
2、 最大/小音量
源码位置**:**frameworks/base/services/core/java/com/android/server/audio/AudioService.java
java
/** 音频流的最大音量索引值 */
protected static int[] MAX_STREAM_VOLUME = new int[] {
5, // STREAM_VOICE_CALL
7, // STREAM_SYSTEM
7, // STREAM_RING
15, // STREAM_MUSIC
7, // STREAM_ALARM
7, // STREAM_NOTIFICATION
15, // STREAM_BLUETOOTH_SCO
7, // STREAM_SYSTEM_ENFORCED
15, // STREAM_DTMF
15, // STREAM_TTS
15, // STREAM_ACCESSIBILITY
15 // STREAM_ASSISTANT
};
/** 音频流的最小音量索引值 */
protected static int[] MIN_STREAM_VOLUME = new int[] {
1, // STREAM_VOICE_CALL
0, // STREAM_SYSTEM
0, // STREAM_RING
0, // STREAM_MUSIC
1, // STREAM_ALARM
0, // STREAM_NOTIFICATION
0, // STREAM_BLUETOOTH_SCO
0, // STREAM_SYSTEM_ENFORCED
0, // STREAM_DTMF
0, // STREAM_TTS
1, // STREAM_ACCESSIBILITY
0 // STREAM_ASSISTANT
};
3、默认值修改
虽然我们找到了默认值的定义位置,但是声音属性默认值最好不要在这里进行修改,否则可能修改无效。因为这两种音量属性被定义之后,还会在 AudioService 的构造方法中进行初始化。在此期间,之前定义的音量值会被覆盖掉。
java
public AudioService(Context context, AudioSystemAdapter audioSystem, SystemServerAdapter systemServer) {
......
int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1);
if (maxCallVolume != -1) {
MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxCallVolume;
}
int defaultCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_default", -1);
if (defaultCallVolume != -1 &&
defaultCallVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] &&
defaultCallVolume >= MIN_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = defaultCallVolume;
} else {
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] =
(MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] * 3) / 4;
}
int maxMusicVolume = SystemProperties.getInt("ro.config.media_vol_steps", -1);
if (maxMusicVolume != -1) {
MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxMusicVolume;
}
int defaultMusicVolume = SystemProperties.getInt("ro.config.media_vol_default", -1);
if (defaultMusicVolume != -1 &&
defaultMusicVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] &&
defaultMusicVolume >= MIN_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = defaultMusicVolume;
} else {
if (isPlatformTelevision()) {
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 4;
} else {
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 3;
}
}
int maxAlarmVolume = SystemProperties.getInt("ro.config.alarm_vol_steps", -1);
if (maxAlarmVolume != -1) {
MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM] = maxAlarmVolume;
}
int defaultAlarmVolume = SystemProperties.getInt("ro.config.alarm_vol_default", -1);
if (defaultAlarmVolume != -1 &&
defaultAlarmVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM]) {
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_ALARM] = defaultAlarmVolume;
} else {
// 默认值是7分中的6分(默认最大值),因此相应地缩放。
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_ALARM] =
6 * MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM] / 7;
}
int maxSystemVolume = SystemProperties.getInt("ro.config.system_vol_steps", -1);
if (maxSystemVolume != -1) {
MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM] = maxSystemVolume;
}
int defaultSystemVolume = SystemProperties.getInt("ro.config.system_vol_default", -1);
if (defaultSystemVolume != -1 && defaultSystemVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM]) {
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM] = defaultSystemVolume;
} else {
// 默认是使用maximum。
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM] = MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM];
}
......
}
以多媒体默认音量为例,我们可以看到,它最终的设置结果是最大音量的三分之一,即 15/3=5 格音量。
java
int defaultMusicVolume = SystemProperties.getInt("ro.config.media_vol_default", -1);
if (defaultMusicVolume != -1 &&
defaultMusicVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] &&
defaultMusicVolume >= MIN_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = defaultMusicVolume;
} else {
if (isPlatformTelevision()) {
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 4;
} else {
AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 3;
}
}
所以,它的修改方式应该是这样的:
java
//多媒体默认音量修改为10格
int defaultMusicVolume = SystemProperties.getInt("ro.config.media_vol_default", 10);
其实这里是系统一用来记录用户设置音量的,首先取出用户设置的音量,如果取出的值在最大值和最小值之间,直接使用该音量。否则设置最大音量的三分之一为默认音量。
一、自定义音量值
对于车机开发来说,为了方便维护我们也可以定义一套自定义音量值的 xml 文件。
1、配置默认值
通常情况下,需要在上面的文件中添加相关默认值属性。
config.xml
源码位置:/packages/services/Car/service/res/values/config.xml
XML
<integer name="mediaMaxVolume">20</integer>
<integer name="mediaMinVolume">5</integer>
<integer name="alarmMaxVolume">20</integer>
<integer name="alarmMinVolume">5</integer>
这里设置了多媒体的最大音量为 20,最小音量为 10。设置了闹钟的最小音量为 5。
2、初始化数据
CarAudioService
源码位置:/packages/services/Car/service/src/com/android/car/CarAudioService.java
java
public class CarAudioService extends ICarAudio.Stub implements CarServiceBase, PowerEventProcessingHandler {
......
private static final String MEDIA_MIN_VOLUME = "vendor.media.min.volume";
private static final String MEDIA_MAX_VOLUME = "vendor.media.max.volume";
private static final String ALARM_MIN_VOLUME = "vendor.alarm.min.volume";
private static final String ALARM_MAX_VOLUME = "vendor.alarm.max.volume";
private int mMediaMinVolume;
private int mMediaMaxVolume;
private int mAlarmMinVolume;
private int mAlarmMaxVolume;
@Override
public void init() {
......
synchronized (mImplLock) {
......
Resources res = mContext.getResources();
mMediaMinVolume = res.getInteger(R.integer.mediaMinVolume);
mMediaMaxVolume = res.getInteger(R.integer.mediaMaxVolume);
mAlarmMinVolume = res.getInteger(R.integer.alarmMinVolume);
mAlarmMaxVolume = res.getInteger(R.integer.alarmMaxVolume);
SystemProperties.set(MEDIA_MIN_VOLUME, String.valueOf(mMediaMinVolume));
SystemProperties.set(MEDIA_MAX_VOLUME, String.valueOf(mMediaMaxVolume));
SystemProperties.set(ALARM_MIN_VOLUME, String.valueOf(mAlarmMinVolume));
SystemProperties.set(ALARM_MAX_VOLUME, String.valueOf(mAlarmMaxVolume));
......
}
......
}
......
}
这里就是取出 xml 中的数据,存储到系统变量中,我们这里看一下存储方式。
SystemProperties
源码位置:/frameworks/base/core/java/android/os/SystemProperties.java
java
/**
* 提供对系统属性存储的访问权限。系统属性存储包含字符串键值对列表。
* 该类仅用于本地的系统属性。
*/
public class SystemProperties {
private static final boolean TRACK_KEY_ACCESS = false;
public static String get(@NonNull String key) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get(key);
}
public static String get(@NonNull String key, @Nullable String def) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get(key, def);
}
}
可以看到这就相当于一个用于存储系统属性的工具类。
3、获取数据
在上面的 AudioService 中可以使用这里存储的数据进行赋值,这样就使用了自定义数据。
java
private static final String MEDIA_MIN_VOLUME = "vendor.media.min.volume";
private static final String MEDIA_MAX_VOLUME = "vendor.media.max.volume";
private static final String ALARM_MIN_VOLUME = "vendor.alarm.min.volume";
private static final String ALARM_MAX_VOLUME = "vendor.alarm.max.volume";
private int mMediaMinVolume;
private int mMediaMaxVolume;
private int mAlarmMinVolume;
private int mAlarmMaxVolume;
mMediaMinVolume = SystemProperties.get(MEDIA_MIN_VOLUME);
mMediaMaxVolume = SystemProperties.get(MEDIA_MAX_VOLUME);
mAlarmMinVolume = SystemProperties.get(ALARM_MIN_VOLUME);
mAlarmMaxVolume = SystemProperties.get(ALARM_MAX_VOLUME);
4、定制设置
如果只有一组设置,直接使用上面的代码就可以了。但是如果当前有多个车型,且对音量的边界值设置还不一样,这就需要定制化设置了。例如我们有 xx01 和 xx02 两个车型,他们的定制化文件存放在 /device/xiaoxu/xx01 和 /device/xiaoxu/xx02 下。这里配置默认值需要覆盖上面的配置信息,所以需要添加 overlay 路径。
xx01
源码位置:/device/xiaoxu/xx01/overlay/packages/services/Car/service/res/values/config.xml
XML
<integer name="mediaMaxVolume">18</integer>
<integer name="mediaMinVolume">3</integer>
<integer name="alarmMaxVolume">18</integer>
<integer name="alarmMinVolume">3</integer>
xx02
源码位置:/device/xiaoxu/xx02/overlay/packages/services/Car/service/res/values/config.xml
XML
<integer name="mediaMaxVolume">22</integer>
<integer name="mediaMinVolume">7</integer>
<integer name="alarmMaxVolume">22</integer>
<integer name="alarmMinVolume">7</integer>
这样该文件就会覆盖上面的设置,而对于数值的初始化和获取方式与上面的相同,这里就不再重复添加。