Created
July 8, 2025 11:24
-
-
Save sathyarajshetigar/30de50a2b7da315e1a6ae118b995d0f3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections; | |
| using System.Collections.Generic; | |
| using System.Collections.ObjectModel; | |
| using System.ComponentModel; | |
| using System.Dynamic; | |
| using System.Linq; | |
| using IjsUiFramework; | |
| using UnityEngine; | |
| using UnityEngine.Android; | |
| using VivoxUnity; | |
| [System.Serializable] | |
| public class VivoxConfig | |
| { | |
| [SerializeField] | |
| private string _server = "https://GETFROMPORTAL.www.vivox.com/api2"; | |
| [SerializeField] | |
| private string _domain = "GET VALUE FROM VIVOX DEVELOPER PORTAL"; | |
| [SerializeField] | |
| private string _tokenIssuer = "GET VALUE FROM VIVOX DEVELOPER PORTAL"; | |
| [SerializeField] | |
| private string _tokenKey = "GET VALUE FROM VIVOX DEVELOPER PORTAL"; | |
| public Uri serverURI => new Uri(_server); | |
| public string server => _server; | |
| public string domain => _domain; | |
| public string tokenIssuer => _tokenIssuer; | |
| public string tokenKey => _tokenKey; | |
| public VivoxConfig(string server, string domain, string tokenIssuer, string tokenKey) | |
| { | |
| _server = server; | |
| _domain = domain; | |
| _tokenIssuer = tokenIssuer; | |
| _tokenKey = tokenKey; | |
| } | |
| } | |
| public class VivoxVoiceManager : MonoBehaviour | |
| { | |
| #region Enums | |
| /// <summary> | |
| /// Defines properties that can change. Used by the functions that subscribe to the OnAfterTYPEValueUpdated functions. | |
| /// </summary> | |
| public enum ChangedProperty | |
| { | |
| None, | |
| Speaking, | |
| Typing, | |
| Muted | |
| } | |
| public enum ChatCapability | |
| { | |
| TextOnly, | |
| AudioOnly, | |
| TextAndAudio | |
| }; | |
| public enum MatchStatus | |
| { | |
| Open, | |
| Closed | |
| } | |
| #endregion | |
| #region Delegates/Events | |
| public delegate void ParticipantValueChangedHandler(string username, ChannelId channel, bool value); | |
| public static event ParticipantValueChangedHandler OnSpeechDetectedEvent; | |
| public static event ParticipantValueChangedHandler OnAudioEnergyChangedEvent; | |
| public delegate void ParticipantStatusChangedHandler(string username, ChannelId channel, IParticipant participant); | |
| public static event ParticipantStatusChangedHandler OnParticipantAddedEvent; | |
| public static event ParticipantStatusChangedHandler OnParticipantRemovedEvent; | |
| public delegate void ChannelTextMessageChangedHandler(string sender, IChannelTextMessage channelTextMessage); | |
| public static event ChannelTextMessageChangedHandler OnTextMessageLogReceivedEvent; | |
| public delegate void SessionArchiveMessageChangedHandler(string sender, ISessionArchiveMessage channelTextMessage); | |
| public static event SessionArchiveMessageChangedHandler OnSessionArchiveMessageReceivedEvent; | |
| public delegate void LoginStatusChangedHandler(); | |
| public static event LoginStatusChangedHandler OnUserLoggedInEvent; | |
| public static event LoginStatusChangedHandler OnUserLoggedOutEvent; | |
| #endregion | |
| #region Member Variables | |
| private VivoxConfig _config; | |
| private TimeSpan _tokenExpiration = TimeSpan.FromSeconds(90); | |
| private Client _client = new Client(); | |
| private AccountId _accountId; | |
| private bool PermissionsDenied; | |
| private IParticipant _localParticipant; | |
| IChannelSession channelSession; | |
| // Check to see if we're about to be destroyed. | |
| private static object m_Lock = new object(); | |
| private static VivoxVoiceManager m_Instance; | |
| /// <summary> | |
| /// Access singleton instance through this propriety. | |
| /// </summary> | |
| public static VivoxVoiceManager Instance | |
| { | |
| get | |
| { | |
| lock (m_Lock) | |
| { | |
| if (m_Instance == null) | |
| { | |
| // Search for existing instance. | |
| m_Instance = (VivoxVoiceManager)FindObjectOfType(typeof(VivoxVoiceManager)); | |
| // Create new instance if one doesn't already exist. | |
| if (m_Instance == null) | |
| { | |
| // Need to create a new GameObject to attach the singleton to. | |
| var singletonObject = new GameObject(); | |
| m_Instance = singletonObject.AddComponent<VivoxVoiceManager>(); | |
| singletonObject.name = typeof(VivoxVoiceManager).ToString() + " (Singleton)"; | |
| } | |
| } | |
| // Make instance persistent even if its already in the scene | |
| DontDestroyOnLoad(m_Instance.gameObject); | |
| return m_Instance; | |
| } | |
| } | |
| } | |
| public LoginState LoginState { get; private set; } | |
| public ILoginSession loginSession; | |
| public VivoxUnity.IReadOnlyDictionary<ChannelId, IChannelSession> ActiveChannels => loginSession?.ChannelSessions; | |
| public IAudioDevices AudioInputDevices => _client.AudioInputDevices; | |
| public IAudioDevices AudioOutputDevices => _client.AudioOutputDevices; | |
| #endregion | |
| #region Properties | |
| /// <summary> | |
| /// Retrieves the first instance of a session that is transmitting. | |
| /// </summary> | |
| public IChannelSession TransmittingSession | |
| { | |
| get | |
| { | |
| if (_client == null) | |
| throw new NullReferenceException("client"); | |
| return _client.GetLoginSession(_accountId).ChannelSessions.FirstOrDefault(x => true); | |
| } | |
| set | |
| { | |
| if (value != null) | |
| { | |
| //value.IsTransmittingSession = true; | |
| } | |
| } | |
| } | |
| public IParticipant localParticipant => _localParticipant; | |
| public bool isInitialized => _client?.Initialized ?? false; | |
| public bool hasMicPermission | |
| { | |
| get | |
| { | |
| #if UNITY_ANDROID | |
| return Permission.HasUserAuthorizedPermission(Permission.Microphone); | |
| #elif UNITY_IOS | |
| // return Application.HasUserAuthorization(UserAuthorization.Microphone); | |
| //https://github.com/zhao1289/unityruntimepermissionplugin | |
| PermissionSelf result = PermissionPluginForIOS.CheckPermission(PermissionType.Microphone); | |
| Game.Log($"hasMicPermission {result}"); | |
| return result == PermissionSelf.Granted; | |
| #else | |
| return false; | |
| #endif | |
| } | |
| } | |
| #endregion | |
| private void Awake() | |
| { | |
| if (m_Instance != null && m_Instance != this) | |
| { | |
| Game.Log("Multiple VivoxVoiceManager detected in the scene. Only one VivoxVoiceManager can exist at a time. The duplicate VivoxVoiceManager will be destroyed."); | |
| Destroy(this); | |
| return; | |
| } | |
| GameData gameData = GameSkinData.gameSkin.currentGameData; | |
| _config = new VivoxConfig("https://mt2p.www.vivox.com/api2", "mt2p.vivox.com", "arvind2023-sk14", "WkGJPfylAz8bLmsSUhqGMa6rTCLvVwxV"); | |
| //_config = new VivoxConfig("https://mt2p.www.vivox.com/api2", "mt2p.vivox.com", "arvind1748-bu79", "Aa5lFVCEKl66hUyv6ceGacH1DT6EguYL"); | |
| //_config = new VivoxConfig("https://mt1s.www.vivox.com/api2", "mt1s.vivox.com", "arvind1748-bu79-dev", "java456"); // sandbox - Business | |
| //_config = new VivoxConfig("https://mt1p.www.vivox.com/api2", "mt1p.vivox.com", "arvind1748-ba20", "yBs0f0plJz7XirNnu1sc0za0WXKNFs9B"); | |
| //_config = new VivoxConfig("https://mt1s.www.vivox.com/api2", "mt1s.vivox.com", "arvind1748-ba20-dev", "buzz086"); // sandBox | |
| //_config = new VivoxConfig("https://vdx5.www.vivox.com/api2", "vdx5.vivox.com", "arvind1748-ba40-dev", "maze382"); // battleship | |
| //_config = new VivoxConfig(gameData.vivoxServer, gameData.vivoxDomain, gameData.vivoxTokenIssuer, gameData.vivoxTokenKey); | |
| #if UNITY_ANDROID && !UNITY_EDITOR | |
| // Initialize the VivoxNative module | |
| AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); | |
| AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); | |
| AndroidJavaObject appContext = activity.Call<AndroidJavaObject>("getApplicationContext"); | |
| AndroidJavaClass pluginClass = new AndroidJavaClass("com.vivox.vivoxnative.VivoxNative"); | |
| pluginClass.CallStatic("init", appContext); | |
| #endif | |
| } | |
| public SkyjoGameManager SkyjoGame; | |
| /// <summary> | |
| /// Init Vivxo when private game starts | |
| /// </summary> | |
| public void Init(SkyjoGameManager skyjoGame) | |
| { | |
| Game.Log($"Vivox Init......................"); | |
| #if UNITY_EDITOR | |
| return; | |
| #endif | |
| SkyjoGame = skyjoGame; | |
| InitService(); | |
| LoginToVivoxService(); | |
| mutedWhenPaused = false; | |
| } | |
| private void InitService() | |
| { | |
| if (_config.serverURI.ToString() == "https://GETFROMPORTAL.www.vivox.com/api2" || | |
| _config.domain == "GET VALUE FROM VIVOX DEVELOPER PORTAL" || | |
| _config.tokenKey == "GET VALUE FROM VIVOX DEVELOPER PORTAL" || | |
| _config.tokenIssuer == "GET VALUE FROM VIVOX DEVELOPER PORTAL") | |
| { | |
| Game.Log("Vivox. The default VivoxVoiceServer values (Server, Domain, TokenIssuer, and TokenKey) must be replaced with application specific issuer and key values from your developer account."); | |
| } | |
| _client?.Uninitialize(); | |
| if (_client == null) | |
| _client = new Client(); | |
| _client?.Initialize(); | |
| } | |
| //public BankruptGameManager mGame; | |
| /// <summary> | |
| /// Check for permission before starting the game and get the permission if not granted | |
| /// </summary> | |
| public void CheckForPermission() | |
| { | |
| Game.Log($"CheckForPermission hasMicPermission {hasMicPermission}"); | |
| #if UNITY_ANDROID | |
| if (!hasMicPermission) | |
| { | |
| //mGame.OnShowVoiceChatPermissionDialog(); | |
| //DialogBox.Show(Game.GetLocTxt(LKeys.ALERT), Game.GetLocTxt(LKeys.MICPER), Game.GetLocTxt(LKeys.ALLOW), Game.GetLocTxt(LKeys.CANCEL), (allow, cancel) => | |
| //{ | |
| // if (allow) | |
| // { | |
| // Permission.RequestUserPermission(Permission.Microphone); | |
| // } | |
| //}); | |
| } | |
| #elif UNITY_IOS | |
| PermissionSelf result = PermissionPluginForIOS.CheckPermission(PermissionType.Microphone); | |
| if (result == PermissionSelf.ShouldAsk) | |
| { | |
| //mGame.ShowEnableChat(); | |
| //DialogBox.Show(Game.GetLocTxt(LKeys.ALERT), Game.GetLocTxt(LKeys.MICPER), Game.GetLocTxt(LKeys.ALLOW), Game.GetLocTxt(LKeys.CANCEL), (allow, cancel) => | |
| //{ | |
| // if (allow) | |
| // { | |
| //PermissionSelf res = PermissionPluginForIOS.RequestPermission(PermissionType.Microphone); | |
| //Game.Log($"Res {res}"); | |
| //if (res == PermissionSelf.Denied) | |
| // DialogBox.ShowToastMessage(Game.GetLocTxt(LKeys.ALLOWLATER)); | |
| // } | |
| //}); | |
| } | |
| #endif | |
| } | |
| private AndroidPermissionsUsageExample ChatCallBack; | |
| public void AllowChat_iOS(AndroidPermissionsUsageExample callback) | |
| { | |
| ChatCallBack = callback; | |
| #if UNITY_IOS | |
| PermissionSelf res = PermissionPluginForIOS.RequestPermission(PermissionType.Microphone); | |
| Debug.Log("Result: " + res); | |
| StartCoroutine(CheckAfterAWhile()); | |
| #endif | |
| } | |
| #if UNITY_IOS | |
| IEnumerator CheckAfterAWhile() | |
| { | |
| yield return new WaitForSeconds(1f); | |
| PermissionSelf res = PermissionPluginForIOS.CheckPermission(PermissionType.Microphone); | |
| if (res == PermissionSelf.Granted) | |
| { | |
| Debug.Log("Granted Voice chat"); | |
| ChatCallBack.SkyjoGame.OnGrantedPermission(); | |
| } | |
| else if (res == PermissionSelf.Denied) | |
| { | |
| Debug.Log("Denied Voice chat"); | |
| ChatCallBack.SkyjoGame.OnUserDeniedPermission(); | |
| } | |
| } | |
| #endif | |
| //System.Collections.IEnumerator ICheckForIOSPermission() | |
| //{ | |
| // yield return Application.RequestUserAuthorization(UserAuthorization.Microphone); | |
| // if (Application.HasUserAuthorization(UserAuthorization.Microphone)) | |
| // { | |
| // Game.Log("Authorized"); | |
| // } | |
| // else | |
| // { | |
| // Game.Log("Not Authorized"); | |
| // } | |
| //} | |
| private void LoginToVivoxService() | |
| { | |
| if (hasMicPermission) | |
| { | |
| // The user authorized use of the microphone. | |
| TryLogin(); | |
| } | |
| else | |
| { | |
| Game.Log("No mic permission"); | |
| Client.Cleanup(); | |
| _client?.Uninitialize(); | |
| _client = null; | |
| } | |
| //else | |
| //{ | |
| // // Check if the users has already denied permissions | |
| // if (PermissionsDenied) | |
| // { | |
| // PermissionsDenied = false; | |
| // TryLogin(); | |
| // } | |
| // else | |
| // { | |
| // PermissionsDenied = true; | |
| // CheckForPermission(); | |
| // } | |
| //} | |
| } | |
| private void TryLogin() | |
| { | |
| Login(PlayerProfile.playFabID, PlayerProfile.playFabID, (success) => | |
| { | |
| Game.roomName = SkyjoGame.Photon.GetRoomName();// PhotonNetwork.room.Name;//.Photon.GetRoomName(); | |
| Game.Log($"Vivox. LoginCallback succes? {success} roomName {Game.roomName}"); | |
| if (success && !string.IsNullOrEmpty(Game.roomName)) | |
| JoinChannel(Game.roomName, ChannelType.NonPositional); | |
| }); | |
| } | |
| private void OnApplicationQuit() | |
| { | |
| // Needed to add this to prevent some unsuccessful uninit, we can revisit to do better -carlo | |
| Client.Cleanup(); | |
| Game.Log("Vivox. Uninitializing client."); | |
| _client?.Uninitialize(); | |
| _client = null; | |
| } | |
| int backgroundTaskID = -1; | |
| bool mutedWhenPaused = false; | |
| void OnApplicationPause(bool paused) | |
| { | |
| // Start the counter on pause | |
| if (paused) | |
| { | |
| // Start a task that invokes once every second (1000 milliseconds) | |
| //backgroundTaskID = Vuopaja.TaskInvoker.StartTask(1000, (_) => | |
| //{ | |
| // if (!PhotonManager.instance.inRoom) | |
| // { | |
| // Game.Log($"Logged out from vivox because player was disconnected from photon"); | |
| // try | |
| // { | |
| // Game.Log("Uninitializing client."); | |
| // Logout(); | |
| // Client.Cleanup(); | |
| // _client?.Uninitialize(); | |
| // _client = null; | |
| // } | |
| // catch (Exception) | |
| // { | |
| // } | |
| // } | |
| //}, null); | |
| //if (AudioInputDevices != null && AudioInputDevices.Muted == false) | |
| //{ | |
| // mutedWhenPaused = true; | |
| // ToggleMuteLocalPlayer(true); | |
| //} | |
| } | |
| else | |
| { | |
| //if (AudioInputDevices != null && AudioInputDevices.Muted == true && mutedWhenPaused) | |
| //{ | |
| // mutedWhenPaused = false; | |
| // ToggleMuteLocalPlayer(false); | |
| //} | |
| //if (backgroundTaskID != -1) | |
| // Vuopaja.TaskInvoker.StopTask(backgroundTaskID); | |
| } | |
| } | |
| private void OnDestroy() | |
| { | |
| try | |
| { | |
| if (isInitialized) | |
| Client.Cleanup(); | |
| Game.Log("Vivox. Uninitializing client."); | |
| _client?.Uninitialize(); | |
| _client = null; | |
| } | |
| catch (Exception) | |
| { | |
| } | |
| } | |
| private void Login(string displayName = null, string uniqueID = null, Action<bool> callback = null) | |
| { | |
| Game.Log($"Vivox Login as {displayName} size {displayName.Length}"); | |
| //for proto purposes only, need to get a real token from server eventually | |
| if (_client != null) | |
| { | |
| _accountId = new AccountId(_config.tokenIssuer, uniqueID, _config.domain, displayName); | |
| loginSession = _client.GetLoginSession(_accountId); | |
| loginSession.PropertyChanged += OnLoginSessionPropertyChanged; | |
| loginSession.BeginLogin(_config.serverURI, loginSession.GetLoginToken(_config.tokenKey, _tokenExpiration), SubscriptionMode.Accept, null, null, null, ar => | |
| { | |
| try | |
| { | |
| loginSession.EndLogin(ar); | |
| callback?.Invoke(true); | |
| } | |
| catch (Exception e) | |
| { | |
| // Handle error | |
| Game.Log(e.Message); | |
| // Unbind if we failed to login. | |
| loginSession.PropertyChanged -= OnLoginSessionPropertyChanged; | |
| callback?.Invoke(false); | |
| return; | |
| } | |
| }); | |
| } | |
| } | |
| /// <summary> | |
| /// Logout when photon is disconneted. Dont leave the connection alive after the game is over | |
| /// </summary> | |
| public void Logout() | |
| { | |
| try | |
| { | |
| Debug.Log("Trying to log out"); | |
| if (loginSession != null && LoginState != LoginState.LoggedOut && LoginState != LoginState.LoggingOut) | |
| { | |
| OnUserLoggedOutEvent?.Invoke(); | |
| if (loginSession != null) | |
| { | |
| loginSession.PropertyChanged -= OnLoginSessionPropertyChanged; | |
| loginSession.Logout(); | |
| Client.Cleanup(); | |
| _client?.Uninitialize(); | |
| _client = null; | |
| Game.Log("Log out successful. Should be able to init again."); | |
| } | |
| } | |
| } | |
| catch (Exception e) | |
| { | |
| Game.Log("Caught an exception: " + e.ToString()); | |
| } | |
| } | |
| private void JoinChannel(string channelName, ChannelType channelType, Channel3DProperties properties = null) | |
| { | |
| Game.Log($"Vivox JoinChannel name {channelName}"); | |
| if (LoginState == LoginState.LoggedIn) | |
| { | |
| ChannelId channelId = new ChannelId(_config.tokenIssuer, channelName, _config.domain, channelType, properties); | |
| channelSession = loginSession.GetChannelSession(channelId); | |
| channelSession.PropertyChanged += OnChannelPropertyChanged; | |
| channelSession.Participants.AfterKeyAdded += OnParticipantAdded; | |
| channelSession.Participants.BeforeKeyRemoved += OnParticipantRemoved; | |
| channelSession.Participants.AfterValueUpdated += OnParticipantValueUpdated; | |
| channelSession.MessageLog.AfterItemAdded += OnMessageLogRecieved; | |
| channelSession.SessionArchive.AfterItemAdded += OnSessionArchiveAdded; | |
| channelSession.BeginConnect(true, false, true, channelSession.GetConnectToken(_config.tokenKey, _tokenExpiration), ar => | |
| { | |
| try | |
| { | |
| channelSession.EndConnect(ar); | |
| CacheAlreadyJoinedPlayers(); | |
| } | |
| catch (Exception e) | |
| { | |
| // Handle error | |
| Game.Log($"Vivox. Could not connect to voice channel: {e.Message}", LogType.Error); | |
| return; | |
| } | |
| }); | |
| //channelSession.BeginConnect(chatCapability != ChatCapability.TextOnly, chatCapability != ChatCapability.AudioOnly, transmitPolicy, channelSession.GetConnectToken(_tokenKey, _tokenExpiration), ar => | |
| //{ | |
| // try | |
| // { | |
| // channelSession.EndConnect(ar); | |
| // } | |
| // catch (Exception e) | |
| // { | |
| // // Handle error | |
| // Game.Log($"Could not connect to voice channel: {e.Message}", LogType.Error); | |
| // return; | |
| // } | |
| //}); | |
| } | |
| else | |
| { | |
| Game.Log("Vivox. Cannot join a channel when not logged in.", LogType.Error); | |
| } | |
| } | |
| private void SendTextMessage(string messageToSend, ChannelId channel) | |
| { | |
| if (string.IsNullOrEmpty(messageToSend)) | |
| { | |
| Game.Log("Vivox. Enter a valid message to send", LogType.Error); | |
| return; | |
| } | |
| var channelSession = loginSession.GetChannelSession(channel); | |
| channelSession.BeginSendText(messageToSend, ar => | |
| { | |
| try | |
| { | |
| channelSession.EndSendText(ar); | |
| } | |
| catch (Exception e) | |
| { | |
| Game.Log($"Vivox. SendTextMessage failed with exception {e.Message}"); | |
| } | |
| }); | |
| } | |
| private void SendMatchStatusMessage(MatchStatus status, string playerIp, ChannelId channelId) | |
| { | |
| if (ChannelId.IsNullOrEmpty(channelId)) | |
| { | |
| throw new ArgumentException(string.Format("{0} is null", channelId)); | |
| } | |
| if (string.IsNullOrEmpty(playerIp)) | |
| { | |
| throw new ArgumentException(string.Format("{0} cannot be empty", playerIp)); | |
| } | |
| SendTextMessage(string.Format($"<{status.ToString()}>{_accountId.DisplayName}:{playerIp}"), channelId); | |
| } | |
| public void RunArchiveQueryInChannel(ChannelId channelId, DateTime? timeStart, DateTime? timeEnd, | |
| string searchText = null, uint max = 50, string afterId = null, string beforeId = null, int firstMessageIndex = -1) | |
| { | |
| IChannelSession channelSession = loginSession.GetChannelSession(channelId); | |
| var channelName = channelId.Name; | |
| var senderName = _accountId.Name; | |
| channelSession.BeginSessionArchiveQuery(timeStart, timeEnd, searchText, _accountId, max, afterId, beforeId, firstMessageIndex, ar => | |
| { | |
| try | |
| { | |
| channelSession.EndSessionArchiveQuery(ar); | |
| } | |
| catch (Exception e) | |
| { | |
| // Handle error | |
| Game.Log($"Vivox. Failed to get archive query for channel: {e.Message}", LogType.Error); | |
| return; | |
| } | |
| Debug.Log(channelName + ": " + senderName + ": "); | |
| }); | |
| } | |
| private void DisconnectAllChannels() | |
| { | |
| if (ActiveChannels?.Count > 0) | |
| { | |
| foreach (var channelSession in ActiveChannels) | |
| { | |
| channelSession?.Disconnect(); | |
| } | |
| } | |
| } | |
| #region Vivox Callbacks | |
| private void OnMessageLogRecieved(object sender, QueueItemAddedEventArgs<IChannelTextMessage> textMessage) | |
| { | |
| Game.Log("Vivox. OnMessageLogRecieved"); | |
| ValidateArgs(new object[] { sender, textMessage }); | |
| IChannelTextMessage channelTextMessage = textMessage.Value; | |
| Game.Log(channelTextMessage.Message); | |
| OnTextMessageLogReceivedEvent?.Invoke(channelTextMessage.Sender.DisplayName, channelTextMessage); | |
| } | |
| private void OnSessionArchiveAdded(object sender, QueueItemAddedEventArgs<ISessionArchiveMessage> archiveMessage) | |
| { | |
| Game.Log("Vivox. OnSessionArchiveAdded"); | |
| ValidateArgs(new object[] { sender, archiveMessage }); | |
| ISessionArchiveMessage sessionArchiveMessage = archiveMessage.Value; | |
| OnSessionArchiveMessageReceivedEvent?.Invoke(sessionArchiveMessage.Sender.DisplayName, sessionArchiveMessage); | |
| } | |
| private void OnLoginSessionPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) | |
| { | |
| if (propertyChangedEventArgs.PropertyName != "State") | |
| { | |
| return; | |
| } | |
| var loginSession = (ILoginSession)sender; | |
| LoginState = loginSession.State; | |
| Game.Log("Vivox. Detecting login session change"); | |
| switch (LoginState) | |
| { | |
| case LoginState.LoggingIn: | |
| { | |
| Game.Log("Vivox. Logging in"); | |
| break; | |
| } | |
| case LoginState.LoggedIn: | |
| { | |
| Game.Log($"Vivox. Connected to voice server and logged in"); | |
| OnUserLoggedInEvent?.Invoke(); | |
| break; | |
| } | |
| case LoginState.LoggingOut: | |
| { | |
| Game.Log("Vivox. Logging out"); | |
| break; | |
| } | |
| case LoginState.LoggedOut: | |
| { | |
| Game.Log("Vivox. Logged out"); | |
| this.loginSession.PropertyChanged -= OnLoginSessionPropertyChanged; | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| } | |
| private void OnParticipantAdded(object sender, KeyEventArg<string> keyEventArg) | |
| { | |
| Game.Log($"Vivox. OnParticipantAdded sender {sender} Key {keyEventArg.Key}"); | |
| ValidateArgs(new object[] { sender, keyEventArg }); | |
| // INFO: sender is the dictionary that changed and trigger the event. Need to cast it back to access it. | |
| var source = (VivoxUnity.IReadOnlyDictionary<string, IParticipant>)sender; | |
| // Look up the participant via the key. | |
| var participant = source[keyEventArg.Key]; | |
| var username = participant.Account.Name; | |
| var channel = participant.ParentChannelSession.Key; | |
| var channelSession = participant.ParentChannelSession; | |
| Game.Log($"Vivox. OnParticipantAdded username {username}"); | |
| if (username.Equals(SystemInfo.deviceUniqueIdentifier)) | |
| _localParticipant = participant; | |
| int playerIndex = SkyjoGame._players.FindIndex(p => p.playfabId == participant.Account.DisplayName); | |
| SkyjoGame.CacheParticipant(playerIndex, participant); | |
| // Trigger callback | |
| OnParticipantAddedEvent?.Invoke(username, channel, participant); | |
| } | |
| private void OnParticipantRemoved(object sender, KeyEventArg<string> keyEventArg) | |
| { | |
| Game.Log($"Vivox. OnParticipantRemoved sender {sender}"); | |
| ValidateArgs(new object[] { sender, keyEventArg }); | |
| // INFO: sender is the dictionary that changed and trigger the event. Need to cast it back to access it. | |
| var source = (VivoxUnity.IReadOnlyDictionary<string, IParticipant>)sender; | |
| // Look up the participant via the key. | |
| var participant = source[keyEventArg.Key]; | |
| var username = participant.Account.Name; | |
| var channel = participant.ParentChannelSession.Key; | |
| var channelSession = participant.ParentChannelSession; | |
| Game.Log($"Vivox. OnParticipantRemoved participant {participant} IsSelf {participant.IsSelf}"); | |
| if (participant.IsSelf) | |
| { | |
| Game.Log($"Vivox. Unsubscribing from: {channelSession.Key.Name}"); | |
| // Now that we are disconnected, unsubscribe. | |
| channelSession.PropertyChanged -= OnChannelPropertyChanged; | |
| channelSession.Participants.AfterKeyAdded -= OnParticipantAdded; | |
| channelSession.Participants.BeforeKeyRemoved -= OnParticipantRemoved; | |
| channelSession.Participants.AfterValueUpdated -= OnParticipantValueUpdated; | |
| channelSession.MessageLog.AfterItemAdded -= OnMessageLogRecieved; | |
| channelSession.SessionArchive.AfterItemAdded -= OnSessionArchiveAdded; | |
| // Remove session. | |
| var user = _client.GetLoginSession(_accountId); | |
| user.DeleteChannelSession(channelSession.Channel); | |
| } | |
| // Trigger callback | |
| OnParticipantRemovedEvent?.Invoke(username, channel, participant); | |
| } | |
| private static void ValidateArgs(object[] objs) | |
| { | |
| foreach (var obj in objs) | |
| { | |
| if (obj == null) | |
| throw new ArgumentNullException(obj.GetType().ToString(), "Specify a non-null/non-empty argument."); | |
| } | |
| } | |
| private void OnParticipantValueUpdated(object sender, ValueEventArg<string, IParticipant> valueEventArg) | |
| { | |
| #if !UNITY_EDITOR | |
| // Game.Log($"Vivox. OnSpeechDetectedEvent: ParticipantId {valueEventArg.Value.ParticipantId} DisplayName {valueEventArg.Value.Account.DisplayName} Name {valueEventArg.Value.Account.Name}"); | |
| #endif | |
| // Game.Log($"OnParticipantValueUpdated sender {sender} PropertyName{valueEventArg.PropertyName}"); | |
| ValidateArgs(new object[] { sender, valueEventArg }); | |
| var source = (VivoxUnity.IReadOnlyDictionary<string, IParticipant>)sender; | |
| // Look up the participant via the key. | |
| var participant = source[valueEventArg.Key]; | |
| string username = valueEventArg.Value.Account.Name; | |
| ChannelId channel = valueEventArg.Value.ParentChannelSession.Key; | |
| string property = valueEventArg.PropertyName; | |
| switch (property) | |
| { | |
| case "SpeechDetected": | |
| { | |
| // Game.Log($"OnSpeechDetectedEvent"); | |
| OnSpeechDetectedEvent?.Invoke(username, channel, valueEventArg.Value.SpeechDetected); | |
| break; | |
| } | |
| case "AudioEnergy": | |
| { | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| } | |
| private void OnChannelPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) | |
| { | |
| Game.Log($"Vivox. OnChannelPropertyChanged sender {sender} PropertyName {propertyChangedEventArgs.PropertyName}"); | |
| ValidateArgs(new object[] { sender, propertyChangedEventArgs }); | |
| //if (_client == null) | |
| // throw new InvalidClient("Invalid client."); | |
| var channelSession = (IChannelSession)sender; | |
| // IF the channel has removed audio, make sure all the VAD indicators aren't showing speaking. | |
| if (propertyChangedEventArgs.PropertyName == "AudioState" && channelSession.AudioState == VivoxUnity.ConnectionState.Disconnected) | |
| { | |
| Game.Log($"Vivox. Audio disconnected from: {channelSession.Key.Name}"); | |
| foreach (var participant in channelSession.Participants) | |
| { | |
| OnSpeechDetectedEvent?.Invoke(participant.Account.Name, channelSession.Channel, false); | |
| } | |
| } | |
| // IF the channel has fully disconnected, unsubscribe and remove. | |
| if ((propertyChangedEventArgs.PropertyName == "AudioState" || propertyChangedEventArgs.PropertyName == "TextState") && | |
| channelSession.AudioState == VivoxUnity.ConnectionState.Disconnected && | |
| channelSession.TextState == VivoxUnity.ConnectionState.Disconnected) | |
| { | |
| Game.Log($"Vivox. Unsubscribing from: {channelSession.Key.Name}"); | |
| // Now that we are disconnected, unsubscribe. | |
| channelSession.PropertyChanged -= OnChannelPropertyChanged; | |
| channelSession.Participants.AfterKeyAdded -= OnParticipantAdded; | |
| channelSession.Participants.BeforeKeyRemoved -= OnParticipantRemoved; | |
| channelSession.Participants.AfterValueUpdated -= OnParticipantValueUpdated; | |
| channelSession.MessageLog.AfterItemAdded -= OnMessageLogRecieved; | |
| channelSession.SessionArchive.AfterItemAdded -= OnSessionArchiveAdded; | |
| // Remove session. | |
| var user = _client.GetLoginSession(_accountId); | |
| user.DeleteChannelSession(channelSession.Channel); | |
| } | |
| if (propertyChangedEventArgs.PropertyName == "SessionArchiveResult") | |
| { | |
| // TODO Let's flesh out the expected behaviour when this occurs. Adding this as a placeholder for now. | |
| Game.Log("Session archive result change detected!"); | |
| } | |
| } | |
| #endregion | |
| public void ToggleMuteLocalPlayer(bool mute) | |
| { | |
| try | |
| { | |
| AudioInputDevices.Muted = mute; | |
| } | |
| catch (Exception) | |
| { | |
| } | |
| } | |
| public bool IsLocalPlayerMuted() | |
| { | |
| return AudioInputDevices.Muted; | |
| } | |
| public void ToggleMutePlayer(IParticipant participant, int playerID, bool mute) | |
| { | |
| try | |
| { | |
| if (participant != null) | |
| participant.LocalMute = mute; | |
| else | |
| { | |
| // DialogBox.ShowToastMessage($"participant is null {playerID}"); | |
| Game.Log($"Vivox. participant is null........."); | |
| } | |
| } | |
| catch (Exception) | |
| { | |
| } | |
| } | |
| private void CacheAlreadyJoinedPlayers() | |
| { | |
| int participantsCount = channelSession?.Participants.Count ?? 0; | |
| Game.Log($"Vivox. CacheAlreadyJoinedPlayers count {participantsCount}"); | |
| if (participantsCount > 0 && channelSession != null) | |
| { | |
| foreach (IParticipant participant in channelSession.Participants) | |
| { | |
| Game.Log($"Vivox. CacheAlreadyJoinedPlayers name {participant.Account.DisplayName}"); | |
| //CYAPlayer player = CYAGame.Players.Find(p => p.PlayfabID == participant.Account.DisplayName); | |
| //player.CacheParticipant(participant); | |
| //SkipBoGameManager.instance.FindUIPlayerWithPlayfabID(participant.Account.Name)?.CacheVivoxPlayer(participant); | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment