android - AudioManager setCommunicationDevice 不适用于 Android 12

标签 android react-native android-audiomanager speaker react-native-native-module

我正在开发一个迷你原生 (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/

相关文章:

android - 如何从设备的联系人列表中获取用户的连接性?

android - 如何通过扫描 NFC 标签启动没有启动器图标的应用程序?

Android:向 EditText 框添加验证?

react-native - 在 react 导航中,routeName 和 key 之间有什么区别?

android - 到目前为止,无法在 Android 上实现无缝音频循环

android - 如何以编程方式使运行 Lollipop 的设备静音/静音?

android - 在 RecyclerView 的适配器中获取上下文

javascript - 无法读取 Reactnative 中 null 错误的属性 'bindings'

javascript - 在 React Native 中设置自定义开发者选项

android - 如何在语音通话期间发送预先录制的 (wav) 文件?