/* * Copyright (C) 2021 because-why-not.com Limited * * Please refer to the license.txt for license information */ using UnityEngine; namespace Byn.Awrtc.Unity { /// /// Provides a range of static functions that help dealing with android specific issues. /// Main issue is that android treats the WebRTC audio as a voice cal. There are multiple problems /// because of this: /// /// * the volume isn't set via "Media" but independently via the "Call volume" slider /// (and unity blocks access to this slider) /// /// * The volume is optimized for headphones or the users holding the phone directly onto their ears. /// -> Use SetSpeakerOn(true) to turn on the phones speaker for increased volume without headsets /// /// /// public class AndroidHelper { public readonly static string jclass_AndroidVideo = "com.because_why_not.wrtc.AndroidVideo"; public readonly static string jclass_PermissionHelper = "com.because_why_not.wrtc.PermissionHelper"; public static bool IsFrontFacing(string deviceName) { if (string.IsNullOrEmpty(deviceName)) return false; AndroidJavaClass contextClass = new AndroidJavaClass(jclass_AndroidVideo); return contextClass.CallStatic("isFrontFacing", deviceName); } public static bool IsBackFacing(string deviceName) { if (string.IsNullOrEmpty(deviceName)) return false; AndroidJavaClass contextClass = new AndroidJavaClass(jclass_AndroidVideo); return contextClass.CallStatic("isBackFacing", deviceName); } /// /// True switches the phone in speaker mode. This will also happen if headphones are connected. /// /// This heavily increases the volume of the webrtc audio but often reduces the quality. /// /// WARNING: This value is persistent even after restarting the app!!! /// /// public static void SetSpeakerOn(bool value) { AndroidJavaObject audioManager = GetAudioManager(); audioManager.Call("setSpeakerphoneOn", value); } /// /// Allows to check if the speakers are currently on. /// /// public static bool IsSpeakerOn() { AndroidJavaObject audioManager = GetAudioManager(); return audioManager.Call("isSpeakerphoneOn"); } /// /// Wrapper for AndroidManager.getMode /// /// public static int GetMode() { AndroidJavaObject audioManager = GetAudioManager(); return audioManager.Call("getMode"); } /// /// Wrapper for AndroidManager.setMode /// /// public static void SetMode(int mode) { AndroidJavaObject audioManager = GetAudioManager(); audioManager.Call("setMode", mode); } /// /// Checks if the current mode is set to InCommunication /// /// public static bool IsModeInCommunication() { return GetMode() == GetAudioManagerFlag("MODE_IN_COMMUNICATION"); } /// /// Switches Android to In-Communcation. /// /// This will show the Call Volume bar if the volume buttons are used and /// might also change the internal piping of audio within Android. /// /// For more info see: /// https://developer.android.com/reference/android/media/AudioManager /// public static void SetModeInCommunicaion() { AndroidJavaObject audioManager = GetAudioManager(); Debug.Log("mode before: " + audioManager.Call("getMode")); SetMode(GetAudioManagerFlag("MODE_IN_COMMUNICATION")); Debug.Log("mode after: " + audioManager.Call("getMode")); } public static int GetAudioManagerMode() { AndroidJavaObject audioManager = GetAudioManager(); return audioManager.Call("getMode"); } /// /// Default mode in android applications. Call volume bar shouldn't be visible /// public static void SetModeNormal() { AndroidJavaObject audioManager = GetAudioManager(); Debug.Log("mode before: " + audioManager.Call("getMode")); SetMode(GetAudioManagerFlag("MODE_NORMAL")); Debug.Log("mode after: " + audioManager.Call("getMode")); } /// /// Returns the volume level of the voice call / webrtc stream /// /// /// public static int GetStreamVolume() { AndroidJavaObject audioManager = GetAudioManager(); return audioManager.Call("getStreamVolume", GetAudioManagerFlag("STREAM_VOICE_CALL")); } /// /// Sets the volume level for the webrtc call / stream /// /// public static void SetStreamVolume(int volume) { AndroidJavaObject audioManager = GetAudioManager(); audioManager.Call("setStreamVolume", GetAudioManagerFlag("STREAM_VOICE_CALL"), volume, GetAudioManagerFlag("FLAG_SHOW_UI") | GetAudioManagerFlag("FLAG_PLAY_SOUND")); } /// /// Doesn't seem to work yet. /// /// public static void SetMute(bool isMute) { AndroidJavaObject audioManager = GetAudioManager(); audioManager.Call("setStreamMute", GetAudioManagerFlag("STREAM_VOICE_CALL"), isMute); } public static bool IsMute() { AndroidJavaObject audioManager = GetAudioManager(); return audioManager.Call("isStreamMute", GetAudioManagerFlag("STREAM_VOICE_CALL")); } private static AndroidJavaObject GetAudioManager() { AndroidJavaObject activity = GetActivity(); AndroidJavaObject context = activity.Call("getApplicationContext"); AndroidJavaClass contextClass = new AndroidJavaClass("android.content.Context"); AndroidJavaObject contextClass_AUDIO_SERVICE = contextClass.GetStatic("AUDIO_SERVICE"); AndroidJavaObject audioManager = context.Call("getSystemService", contextClass_AUDIO_SERVICE); return audioManager; } private static AndroidJavaObject GetActivity() { AndroidJavaClass unityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject activity = unityPlayerClass.GetStatic("currentActivity"); return activity; } private static int GetAudioManagerFlag(string flag) { AndroidJavaClass audioManagerClass = new AndroidJavaClass("android.media.AudioManager"); return audioManagerClass.GetStatic(flag); } public static bool CheckPermissionMicrophone() { AndroidJavaClass permissionHelper = new AndroidJavaClass(jclass_PermissionHelper); return permissionHelper.CallStatic("CheckPermissionMicrophone", GetActivity()); } public static bool CheckPermissionCamera() { AndroidJavaClass permissionHelper = new AndroidJavaClass(jclass_PermissionHelper); return permissionHelper.CallStatic("CheckPermissionCamera", GetActivity()); } public static bool CheckPermissionAudioSettings() { AndroidJavaClass permissionHelper = new AndroidJavaClass(jclass_PermissionHelper); return permissionHelper.CallStatic("CheckPermissionAudioSettings", GetActivity()); } public static bool CheckPermissionNetwork() { AndroidJavaClass permissionHelper = new AndroidJavaClass(jclass_PermissionHelper); return permissionHelper.CallStatic("CheckPermissionNetwork", GetActivity()); } public static bool HasRuntimePermissions() { AndroidJavaClass permissionHelper = new AndroidJavaClass(jclass_PermissionHelper); return permissionHelper.CallStatic("HasRuntimePermissions"); } public static void RequestPermissions(bool microphone, bool camera, bool audioSettings, int requestCode) { AndroidJavaClass permissionHelper = new AndroidJavaClass(jclass_PermissionHelper); permissionHelper.CallStatic("RequestPermissions", GetActivity(), microphone, camera, audioSettings, requestCode); } public static void OpenPermissionView() { AndroidJavaClass permissionHelper = new AndroidJavaClass(jclass_PermissionHelper); permissionHelper.CallStatic("OpenPermissionView", GetActivity()); } /// /// Maps to AudioManager.setBluetoothScoOn /// /// /// private static void setBluetoothScoOn(bool value) { AndroidJavaObject audioManager = GetAudioManager(); audioManager.Call("setBluetoothScoOn", value); } /// /// Maps to AudioManager.startBluetoothSco /// /// /// private static void startBluetoothSco() { AndroidJavaObject audioManager = GetAudioManager(); audioManager.Call("startBluetoothSco"); } /// /// Maps to AudioManager.stopBluetoothSco /// /// private static void stopBluetoothSco() { AndroidJavaObject audioManager = GetAudioManager(); audioManager.Call("stopBluetoothSco"); } /// /// Gets the status of whether a headset is currently connected. /// /// public static bool IsHeadsetOn() { //submitted by scott. Thanks! :) AndroidJavaObject audioManager = GetAudioManager(); if (audioManager.Call("isWiredHeadsetOn") || audioManager.Call("isBluetoothA2dpOn")) { return true; } return false; } /// /// Turns on / off routing to a bluetooth speaker. /// Works only while in communication mode. If the /// mode turns off the results might be device specific. /// /// /// true - route to bluetooth /// false - turn off routing to bluetooth /// public static void SetBluetoothOn(bool state) { if (state) { setBluetoothScoOn(true); startBluetoothSco(); } else { setBluetoothScoOn(false); stopBluetoothSco(); } } } }