Android音量設定流程(android8.0)
最近一直在解安卓audio部分的bug,其中最多的就是音量設定方面的問題,在這裡把自己學習到的一些東西記錄一下,以供參考。
安卓java部分的音量設定首先呼叫到AudioManager.java中
在這裡有兩種方法可以設定音量setStreamVolume和adjustStreamVolume
setStreamVolume:傳入index直接設定音量值
adjustStreamVolume:傳入direction,根據direction和獲取到的步長設定音量。
由於我們用到的是setStreamVolume方法,所以通過setStreamVolume向下看,其實如果再去看adjustStreamVolume其實也是殊途同歸。
1.setStreamVolume(AudioManager.java)
public void setStreamVolume(int streamType, int index, int flags) {
final IAudioService service = getService();
try {
service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
在此處呼叫了AudioService的setStreamVolume方法。此處傳入的streamType和index分別為設定的流型別和音量值。
關於streamType:安卓在聲音方面定義了多種流的型別以控制不同的聲音(比如區分音樂和鈴聲以及系統提示音等)
/** Used to identify the volume of audio streams for phone calls */
public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
/** Used to identify the volume of audio streams for system sounds */
public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
/** Used to identify the volume of audio streams for the phone ring */
public static final int STREAM_RING = AudioSystem.STREAM_RING;
/** Used to identify the volume of audio streams for music playback */
public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
/** Used to identify the volume of audio streams for alarms */
public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
/** Used to identify the volume of audio streams for notifications */
public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
/** @hide Used to identify the volume of audio streams for phone calls when connected
* to bluetooth */
public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
/** @hide Used to identify the volume of audio streams for enforced system sounds
* in certain countries (e.g camera in Japan) */
public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
/** Used to identify the volume of audio streams for DTMF Tones */
public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
/** @hide Used to identify the volume of audio streams exclusively transmitted through the
* speaker (TTS) of the device */
public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
/** Used to identify the volume of audio streams for accessibility prompts */
public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;
我們在AudioManager.java中可以看到原始碼對各種流型別進行了解釋,並且呼叫AudioSystem中的變數進行了賦值。
/** Used to identify the default audio stream volume */
public static final int STREAM_DEFAULT = -1;
/** Used to identify the volume of audio streams for phone calls */
public static final int STREAM_VOICE_CALL = 0;
/** Used to identify the volume of audio streams for system sounds */
public static final int STREAM_SYSTEM = 1;
/** Used to identify the volume of audio streams for the phone ring and message alerts */
public static final int STREAM_RING = 2;
/** Used to identify the volume of audio streams for music playback */
public static final int STREAM_MUSIC = 3;
/** Used to identify the volume of audio streams for alarms */
public static final int STREAM_ALARM = 4;
/** Used to identify the volume of audio streams for notifications */
public static final int STREAM_NOTIFICATION = 5;
/** Used to identify the volume of audio streams for phone calls when connected on bluetooth */
public static final int STREAM_BLUETOOTH_SCO = 6;
/** Used to identify the volume of audio streams for enforced system sounds in certain
* countries (e.g camera in Japan) */
public static final int STREAM_SYSTEM_ENFORCED = 7;
/** Used to identify the volume of audio streams for DTMF tones */
public static final int STREAM_DTMF = 8;
/** Used to identify the volume of audio streams exclusively transmitted through the
* speaker (TTS) of the device */
public static final int STREAM_TTS = 9;
/** Used to identify the volume of audio streams for accessibility prompts */
public static final int STREAM_ACCESSIBILITY = 10;
/**
2.AudioService.java
/** @see AudioManager#setStreamVolume(int, int, int) */
public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
//驗證流型別是否合法
if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
Log.w(TAG, "Trying to call setStreamVolume() for a11y without"
+ " CHANGE_ACCESSIBILITY_VOLUME callingPackage=" + callingPackage);
return;
}
setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
Binder.getCallingUid());
}
此處再呼叫AudioService中的setStreamVolume的過載函式,該函式多傳入了一個Binder.getCallingUid(),此處用到了binder的方法獲取呼叫端的UID來判斷呼叫者的身份,有興趣的可以去了解binder相關的內容,此處影響不大不多做解釋。
private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
String caller, int uid) {
if (DEBUG_VOL) {
Log.d(TAG, "setStreamVolume(stream=" + streamType+", index=" + index
+ ", calling=" + callingPackage + ")");
}
if (mUseFixedVolume) {
return;
}
//確認流型別
ensureValidStreamType(streamType);
//獲取別名,安卓在通過流設定音量時可以通過傳入一個流型別通過mStreamVolumeAlias查詢隱射的流型別來達到通過一個流來設定另一個流的目的。(此處比較繞,簡單的理解就是我可以通過使用STREAM_RING 通過mStreamVolumeAlias來對映到STREAM_MUSIC這個流以達到改變STREAM_RING來控制STREAM_MUSIC的目的)。
int streamTypeAlias = mStreamVolumeAlias[streamType];
VolumeStreamState streamState = mStreamStates[streamTypeAlias];
//獲取當前流的裝置(如喇叭,藍芽,以下所設定以及儲存的音量是和裝置進行儲存的)
final int device = getDeviceForStream(streamType);
//上一次設定的音量值
int oldIndex;
// skip a2dp absolute volume control request when the device
// is not an a2dp device
if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
(flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
return;
}
// If we are being called by the system (e.g. hardware keys) check for current user
// so we handle user restrictions correctly.
if (uid == android.os.Process.SYSTEM_UID) {
uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
}
if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
!= AppOpsManager.MODE_ALLOWED) {
return;
}
if (isAndroidNPlus(callingPackage)
&& wouldToggleZenMode(getNewRingerMode(streamTypeAlias, index, flags))
&& !mNm.isNotificationPolicyAccessGrantedForPackage(callingPackage)) {
throw new SecurityException("Not allowed to change Do Not Disturb state");
}
if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
return;
}
synchronized (mSafeMediaVolumeState) {
// reset any pending volume command
mPendingVolumeCommand = null;
//獲取舊的音量值
oldIndex = streamState.getIndex(device);
//對音量值進行某些操作(在音量設定邏輯中對傳入的值進行修改,達到對不同流對應的音量大小進行分別控制的目的,簡單說大概就是單位換算的意思,集體怎麼計算的有需要可以加列印追蹤)
index = rescaleIndex(index * 10, streamType, streamTypeAlias);
if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
(device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
(flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
synchronized (mA2dpAvrcpLock) {
if (mA2dp != null && mAvrcpAbsVolSupported) {
mA2dp.setAvrcpAbsoluteVolume(index / 10);
}
}
}
if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
}
flags &= ~AudioManager.FLAG_FIXED_VOLUME;
if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
((device & mFixedVolumeDevices) != 0)) {
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 & mSafeMediaVolumeDevices) != 0) {
index = mSafeMediaVolumeIndex;
} else {
index = streamState.getMaxIndex();
}
}
}
if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
mVolumeController.postDisplaySafeVolumeWarning(flags);
mPendingVolumeCommand = new StreamVolumeCommand(
streamType, index, flags, device);
} else {
//此處時真正設定音量的地方,呼叫onSetStreamVolume。上面做的那些判斷有需要或者遇到問題再去查,此處不一一解釋了。
onSetStreamVolume(streamType, index, flags, device, caller);
index = mStreamStates[streamType].getIndex(device);
}
}
sendVolumeUpdate(streamType, oldIndex, index, flags);
}
onSetStreamVolume
private void onSetStreamVolume(int streamType, int index, int flags, int device,
String caller) {
final int stream = mStreamVolumeAlias[streamType];
//呼叫setstreamVolumeInt
setStreamVolumeInt(stream, index, device, false, caller);
// setting volume on ui sounds stream type also controls silent mode
if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
(stream == getUiSoundsStreamType())) {
setRingerMode(getNewRingerMode(stream, index, flags),
TAG + ".onSetStreamVolume", false /*external*/);
}
// setting non-zero volume for a muted stream unmutes the stream and vice versa
mStreamStates[stream].mute(index == 0);
}
setstreamVolumeInt
private void setStreamVolumeInt(int streamType,
int index,
int device,
boolean force,
String caller) {
VolumeStreamState streamState = mStreamStates[streamType];
//先呼叫streamState.setIndex將音量設定到表裡面儲存起來
if (streamState.setIndex(index, device, caller) || force) {
// Post message to set system volume (it in turn will post a message
// to persist).
//傳送訊息給handler設定音量
sendMsg(mAudioHandler,
MSG_SET_DEVICE_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
0);
}
}
handleMessage
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SET_DEVICE_VOLUME:
//呼叫setDeviceVolume
setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
break;
setDeviceVolume
private void setDeviceVolume(VolumeStreamState streamState, int device) {
synchronized (VolumeStreamState.class) {
// Apply volume
//呼叫streamState.applyDeviceVolume_syncVSS
streamState.applyDeviceVolume_syncVSS(device);
// Apply change to all streams using this one as alias
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (streamType != streamState.mStreamType &&
mStreamVolumeAlias[streamType] == streamState.mStreamType) {
// Make sure volume is also maxed out on A2DP device for aliased stream
// that may have a different device selected
int streamDevice = getDeviceForStream(streamType);
if ((device != streamDevice) && mAvrcpAbsVolSupported &&
((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
}
mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
}
}
}
// Post a persist volume msg
sendMsg(mAudioHandler,
MSG_PERSIST_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
PERSIST_DELAY);
}
streamState.applyDeviceVolume_syncVSS
public void applyDeviceVolume_syncVSS(int device) {
int index;
if (mIsMuted) {
index = 0;
} else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
} else if ((device & mFullVolumeDevices) != 0) {
index = (mIndexMax + 5)/10;
} else {
index = (getIndex(device) + 5)/10;
}
//進入AudioSystem,開始真正地設定音量了
AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
}
3.AudioSystem.java
public static native int setStreamVolumeIndex(int stream, int index, int device);
這裡呼叫了一個native函式,其中涉及到JNI的知識,有興趣的可以去查詢資料學習。這個native函式可以在android_media_AudioSystem.cpp 中查詢到。
4.android_media_AudioSystem.cpp
static const JNINativeMethod gMethods[] = {
{"setParameters", "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
.....................................................
{"setForceUse", "(II)I", (void *)android_media_AudioSystem_setForceUse},
{"getForceUse", "(I)I", (void *)android_media_AudioSystem_getForceUse},
{"initStreamVolume", "(III)I", (void *)android_media_AudioSystem_initStreamVolume},
//查詢到JAVA層的setStreamVolumeIndex函式對應的是c++層android_media_AudioSystem_setStreamVolumeIndex
{"setStreamVolumeIndex","(III)I", (void *)android_media_AudioSystem_setStreamVolumeIndex},
{"getStreamVolumeIndex","(II)I", (void *)android_media_AudioSystem_getStreamVolumeIndex},
{"setMasterVolume", "(F)I", (void *)android_media_AudioSystem_setMasterVolume},
......................................................
android_media_AudioSystem_setStreamVolumeIndex
static jint
android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
jobject thiz,
jint stream,
jint index,
jint device)
{
return (jint) check_AudioSystem_Command(
AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
index,
(audio_devices_t)device));
}
此處呼叫AudioSystem::setStreamVolumeIndex(此時的是AudioSystem.cpp的函式)
5.AudioSystem.cpp
setStreamVolumeIndex
status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,
int index,
audio_devices_t device)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
return aps->setStreamVolumeIndex(stream, index, device);
}
此處建立了一個aps物件,並呼叫了該物件的setStreamVolume方法。 所以我們先看AudioSystem::get_audio_policy_service()返回了一個什麼物件。
AudioSystem::get_audio_policy_service()
const sp<IAudioPolicyService> AudioSystem::get_audio_policy_service()
{
sp<IAudioPolicyService> ap;
sp<AudioPolicyServiceClient> apc;
{
Mutex::Autolock _l(gLockAPS);
if (gAudioPolicyService == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.audio_policy"));
if (binder != 0)
break;
ALOGW("AudioPolicyService not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
if (gAudioPolicyServiceClient == NULL) {
gAudioPolicyServiceClient = new AudioPolicyServiceClient();
}
binder->linkToDeath(gAudioPolicyServiceClient);
//這裡使用了interface_cast並且傳入了一個binder,這裡也是binder相關的知識,這裡不對binder做過多解釋,
只根據這音量設定的流程做一定說明
gAudioPolicyService = interface_cast<IAudioPolicyService>(binder);
LOG_ALWAYS_FATAL_IF(gAudioPolicyService == 0);
apc = gAudioPolicyServiceClient;
// Make sure callbacks can be received by gAudioPolicyServiceClient
ProcessState::self()->startThreadPool();
}
ap = gAudioPolicyService;
}
if (apc != 0) {
ap->registerClient(apc);
}
return ap;
}
6.IInterface.h
上面的interface_cast(binder),interface_cast是一個模版,在frameworks\native\include\binder\IInterface.h中定義如下
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
展開後返回的是 IAudioPolicyService::asInterface(binder)
此時asInterface是在IAudioPolicyService作用域下,所以再去IAudioPolicyService.h查詢asInterface
7.IAudioPolicyService.h
在IAudioPolicyService中發現
DECLARE_META_INTERFACE(AudioPolicyService);
這一個巨集,這個巨集的定義也在frameworks\native\include\binder\IInterface.h中。
8.IInterface.h
#define DECLARE_META_INTERFACE(INTERFACE) \
static const ::android::String16 descriptor; \
static ::android::sp<I##INTERFACE> asInterface( \
const ::android::sp<::android::IBinder>& obj); \
virtual const ::android::String16& getInterfaceDescriptor() const; \
I##INTERFACE(); \
virtual ~I##INTERFACE(); \
其中static ::android::sp
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
const ::android::String16 I##INTERFACE::descriptor(NAME); \
const ::android::String16& \
I##INTERFACE::getInterfaceDescriptor() const { \
return I##INTERFACE::descriptor; \
} \
::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
const ::android::sp<::android::IBinder>& obj) \
{ \
::android::sp<I##INTERFACE> intr; \
if (obj != NULL) { \
intr = static_cast<I##INTERFACE*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
} \
I##INTERFACE::I##INTERFACE() { } \
I##INTERFACE::~I##INTERFACE() { } \
其中
::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
const ::android::sp<::android::IBinder>& obj) \
{ \
::android::sp<I##INTERFACE> intr; \
if (obj != NULL) { \
intr = static_cast<I##INTERFACE*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
}
返回的intr 就是Bp##INTERFACE(obj),其中INTERFACE就是我們的AudioPolicyService,
obj就是binder,所以展開返回的物件就是BpAudioPolicyService(binder)。
9.此時我們回到AudioSystem.cpp中
setStreamVolumeIndex
status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,
int index,
audio_devices_t device)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
return aps->setStreamVolumeIndex(stream, index, device);
}
那麼此時呼叫的就是BpAudioPolicyService(binder)->setStreamVolumeIndex(stream, index, device)
而這個BpAudioPolicyService的定義在IAudioPolicyService.cpp中。
10.IAudioPolicyService.cpp
class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
{
...
virtual status_t setStreamVolumeIndex(audio_stream_type_t stream,
int index,
audio_devices_t device)
{
Parcel data, reply;
//呼叫Parcel講介面描述符以及stream,index,device包裝進data
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
data.writeInt32(static_cast <uint32_t>(stream));
data.writeInt32(index);
data.writeInt32(static_cast <uint32_t>(device));
//使用transact將data以及SET_STREAM_VOLUME傳走,並且傳了一個reply的引用來儲存傳回來的值
remote()->transact(SET_STREAM_VOLUME, data, &reply);
return static_cast <status_t> (reply.readInt32());
}
...
}
其中remote()是通過繼承關係BpAudioPolicyService -> BpInterface -> BpRefBase,在類BpRefBase中定義的
inline IBinder* remote() { return mRemote; }
IBinder* const mRemote;
這裡是內聯的,並且return的mRemote也是const的,只賦值一次,它是在前面獲取遠端服務AudioPolicyService時候建立的BpBinder物件(主要是打開了binder驅動,獲得FD描述符,並且記憶體映射了空間),所以呼叫BpBinder.cpp的transact函式
11.BpBinder.cpp
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
呼叫IPCThreadState.cpp的transact。
12.進入IPCThreadState.cpp
在這個IPCThreadState就是真正交換通訊的地方了,void IPCThreadState::joinThreadPool(bool isMain)會迴圈呼叫
result = getAndExecuteCommand();處理命令,而我們的IPCThreadState::self()->transact就會使用Pacle來封裝我們傳入的資料交給
joinThreadPool來處理。最終會在
status_t IPCThreadState::executeCommand(int32_t cmd)中呼叫
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
這個the_context_object我們可以根據定義
sp the_context_object;瞭解這是一個bbinder物件(在binder.cpp中)。
13.進入binder.cpp
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
data.setDataPosition(0);
status_t err = NO_ERROR;
switch (code) {
case PING_TRANSACTION:
reply->writeInt32(pingBinder());
break;
default:
err = onTransact(code, data, reply, flags);
break;
}
if (reply != NULL) {
reply->setDataPosition(0);
}
return err;
}
這裡呼叫了err = onTransact(code, data, reply, flags);根據繼承關係,我們可以知道呼叫的是AudioPolicyService的ontransact方法。
14.AudioPolicyService.cpp
status_t AudioPolicyService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
return BnAudioPolicyService::onTransact(code, data, reply, flags);
}
所以現在我們知道應答了binder的transact之後其實是呼叫了AudioPolicyService中的 ontransact。
15.IAudioPolicyService
status_t BnAudioPolicyService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
...................
case SET_STREAM_VOLUME: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
audio_stream_type_t stream =
static_cast <audio_stream_type_t>(data.readInt32());
int index = data.readInt32();
audio_devices_t device = static_cast <audio_devices_t>(data.readInt32());
reply->writeInt32(static_cast <uint32_t>(setStreamVolumeIndex(stream,
index,
device)));
return NO_ERROR;
} break;
......................
此處的reply->writeInt32(static_cast (setStreamVolumeIndex(stream,
index,device));
這裡呼叫了setStreamVolumeIndex方法,所以AudioPolicyService呼叫了BnAudioPolicyService::onTransact後回去呼叫自己的
setStreamVolumeIndex方法。而setStreamVolumeIndex的實現在android8.0中在AudioPolicyInterfaceImpl.cpp中。
16.AudioPolicyInterfaceImpl.cpp中。
status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream,
int index,
audio_devices_t device)
{
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
return BAD_VALUE;
}
Mutex::Autolock _l(mLock);
return mAudioPolicyManager->setStreamVolumeIndex(stream,
index,
device);
}
這裡呼叫mAudioPolicyManager->setStreamVolumeIndex(stream, index,device);
AudioPolicyManager下的setStreamVolumeIndex定義在AudioPolicyManager.cpp中。
17.AudioPolicyManager.cpp
status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
int index,
audio_devices_t device)
{
if ((index < mVolumeCurves->getVolumeIndexMin(stream)) ||
(index > mVolumeCurves->getVolumeIndexMax(stream))) {
return BAD_VALUE;
}
if (!audio_is_output_device(device)) {
return BAD_VALUE;
}
// Force max volume if stream cannot be muted
if (!mVolumeCurves->canBeMuted(stream)) index = mVolumeCurves->getVolumeIndexMax(stream);
// update other private stream volumes which follow this one
for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
continue;
}
mVolumeCurves->addCurrentVolumeIndex((audio_stream_type_t)curStream, device, index);
}
// update volume on all outputs and streams matching the following:
// - The requested stream (or a stream matching for volume control) is active on the output
// - The device (or devices) selected by the strategy corresponding to this stream includes
// the requested device
// - For non default requested device, currently selected device on the output is either the
// requested device or one of the devices selected by the strategy
// - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if
// no specific device volume value exists for currently selected device.
status_t status = NO_ERROR;
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device());
for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
continue;
}
if (!(desc->isStreamActive((audio_stream_type_t)curStream) ||
(isInCall() && (curStream == AUDIO_STREAM_VOICE_CALL)))) {
continue;
}
routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
audio_devices_t curStreamDevice = getDeviceForStrategy(curStrategy, false /*fromCache*/);
if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&
((curStreamDevice & device) == 0)) {
continue;
}
bool applyVolume;
if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
curStreamDevice |= device;
applyVolume = (curDevice & curStreamDevice) != 0;
} else {
applyVolume = !mVolumeCurves->hasVolumeIndexForDevice(
stream, Volume::getDeviceForVolume(curStreamDevice));
}
if (applyVolume) {
//FIXME: workaround for truncated touch sounds
// delayed volume change for system stream to be removed when the problem is
// handled by system UI
status_t volStatus =
checkAndSetVolume((audio_stream_type_t)curStream, index, desc, curDevice,
(stream == AUDIO_STREAM_SYSTEM) ? TOUCH_SOUND_FIXED_DELAY_MS : 0);
if (volStatus != NO_ERROR) {
status = volStatus;
}
}
}
}
return NO_ERROR;
}
在這裡會在audiopolicymanager中做一系列的處理,最後調回AudioSystem再進入AudioFlinger中,由於在工作中用到的情況是在AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,int index, audio_devices_t device)之後便直接切入自己的中介軟體了,所以沒有再進入安卓的流程,如果有需要的話可以再繼續往下研究。難點主要在於binder和JNI,其實只要瞭解了binder和JNI之後,更多的就是一些流程化的東西了。
相關推薦
Android音量設定流程(android8.0)
最近一直在解安卓audio部分的bug,其中最多的就是音量設定方面的問題,在這裡把自己學習到的一些東西記錄一下,以供參考。 安卓java部分的音量設定首先呼叫到AudioManager.java中 在這裡有兩種方法可以設定音量setStreamVolume和
Android進階3:Activity原始碼分析(2) —— Activity啟動和銷燬流程(8.0)
上篇文章講述了app從啟動建立Activity呼叫onCreate,onStart, onResume方法,這篇文章講述一下Activity啟動的另一個切入點:startActivity方法,啟動Activity。 通過上一篇文章,我們總結一下: 1:A
Android音量設定流程乾貨版
1. 音量級數定義 在AudioService.java中定義了最大音量MAX_STREAM_VOLUME,手機的設定property可以覆蓋它。 2. 音量初始化 initStreamVolume傳入AudioPolicyManagerBase裡的Stre
Android Activity啟動流程(基於Android8.0系統)
主要物件介紹 ActivityManagerService:負責系統中所有Activity的生命週期; Activi
Android 一行程式碼版本更新(適配到Android8.0)
做Android 專案的時候一般都需要在App內版本更新,以前自己寫過,今天介紹的不是自己的,是一個開源,功能比較強大,一句話實現版本更新功能 一、依賴 compile 'com.allenliu.versionchecklib:library:2.0.5' 二、程式碼 AllenVer
Android系統啟動流程(一)解析init進程啟動過程
option 寫入 android change failed miss 通知 target sna 前言 作為“Android框架層”這個大系列中的第一個系列,我們首先要了解的是Android系統啟動流程,在這個流程中會涉及到很多重要的知識點,這個系列我們就來一一講解它們
(Android) RadioButton設定setCheck(true)無效
今天碰到個問題,RadioButton設定setCheck(true)無效,佈局xml是RadioGroup裡包含了幾個RadioButton。 經驗證,發現之前有個呼叫,把所有RadioButton都呼叫setChecked(false),這個會導致再次設定setCheched(true)無效
Android應用反編譯詳細流程(Mac系統)
新版Android應用反編譯詳細流程(Mac系統) 以前一直都是用win來反編譯,後來換了Mac就一直沒弄過了,今天剛好有需要,正好也做個筆記,留著以後備用。 其實現在大多數應用都會做一些防護,下面這種方式,只適用於一般的沒做加固處理的apk。 現在開始吧,首先你需要準備好必
《第一行程式碼》 第五章:全域性大喇叭 筆記(基於Android8.0)
由於Android8.0對廣播機制做了很大的調整理,導致《第一行程式碼》中很多例項無法正常執行,因此我結合書本,自行整理了一下。 廣播需要接收器和傳送器。系統的動作都會發送一條廣播,例如電量的變化,系
Android Multimedia框架總結(十二)CodeC部分之OMXCodec與OMX事件回撥流程
前言:上篇文中分析到AwesomePlayer到OMX服務,曾介紹到,OMX服務主要完成三個任務: NodeInstance列表的管理,NodeInstance的操作, 事件的處理。最後這個事件處理就是今天放大看的內容。要一步一步一Codec,事件傳遞必不可
Android系統啟動流程(一)解析init程序啟動過程
前言 作為“Android框架層”這個大系列中的第一個系列,我們首先要了解的是Android系統啟動流程,在這個流程中會涉及到很多重要的知識點,這個系列我們就來一一講解它們,這一篇我們就來學習init程序。 1.init簡介 init程序是An
Android 測試的流程(工作流程)
•5、等待開發提交測試版本,提交後優先執行冒煙測試。冒煙測試的結果,需要郵件周知相關人,開發,測試,產品,其中重要的是開發領導,測試領導和產品。冒煙不通過等待開發重新提交版本,冒煙通過了進入執行用例進行測試階段。
Feign的超時與重試設定(SpringCloud2.0)
1.Feign的依賴 <dependency> <groupId>org.springframework.cloud</groupId> <artif
Android原始碼解析之(十一)-->應用程序啟動流程
本節主要是通過分析Activity的啟動過程介紹應用程式程序的啟動流程。關於Android的應用程序在android guide中有這樣的一段描述: By default, every application runs in its own Linu
Android系統啟動流程(二)解析Zygote程序啟動過程
前言 上一篇文章我們分析了init程序的啟動過程,啟動過程中主要做了三件事,其中一件就是建立了Zygote程序,那麼Zygote程序是什麼,它做了哪些事呢?這篇文章會給你這些問題的答案。 1.Zygote簡介 在Android系統中,DVM(D
從0開始設定django(基於CentOS7)
一 CentOS python3的安裝 yum -y groupinstall "Development tools" yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel
Android圖表控制元件MPAndroidChart的簡單介紹(MPAndroidChart3.0)
每個類對應的圖是什麼github上有詳細的介紹圖表類具有相同的地方X軸:XAxisY軸:YAxis圖例:Legend描述:Description限制線:LimitLine選中圖表中的值,可顯示的檢視:MarkerView 具體在圖表中的表現如下圖以曲線圖為例依賴:projec
[RK3288][Android6.0] Audio的音量設定流程小結
Platform: Rockchip OS: Android 6.0 Kernel: 3.10.92 說明一: AudioManager提供了兩個調節音量介面 adjustSuggestedSt
Android系統啟動流程(四)Launcher啟動過程與系統啟動流程
相關文章 Android系統架構與系統原始碼目錄 Android系統啟動流程(一)解析init程序啟動過程 Android系統啟動流程(二)解析Zygote程序啟動過程 Android系統啟動流程(三)解析SyetemServer程序啟動過程 前言
Android系統啟動流程(三)解析SyetemServer程序啟動過程
相關文章 Android系統架構與系統原始碼目錄 Android系統啟動流程(一)解析init程序啟動過程 Android系統啟動流程(二)解析Zygote程序啟動過程 前言 上一篇我們學習了Zygote程序,並且知道Zygote程序啟動了SyetemServ