Android 4.4 볼륨 조정 프로세스 분석
출처 : http://www.cnblogs.com/Peter-Chen/p/3856411.html
출처 : http://www.cnblogs.com/Peter-Chen/p/3859498.html
Android Audio의 최근 작업에서는 Volume_Up_Key 및 Volume_Down_key가 조정되었을 때 Spearker 또는 헤드셋의 음악 규모 당 감쇠가 약 3db가된다는 요구가있었습니다. 따라서 Source Insight를 사용하여 Android 소스 코드의 볼륨 제어 흐름을 분석하십시오. 오류가있는 경우 수정하십시오. 감사합니다!
다음은 볼륨을 조정하는 프로세스입니다.
Step_1. 먼저 시스템의 Volume_Up_Key & Volume_Down_Key 연산을 조정하면 시스템이 AudioManager.java의 handleKeyUp & handleKeyDown 함수를 호출합니다. handleKeyDown 함수를 예로 들어 보겠습니다.
1 public void handleKeyDown(KeyEvent event, int stream) { 2 int keyCode = event.getKeyCode(); 3 switch (keyCode) { 4 case KeyEvent.KEYCODE_VOLUME_UP: /*KeyEvent 在KeyEvent.java中定义*/ 5 case KeyEvent.KEYCODE_VOLUME_DOWN: 6 7 int flags = FLAG_SHOW_UI | FLAG_VIBRATE; 8 9 if (mUseMasterVolume) { 10 adjustMasterVolume( 11 keyCode == KeyEvent.KEYCODE_VOLUME_UP 12 ? ADJUST_RAISE 13 : ADJUST_LOWER, 14 flags); 15 } else { 16 adjustSuggestedStreamVolume( 17 keyCode == KeyEvent.KEYCODE_VOLUME_UP 18 ? ADJUST_RAISE 19 : ADJUST_LOWER, 20 stream, 21 flags); 22 } 23 break; 24 ... ... 25 } 26 }
상기 입력 여부 adjustMasterVolume 의해 기능 mUseMasterVolume의 값을 결정하고 다음 :. MUseMasterVolume mContext.getResources = ()으로 getBoolean 값의 크기의 값을 mUseMasterVolume AudioManager 생성자를 정의 (com.android.internal.R. bool.config_useMasterVolume) 먼저 구성 파일의 Config.xml 시스템에서 크기 config_useMasterVolume 값을 찾는다
<bool name = "config_useMasterVolume"> false </ bool>
따라서 handleKeyDown switch 문은 adjustSuggestedStreamVolume 함수 를 입력하도록 선택 합니다.
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 : adjustSuggestedStreamVolume 함수에서, 먼저 AudioService가 바인더 메커니즘을 통해 얻어지고 볼륨 제어 프로세스가 AudioService.java로 전달됩니다.
1 public void adjustStreamVolume(int streamType, int direction, int flags, 2 String callingPackage) { 3 ... ... 4 /*音量调大时,若要超过SafeMediaVolume时,系统会弹出对话框给予确认*/ 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值*/ 12 SENDMSG_QUEUE, 13 device, 14 0, 15 streamState, 16 0); 17 } 18 } 19 int index = mStreamStates[streamType].getIndex(device); 20 sendVolumeUpdate(streamType, oldIndex, index, flags); /*通知上层更新Volume*/ 21 }
adjustStreamVolume에 의해 것이다 sendMsg는 메시지가 휠을 찾게되면 볼륨 이벤트 메시지 큐 SENDMSG_QUENE에 첨가하는 방법을 조절하는 기능을 처리 할 시스템의 경우 해당 메시지 MSG_SET_DEVICE_VOLUME 들어 handleMessage 메시지를 호출한다.
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 }
그것을 발견 할 수있는 경우 msg.what = MSG_SET_DEVICE_VOLUME는 setDeviceVolume 함수로 분석을 계속하는 경우 :
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 msg 10 ... ... 11 }
applyDeviceVolume은 볼륨 Volume을 해당 장치 Device로 설정하고 분석을 계속합니다.
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는 UI 볼륨을 조정할 때 볼륨이 위치한 위치의 인덱스입니다. 각 오디오 스트림의 대응하는 최대 인덱스는 AudioService.java에 정의되어있어, 최초의 플래시 후의 각 오디오 스트림의 디폴트의 Index는 AudioManager.java로 정의되고 있습니다.
Step_3이 시점에서 볼륨의 첨자 인덱스를 가져오고 AudioSystem.java의 setStreamVolumeIndex 함수를 호출하여 현재 사운드 볼륨의 확대율을 얻습니다. JNI 레이어를 통해 AudioSystem.cpp 파일의 setStreamVolumeIndex로 호출됩니다.
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 }
setStreamVolumeIndex 기능 완료 AP를 움직 setStreamVolumeIndex AudioSystem의 동작에 의해 StrongPointer AudioPolicyService 접촉을 확립 비교적 간단하다. 다음은 AudioPolicyService.cpp 파일의 setStreamVolumeIndex로 이동하여 분석을 계속 진행합니다.
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는 bn으로 사용되며 해당 bp는 AudioPolicyManagerBase.cpp입니다. 은 if 문 현재 함수 거기 setStreamVolumeIndexForDevice 기능 AudioPolicyManagerBase.cpp 파일, 설정 한 조건이 유입 단부의 함수로서 setStreamVolumeIndexForDevice를 선택할지 여부를 결정하는 상기 입구의 함수로서 다르게 선택 setStreamVolumeIndex한다. 이제 AudioPolicyManagerBase.cpp에 파일을 입력하여 최종 분석을 완료하십시오.
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 }
checkAndSetVolume 함수를 계속 호출합니다.
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 muted 10 ... ... 11 // do not change in call volume if bluetooth is connected and vice versa 12 ... ... 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);/*将得到的volume应用到对应的output中*/ 18 }
checkAndSetVolume에서 볼륨이 computeVolume을 통해 얻어지는 것을 볼 수 있습니다. 분석을 계속하십시오.
float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_devices_t device) { ... ... volume = volIndexToAmpl(device, streamDesc, index); ... ... return volume; }
마지막으로 마지막 volIndexToAmpl에 도달하면 함수 이름에서 함수의 역할이 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; }
곡선 장비를 나타내고 (예를 들어, 스피커, 헤드셋 및 이어폰)의 오디오 스트림 (예를 들면, SYSTEM, MUSIC, 알람, 고리 재생 TTS 등 ) 부피 곡선, 최종적 시빌 및 증폭 우리 항 필요한 값 (A)의 상기 시빌 대신하여 인 음절은 dB 값에 해당하며 증폭은 dB 값을 변환하여 얻은 볼륨 증폭입니다. 이 방법으로 전체 볼륨 조정 프로세스가 완료 되더라도 특정 계산이 나중에 분석됩니다.
전에 조정 과정 분석 (a)는 안드로이드 4.4 볼륨이 이미 볼륨 컨트롤의 분석의 간단한 과정을 가지고, 다음은 오늘 다음 볼륨의 크기를 계산하는 방법을 분석하기 위해 계속하고 싶습니다. 그들의 매우 파일 재생 볼륨의 임의의 고정 된 크기를 갖는다 Volume_Max 들어 AudioPolicyManagerBase.cpp 파일로 인식되도록 Volume_Max κ의 승산 계수 (0≤κ≤1)에 기초하여, 볼륨 제어 등.
이제 AudioPolicyManagerBase.cpp에서 volIndexToAmpl 함수를 분석하십시오. volIndexToAmpl의 기능은 다음과 같이 정의됩니다.
1 float AudioPolicyManagerBase::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, 2 int indexInUi) 3 { 4 device_category deviceCategory = getDeviceCategory(device); 5 const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory]; 6 7 // the volume index in the UI is relative to the min and max volume indices for this stream type 8 int nbSteps = 1 + curve[VOLMAX].mIndex - 9 curve[VOLMIN].mIndex; 10 int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) / 11 (streamDesc.mIndexMax - streamDesc.mIndexMin); 12 13 // find what part of the curve this index volume belongs to, or if it's out of bounds 14 int segment = 0; 15 if (volIdx < curve[VOLMIN].mIndex) { // out of bounds 16 return 0.0f; 17 } else if (volIdx < curve[VOLKNEE1].mIndex) { 18 segment = 0; 19 } else if (volIdx < curve[VOLKNEE2].mIndex) { 20 segment = 1; 21 } else if (volIdx <= curve[VOLMAX].mIndex) { 22 segment = 2; 23 } else { // out of bounds 24 return 1.0f; 25 } 26 27 // linear interpolation in the attenuation table in dB 28 float decibels = curve[segment].mDBAttenuation + 29 ((float)(volIdx - curve[segment].mIndex)) * 30 ( (curve[segment+1].mDBAttenuation - 31 curve[segment].mDBAttenuation) / 32 ((float)(curve[segment+1].mIndex - 33 curve[segment].mIndex)) ); 34 35 float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 ) 36 37 return amplification; 38 }
이 코드 섹션에는 주로 다음과 같은 7 가지 변수가 있습니다.
1. deviceCategory : Android 시스템에 DEVICE_CATEGORY_HEADSET, DEVICE_CATEGORY_SPEAKER & DEVICE_CATEGORY_EARPIECE의 세 가지 유형의 기기가 있습니다. 현재 Speaker를 사용하여 오디오 스트림을 재생하는 경우 deviceCategory는 DEVICE_CATEGORY_SPEAKER에 해당합니다.
2. 곡선 : 부피 곡선은 모두 및 DEVICE_CATEGORY Audio_Stream 의해 결정된다 일치하는 모든 종류의 수 sVolumeProfiles는 에 행렬을 수득 Audio_Stream = AUDIO_STREAM_MUSIC 및 device_Category = DEVICE_CATEGORY_SPEAKER 예,이 곡선 sSpeakerMediaVolumeCurve에 대응하는 양이며;
sSpeakerMediaVolumeCurve : (수치 계산의 예로이 볼륨 커브를 사용)
1 const AudioPolicyManagerBase::VolumeCurvePoint 2 AudioPolicyManagerBase::sSpeakerMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = { 3 {1, -59.1f}, {20, -48.3f}, {60, -24.4f}, {100, 0.0f} 4 };
SSpeakerMediaVolumeCurve 어레이 각각 네 부분으로, 20 ~ 60 20 ~ 60 1 ~ 100으로 나누어 체적 곡선 4 점에서 알 수있다. 이 각 요소의 매개 변수의 의미는 다음과 같습니다.
class VolumeCurvePoint { public: int mIndex;//百分制下标 float mDBAttenuation;//衰减 };
3. nbSteps : 계산 소수를 방지하기 위해이 예에서, 0부터 100까지 변환 VolumeIndex 시스템 UI 인터페이스에서 발생에 sSpeakerMediaVolumeCurve 곡선 [VOLMAX] .mIndex = 100 , 곡선 [VOLMIN] .mIndex = 1 이므로 nbSteps = 1 + 100-1 = 100;
4. volIdx : 액 처리는, 실제로 사용할 AudioService.java 대응 indexInUi_Max 오디오 스트림이 STREAM_MUSIC 해당 값이 15 인 100 분의 처리에 볼륨 volIdx 인덱스 UI 인터페이스이다 streamDesc.mIndexMax = 15이므로 streamDesc.mIndexMin = 0이면 volIdx = (20/3) * indexInUi 입니다.
//AudioService.java /** @hide Maximum volume index values for audio streams */ private static final 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 };
5. 세그먼트 : UI 볼륨 인터페이스의 VolumeIndex가 소수점 이하의 범위로 변환되었는지 확인하는 데 사용됩니다.
6. 데시벨 : VolumeIndex에 해당하는 볼륨 감쇠 단위는 dB입니다. 계산식은 다음과 같습니다.
스피커 M (dB)의 각 배율의 감쇠 차이를 달성하기 위해, 계산 방법은 decibels_Index_N decibels_Index_ 및 (N + 1) 사이의 차이를 계산하는 것이다. 계산을 쉽게하기 위해 N & N + 1은 기본적으로 동일한 세그먼트에 속할 수 있습니다.
때문에 곡선 [VOLMAX] .mDBAttenuation 보통 0, 즉 (이 제외 될 수 있지만, 어떤 경우, 커브 [VOLMAX] .mDBAttenuation 가장 쉽게 판정 값은 물론), 그것은 일반적으로 세그먼트 = 2 행의 시작으로부터 계산되는 감쇠없이 상태 이므로 60 ~ 100 범위의 Δdecibels 값은 다음과 같습니다.
Δdecibels = (20/3) * ((0- 곡선 [2] .mDBAttenuation) / (100-60)) = - (곡선 [2] .mDBAttenuation / 6)
그래서 Δdecibels = M, 그 곡선 [2] = .mDBAttenuation -6M 등 곡선 [1] = .mDBAttenuation -12M, 곡선 [0] = .mDBAttenuation -15M.
제 증폭 : 확대 / 축소 비율. 얻은 데시벨을 수식으로 가져 오면 직접 찾을 수 있습니다. 말할 것도 없습니다.
요약 :이 기사에서는 sSpeakerMediaVolumeCurve를 예로 들어 볼륨 감쇠 값 계산을 설명합니다. 다른 볼륨 커브 조정도 같은 방식으로 구현할 수 있습니다.
'Android' 카테고리의 다른 글
Android volume / Audio HAL / Audio policy / Camera (0) | 2018.03.15 |
---|---|
Android log 추출 (0) | 2018.01.03 |
안드로이드 heap dump 생성방법. (0) | 2017.10.19 |