Preface:
Absolute volume: The mobile phone does not process the volume, only tells the headphones the current volume, and the headphones end processes the volume.
Relative volume: On the mobile phone, the headset is not sure whether it is the default maximum, or whether there is a default volume or the absolute volume value set previously.
The volume of the mobile phone converts the absolute volume. There will be a calculation process here, which roughly means that the mobile phone side calculates the percentage of the current volume and maximum volume and then sets it to the headset. The headset end receives the percentage to process. Otherwise, the volume range of each phone is different, and it will be difficult to adapt without normalization.
When the volume is adjusted by the volume button, it will be distributed through the input event, and the input will distribute the event to the mediation. The mediasession calls the audiomanager's adjustStreamVolume to adjust the volume.
When adjusting the volume by dragging the volume bar, the settings app calls the audiomanager's setStreamVolume to adjust the volume.
AdjustStreamVolume and setStreamVolume are similar to those of setStreamVolume. Next, only look at setStreamVolume.
setStreamVolume call
// frameworks/base/media/java/android/media/ public void setStreamVolume(int streamType, int index, int flags) { final IAudioService service = getService(); try { (streamType, index, flags, getContext().getOpPackageName()); // The audiomanager calls the audioservice's setStreamVolume } catch (RemoteException e) { throw (); } }
Audioservice calling process:
// frameworks/base/services/core/java/com/android/server/audio/ private void setStreamVolume(int streamType, int index, int flags, String callingPackage, String caller, int uid, boolean hasModifyAudioSettings) { ensureValidStreamType(streamType); int streamTypeAlias = mStreamVolumeAlias[streamType]; VolumeStreamState streamState = mStreamStates[streamTypeAlias]; inal int device = getDeviceForStream(streamType); // Get the device corresponding to streamType int oldIndex; synchronized (mSafeMediaVolumeStateLock) { // reset any pending volume command mPendingVolumeCommand = null; oldIndex = (device); = index; index = rescaleIndex(index * 10, streamType, streamTypeAlias); // Set absolute volume if (streamTypeAlias == AudioSystem.STREAM_MUSIC && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) { (index / 10); } if (streamTypeAlias == AudioSystem.STREAM_MUSIC) { setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags); // This is related to HDMI, don't worry } flags &= ~AudioManager.FLAG_FIXED_VOLUME; if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) { flags |= AudioManager.FLAG_FIXED_VOLUME; // volume is either 0 or max allowed for fixed volume devices if (index != 0) { if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE && (device)) { index = safeMediaVolumeIndex(device); } else { index = (); } } } if (!checkSafeMediaVolume(streamTypeAlias, index, device)) { (flags); // This should be a safety reminder, such as a reminder that excessive volume damages hearing mPendingVolumeCommand = new StreamVolumeCommand(streamType, index, flags, device); } else { onSetStreamVolume(streamType, index, flags, device, caller, hasModifyAudioSettings); // Call onSetStreamVolume to set the volume index = mStreamStates[streamType].getIndex(device); } } sendVolumeUpdate(streamType, oldIndex, index, flags, device); }
The role of onSetStreamVolume and sendVolumeUpdate:
onSetStreamVolume -> Set the volume to the bottom and handle some mute logic.
sendVolumeUpdate -> Notify ui to update volume value
Here is a process to automatically mute when the volume is set to 0:
// frameworks/base/services/core/java/com/android/server/audio/ private void onSetStreamVolume(int streamType, int index, int flags, int device, String caller, boolean hasModifyAudioSettings) { final int stream = mStreamVolumeAlias[streamType]; setStreamVolumeInt(stream, index, device, false, caller, hasModifyAudioSettings); // Set the volume to the bottom // setting volume on ui sounds stream type also controls silent mode if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || (stream == getUiSoundsStreamType())) { int ringerMode = getNewRingerMode(stream, index, flags); // Get ringmode miuiRingerMode = (mContext, miuiRingerMode); // Get ringmode setRingerMode(ringerMode, TAG + ".onSetStreamVolume", false /*external*/); // Set ringmode } } private int getNewRingerMode(int stream, int index, int flags) { if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || (stream == getUiSoundsStreamType())) { int newRingerMode; if (index == 0) { // If the set volume is 0 // If there is vibration, set ringmode to vibration mode. Otherwise, determine whether volumeDownToEnterSilent decides to set mute or not to mute newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE : ? AudioManager.RINGER_MODE_SILENT : AudioManager.RINGER_MODE_NORMAL; } else { newRingerMode = AudioManager.RINGER_MODE_NORMAL; // If the volume is not 0, ringmode is set to non-mute } return newRingerMode; } return getRingerModeExternal(); }
Set absolute volume: postSetAvrcpAbsoluteVolumeIndex
// frameworks/base/services/core/java/com/android/server/audio/ void postSetAvrcpAbsoluteVolumeIndex(int index) { sendIMsgNoDelay(MSG_I_SET_AVRCP_ABSOLUTE_VOLUME, SENDMSG_REPLACE, index); } // Receive the message MSG_I_SET_AVRCP_ABSOLUTE_VOLUME, call (msg.arg1); // frameworks/base/services/core/java/com/android/server/audio/ synchronized void setAvrcpAbsoluteVolumeIndex(int index) { (index); }
Bluetooth side absolute volume processing:
// vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/ public void setAvrcpAbsoluteVolume(int volume) { if (() != null) { ().sendVolumeChanged(volume); return; } if(()) { VolumeManagerIntf mVolumeManager = (); (volume); return; } synchronized(mBtAvrcpLock) { if (mAvrcp_ext != null) { mAvrcp_ext.setAbsoluteVolume(volume); return; } if (mAvrcp != null) { (volume); } } } // vendor/qcom/opensource/commonsys/bluetooth_ext/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java public void setAbsoluteVolume(int volume) { Message msg = (MSG_SET_ABSOLUTE_VOLUME, volume, 0); (msg); } Received a messageMSG_SET_ABSOLUTE_VOLUMEAfter that, call as follows case MSG_SET_ABSOLUTE_VOLUME: { int avrcpVolume = convertToAvrcpVolume(msg.arg1); ...... } // Calculate avrcpVolumeprivate int convertToAvrcpVolume(int volume) { if(mAudioStreamMax == 150) { return (int) ((double) volume*AVRCP_MAX_VOL/mAudioStreamMax); } return (int) ((double) volume*AVRCP_MAX_VOL/mAudioStreamMax); }
From here, we can see that the volume transmitted to the headphones on the Bluetooth side is actually a percentage.
The process of switching from relative volume to absolute volume:
The Bluetooth APP has a NotificationReceiver. When the absolute volume switch changes, the NotificationReceiver will receive the message and then do the following processing:
private class NotificationReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { if(ABS_VOLUME_ACTION.equals(())) { handleDeviceAbsVolume(mac, value); } } } // handleDeviceAbsVolumeWill do the corresponding processing,Send the volume value to the headset side。
Here, log printing will be performed every time you switch, log mask:handleDeviceAbsVolume|setVolumeNative
After switching, the sound playback will be called to checkAndSetVolume to set the volume value to the maximum to ensure that there is no volume processing on the phone.
Switching from absolute volume to relative volume:
Like above, the Bluetooth APP NotificationReceiver will receive a message that the absolute volume switch is turned off and then send the message to the headset. Then the audio side will be called to set the volume of the stream.
log mask: handleDeviceAbsVolume|setStreamVolume
After switching, the playback sound will be called to checkAndSetVolume to set the volume value to the current actual volume value.
Summarize
This is the article about absolute volume and relative volume settings in Android. For more related content on Android, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!