在某些国家(比如Japan),为了防止偷拍,强制拍照声是需要从Speaker出来的(即使插入耳机的情况下)。
实现该功能比较简单的方法就是将拍照声类型设置为Ringtone 或 Alarm 或 Notification类型,这样在AudioPolicyManager.cpp中device选择时就会将Speaker设为output device。
还有一种方式就是设置拍照声为ENFORCED_AUDIBLE,该类型音频流的类型解释:
ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be routed to speaker
该解释应该就是说这类型的声音不能被静音,而且必须从speaker出来。
但是仅仅将音频流类型设置为ENFORCED_AUDIBLE,并不能保证声音从speaker出来,从AudioPolicyManager.cpp里逻辑里看:
case STRATEGY_ENFORCED_AUDIBLE:
// strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
// except:
// - when in call where it doesn't default to STRATEGY_PHONE behavior
// - in countries where not enforced in which case it follows STRATEGY_MEDIA if ((strategy == STRATEGY_SONIFICATION) ||
(mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_SYSTEM_ENFORCED)) {
device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION");
}
}
// The second device used for sonification is the same as the device used by media strategy
// FALL THROUGH case STRATEGY_MEDIA: {
uint32_t device2 = AUDIO_DEVICE_NONE;
if (strategy != STRATEGY_SONIFICATION) {
// no sonification on remote submix (e.g. WFD)
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
}
if ((device2 == AUDIO_DEVICE_NONE) &&
mHasA2dp && (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
(getA2dpOutput() != ) && !mA2dpSuspended) {
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
if (device2 == AUDIO_DEVICE_NONE) {
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
}
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
}
if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
// no sonification on aux digital (e.g. HDMI)
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
}
if ((device2 == AUDIO_DEVICE_NONE) &&
(mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)) {
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
}
if (device2 == AUDIO_DEVICE_NONE) {
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
} // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
// STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
device |= device2;
if (device) break;
device = mDefaultOutputDevice;
if (device == AUDIO_DEVICE_NONE) {
ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
}
} break;
在case STRATEGY_ENFORCED_AUDIBLE中,因为目前(strategy != STRATEGY_SONIFICATION) 所以想要在音频流类型是ENFORCED_AUDIBLE的情况下Speaker还能出声的话,就需要满足:(mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_SYSTEM_ENFORCED),否则就会follow case STRATEGY_MEDIA的device。
而(mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_SYSTEM_ENFORCED)是在哪边设定的呢?
全局搜索了代码,原来在AudioService初始化时:
boolean cameraSoundForced = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_camera_sound_forced);
mCameraSoundForced = new Boolean(cameraSoundForced);
sendMsg(mAudioHandler,
MSG_SET_FORCE_USE,
SENDMSG_QUEUE,
AudioSystem.FOR_SYSTEM,
cameraSoundForced ?
AudioSystem.FORCE_SYSTEM_ENFORCED :AudioSystem.FORCE_NONE,
null,
0);
所以当cameraSoundForced的值为true时,就会setforceuse(FOR_SYSTEM,FORCE_SYSTEM_ENFORCED);而com.android.internal.R.bool.config_camera_sound_forced是在config.xml中设定的,所以还需要在config.xml档里将config_camera_sound_forced变量设置为true。