Reference blog: Android native volume control
Reference blog: In depth understanding AudioService
1, Problem description
When the USB headset is not connected, the system volume can be set to the maximum value of 15. When the USB headset is connected, the system volume can only be set to 4
1, Cause analysis
(1) Android audio system sets different volume control ranges for different audio streams, presumably related to the range settings
But in the source code, the maximum value of stream music has been set to 15, mSafeMediaVolumeState = 10, and the safe volume has also been set to 10
Safe volume is configured in xml file
//AudioService.java mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver, Settings.Global.AUDIO_SAFE_VOLUME_STATE, SAFE_MEDIA_VOLUME_NOT_CONFIGURED)); ///////line284 /** Maximum volume index values for audio streams */ private 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 };
(2) Volume settings for USB Audio
You can see that USB audio is calculated according to MUSIC volume
//AudioService.java 6208 private int safeMediaVolumeIndex(int device) { if ((device & mSafeMediaVolumeDevices) == 0) { Slog.w(TAG,"SOLEN return MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]"); return MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]; } if (device == AudioSystem.DEVICE_OUT_USB_HEADSET) { Slog.w(TAG,"SOLEN mSafeUsbMediaVolumeIndex" + Integer.toHexString(mSafeUsbMediaVolumeIndex)); return mSafeUsbMediaVolumeIndex; } else { return mSafeMediaVolumeIndex; } } //AudioService.java 754 // relies on audio policy having correct ranges for volume indexes. mSafeUsbMediaVolumeIndex = getSafeUsbMediaVolumeIndex(); private int getSafeUsbMediaVolumeIndex() { // determine UI volume index corresponding to the wanted safe gain in dBFS int min = MIN_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]; int max = MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]; while (Math.abs(max-min) > 1) { int index = (max + min) / 2; float gainDB = AudioSystem.getStreamVolumeDB( AudioSystem.STREAM_MUSIC, index, AudioSystem.DEVICE_OUT_USB_HEADSET); if (Float.isNaN(gainDB)) { //keep last min in case of read error break; } else if (gainDB == SAFE_VOLUME_GAIN_DBFS) { min = index; break; } else if (gainDB < SAFE_VOLUME_GAIN_DBFS) { min = index; } else { max = index; } } return min * 10;
Modify the value of mSafeUsbMediaVolumeIndex to 150 directly, and solve the problem. Android audio system adds a precision design, which processes the volume by X10, 150 is actually 15, the maximum volume.