我正在开发一个迷你原生 (Java) SDK 来打开/关闭 react-native 应用程序的扬声器,因为 React-Native Incall Manager 在 Android 12 上无法正常工作。
模块在 Android 11 上运行良好,但由于 AudioManager 中的 setSpeakerOn 方法已被最新的 SDK 弃用,因此在 Android 12 上存在一些问题。我从官方docs拿了代码 fragment 并对其进行了调整。即使 bool 值
result = audioManager.setCommunicationDevice(device)
返回 TRUE ,它不会改变扬声器状态。
许可
android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
AudioModule.java
public class AudioModule extends ReactContextBaseJavaModule {
private AudioManager audioManager;
private static final String TAG = "AudioModule";
private static ReactApplicationContext reactContext;
AudioModule(ReactApplicationContext context) {
super(context);
reactContext = context;
audioManager = ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE));
}
@Override
public String getName() {
return "AudioModule";
}
@ReactMethod
public void setSpeakerState(Boolean speakerState) {
try {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
if (speakerState) {
setCommunicationDevice(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
} else {
audioManager.clearCommunicationDevice(); //turn off speaker
}
} else {
audioManager.setMode(speakerState ? AudioManager.MODE_IN_COMMUNICATION : AudioManager.MODE_NORMAL);
audioManager.setSpeakerphoneOn(speakerState);
}
Toast.makeText(reactContext, "speakerStatus " + audioManager.isSpeakerphoneOn(), Toast.LENGTH_LONG).show();
} catch (Exception e) {
Log.d(TAG, "AudioModule setSpeaker", e);
}
}
@RequiresApi(api = Build.VERSION_CODES.S)
public void setCommunicationDevice(Integer targetDeviceType) {
List<AudioDeviceInfo> audioDevices = audioManager.getAvailableCommunicationDevices();
for (AudioDeviceInfo device : audioDevices) {
if (device.getType() == targetDeviceType) {
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION );
boolean result = audioManager.setCommunicationDevice(device);
break;
}
}
}
注意:React-Native 的原生模块在 Android 11 操作系统上正常工作,并在 Android 12 和 13 上显示 Toast(在物理设备上测试)
更新: 还尝试了 IncallService 接口(interface): 导入 android.telecom.InCallService;
public class CallService extends InCallService {
private static CallService sInstance;
CallService() {
sInstance = this;
}
public static CallService getInstance() {
return sInstance;
}
}
调用的方法
@ReactMethod
public void toggleSpeaker() {
boolean isSpeakerOn = audioManager.isSpeakerphoneOn();
int earpiece = CallAudioState.ROUTE_WIRED_OR_EARPIECE;
int speaker = CallAudioState.ROUTE_SPEAKER;
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.P) {
callService.getInstance().setAudioRoute(isSpeakerOn ? earpiece : speaker);
} else {
audioManager.setSpeakerphoneOn(!isSpeakerOn);
}
Toast.makeText(reactContext, "speakerStatus " + audioManager.isSpeakerphoneOn(), Toast.LENGTH_LONG).show();
}
Logcat 返回下一条消息:
android.hardware.audio.service: Failed to fetch the lookup information of the device
最佳答案
我在 android 12 甚至一些 android 11 设备上遇到了类似的问题。当我调用 am.setCommunicationDevice(earpieceDevice)
时,它返回 true
但音频仍在扬声器上播放。然后我通过调用 am.setMode(AudioManager.MODE_NORMAL)
强制启用了 NORMAL_MODE
,现在它开始工作了。奇怪!
private fun setAudioDevice(){
am.mode = AudioManager.MODE_NORMAL
val speakerDevice: AudioDeviceInfo? = getAudioDevice(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER)
am.setCommunicationDevice(speakerDevice)
}
private fun getAudioDevice(type: Int): AudioDeviceInfo? {
val audioDevices = am.getDevices(AudioManager.GET_DEVICES_OUTPUTS)
for (deviceInfo in audioDevices) {
if (type == deviceInfo.type) return deviceInfo
}
return null
}
关于android - AudioManager setCommunicationDevice 不适用于 Android 12,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73565120/