The following describes how to adjust the volume:
Step 1. When you adjust the volume_up_key & volume_down_key operation on the machine, the system calls the handlekeyup & handlekeydown function in audiomanager. java. The handlekeydown function is used as an example:
1 Public void handlekeydown (keyevent event, int stream) {2 int keycode = event. getkeycode (); 3 Switch (keycode) {4 case keyevent. keycode_volume_up:/* keyevent in keyevent. define */5 case keyevent in Java. keycode_volume_down: 6 7 int flags = flag_show_ui | flag_vibrate; 8 9 If (musemastervolume) {10 adjustmastervolume (11 keycode = keyevent. keycode_volume_up12? Adjust_raise13: adjust_lower, 14 flags); 15} else {16 adjustsuggestedstreamvolume (17 keycode = keyevent. keycode_volume_up18? Adjust_raise19: adjust_lower, 20 stream, 21 flags); 22} 23 break; 24 ...... 25} 26}
Whether to enter the adjustmastervolume function is determined by the musemastervolume value, while the musemastervolume value is defined in the audiomanager constructor. The value is as follows: musemastervolume = mcontext. getresources (). getboolean (COM. android. internal. r. bool. config_usemastervolume), so first from the system configuration file config. search for the config_usemastervolume value in XML
<Bool name = "config_usemastervolume"> false </bool>
Therefore, the switch statement in handlekeydown will choose to enter the adjustsuggestedstreamvolume function.
1 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { 2 IAudioService service = getService(); 3 try { 4 if (mUseMasterVolume) { 5 service.adjustMasterVolume(direction, flags, mContext.getOpPackageName()); 6 } else { 7 service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, 8 mContext.getOpPackageName()); 9 }10 ... ...
11 }12 }
Step_2. In the adjustsuggestedstreamvolume function, the audioservice is first obtained through the binder mechanism, and the volume control process is transferred to audioservice. java.
1 Public void adjuststreamvolume (INT streamtype, int direction, int flags, 2 string callingpackage) {3 ...... 4/* when the volume is increased, if you want to exceed safemediavolume, the system will pop up a dialog box to confirm */5 If (Direction = audiomanager. adjust_raise) & 6! Checksafemediavolume (streamtypealias, aliasindex + step, device) {7 log. E (TAG, "adjuststreamvolume () safe volume index =" + oldindex); 8 mvolumepanel. postdisplaysafevolumewarning (flags); 9} else if (streamstate. adjustindex (Direction * step, device) {10 sendmsg (maudiohandler, 11 msg_set_device_volume,/* message value to be processed */12 sendmsg_queue, 13 device, 14 streamstate, 16 0); 17} 18} 19 int Index = mstreamstates [streamtype]. getindex (device); 20 sendvolumeupdate (streamtype, oldindex, index, flags);/* notifies the upper-layer Update volume */21}
In adjuststreamvolume, events that adjust the volume are added to the Message Queue sendmsg_quene through sendmsg. When this message is found in the round, the system calls the handlemessage function to process the message, the message corresponding to this field is msg_set_device_volume.
1 public void handleMessage(Message msg) { 2 3 switch (msg.what) { 4 5 case MSG_SET_DEVICE_VOLUME: 6 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1); 7 break; 8 9 case MSG_SET_ALL_VOLUMES:10 setAllVolumes((VolumeStreamState) msg.obj);11 break;12 13 ... ... 14 }15 }
It can be found that when MSG. What = msg_set_device_volume, it will go to the setdevicevolume function and continue the analysis:
1 private void setDeviceVolume(VolumeStreamState streamState, int device) { 2 3 // Apply volume 4 streamState.applyDeviceVolume(device); 5 6 // Apply change to all streams using this one as alias 7 ... ... 8 9 // Post a persist volume msg10 ... ... 11 }
Applydevicevolume is to set the volume to the corresponding device and continue the analysis:
1 public void applyDeviceVolume(int device) { 2 int index; 3 if (isMuted()) { 4 index = 0; 5 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && 6 mAvrcpAbsVolSupported) { 7 index = (mIndexMax + 5)/10; 8 } else { 9 index = (getIndex(device) + 5)/10;10 }11 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);12 }
Volumeindex is the subscript of the position in which the volume is located when the volume is adjusted on the UI. In audioservice. Java, the max-index corresponding to each audio stream is defined. In audiomanager. Java, the default index of each audio stream is defined after the first flash.
Step 3. After obtaining the index of the volume subscript, call the setstreamvolumeindex function in audiosystem. Java to obtain the magnification of the volume. Use the JNI layer to call setstreamvolumeindex in the audiosystem. cpp file.
1 status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,2 int index,3 audio_devices_t device)4 {5 const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();6 if (aps == 0) return PERMISSION_DENIED;7 return aps->setStreamVolumeIndex(stream, index, device);8 }
The setstreamvolumeindex function is relatively simple. You can use strongpointer to establish a connection with audiopolicyservice and move the setstreamvolumeindex operation in audiosystem to APs. Next, go to the setstreamvolumeindex in the audiopolicyservice. cpp file to continue the analysis:
1 status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream, 2 int index, 3 audio_devices_t device) 4 { 5 ... ... 6 if (mpAudioPolicy->set_stream_volume_index_for_device) { 7 return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy, 8 stream, 9 index,10 device);11 } else {12 return mpAudioPolicy->set_stream_volume_index(mpAudioPolicy, stream, index);13 }14 }
Step_4.audiopolicyservice.cpp is used as the BN end, and the corresponding BP end is audiopolicymanagerbase. cpp. In the if statement of the current function, determine whether the setstreamvolumeindexfordevice function exists in the audiopolicymanagerbase. cpp file. If the condition is true, setstreamvolumeindexfordevice is selected as the function entry; otherwise, setstreamvolumeindex is selected as the function. Now go to the audiopolicymanagerbase. cpp file to complete the final analysis:
1 status_t AudioPolicyManagerBase::setStreamVolumeIndex(AudioSystem::stream_type stream, 2 int index, 3 audio_devices_t device) 4 { 5 ... ... 6 // compute and apply stream volume on all outputs according to connected device 7 status_t status = NO_ERROR; 8 for (size_t i = 0; i < mOutputs.size(); i++) { 9 audio_devices_t curDevice =10 getDeviceForVolume(mOutputs.valueAt(i)->device());11 if ((device == AUDIO_DEVICE_OUT_DEFAULT) || (device == curDevice)) {12 status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);13 if (volStatus != NO_ERROR) {14 status = volStatus;15 }16 }17 }18 return status;19 }
Continue to call the checkandsetvolume function:
1 status_t audiopolicymanagerbase: checkandsetvolume (INT stream, 2 int index, 3 audio_io_handle_t output, 4 audio_devices_t device, 5 Int delayms, 6 bool force) 7 {8 9 // do not change actual stream volume if the stream is muted10 ...... 11 // do not change in call volume if Bluetooth is connected and vice versa12 ...... 13 audio_devices_t checkeddevice = (device = audio_device_none )? Moutputs. valuefor (output)-> device (): device; 14 float volume = computevolume (stream, index, checkeddevice); 15 16 ...... 17 mpclientinterface-> setstreamvolume (audiosystem: stream_type) stream, volume, output, delayms);/* apply the obtained volume to the corresponding output */18}
In checkandsetvolume, we can know that volume is obtained through computevolume. Continue the following analysis:
float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_devices_t device){ ... ... volume = volIndexToAmpl(device, streamDesc, index); ... ... return volume;}
Finally, volindextoampl is reached. From the function name, we can know that the function is used to obtain the volume magnification through volindex.
float AudioPolicyManagerBase::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, int indexInUi){ device_category deviceCategory = getDeviceCategory(device); const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory]; // the volume index in the UI is relative to the min and max volume indices for this stream type int nbSteps = 1 + curve[VOLMAX].mIndex - curve[VOLMIN].mIndex; int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin); // find what part of the curve this index volume belongs to, or if it‘s out of bounds int segment = 0; if (volIdx < curve[VOLMIN].mIndex) { // out of bounds return 0.0f; } else if (volIdx < curve[VOLKNEE1].mIndex) { segment = 0; } else if (volIdx < curve[VOLKNEE2].mIndex) { segment = 1; } else if (volIdx <= curve[VOLMAX].mIndex) { segment = 2; } else { // out of bounds return 1.0f; } // linear interpolation in the attenuation table in dB float decibels = curve[segment].mDBAttenuation + ((float)(volIdx - curve[segment].mIndex)) * ( (curve[segment+1].mDBAttenuation - curve[segment].mDBAttenuation) / ((float)(curve[segment+1].mIndex - curve[segment].mIndex)) ); float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 ) return amplification;}
Curve indicates the volume curve of the audio stream (such as system, music, alarm, and ring & TTS) played by a device (such as speaker and headset & earpiece, finally, decibles & amplification is the value we need. decibles represents the DB value corresponding to a certain syllable, while amplification is the volume magnification obtained from the DB value conversion. This completes the entire volume adjustment process, and the specific computing and analysis will be carried on later.
Volume Adjustment Process