non-vr lobby, version fix

This commit is contained in:
joonasp
2022-06-29 14:45:17 +03:00
parent 5774be9822
commit 04baadfad1
1774 changed files with 573069 additions and 1533 deletions

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: ecb985625034aef4681a3a80b40cc5ed
folderAsset: yes
timeCreated: 1537958667
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
{
"name": "PhotonVoice.PUN.Editor",
"references": [
"PhotonVoice.PUN",
"PhotonVoice.Editor",
"PhotonVoice",
"PhotonRealtime",
"PhotonUnityNetworking"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": []
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: bc45562f375e105438d27eded7d73e12
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,73 @@
using System;
namespace Photon.Voice.PUN.Editor
{
using Unity.Editor;
using UnityEditor;
using UnityEngine;
using Pun;
[CustomEditor(typeof(PhotonVoiceNetwork))]
public class PhotonVoiceNetworkEditor : VoiceConnectionEditor
{
private SerializedProperty autoConnectAndJoinSp;
private SerializedProperty autoLeaveAndDisconnectSp;
private SerializedProperty usePunAppSettingsSp;
private SerializedProperty usePunAuthValuesSp;
private SerializedProperty workInOfflineModeSp;
protected override void OnEnable()
{
base.OnEnable();
this.autoConnectAndJoinSp = this.serializedObject.FindProperty("AutoConnectAndJoin");
this.autoLeaveAndDisconnectSp = this.serializedObject.FindProperty("AutoLeaveAndDisconnect");
this.usePunAppSettingsSp = this.serializedObject.FindProperty("usePunAppSettings");
this.usePunAuthValuesSp = this.serializedObject.FindProperty("usePunAuthValues");
this.workInOfflineModeSp = this.serializedObject.FindProperty("WorkInOfflineMode");
}
protected override void DisplayAppSettings()
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(this.usePunAppSettingsSp, new GUIContent("Use PUN's App Settings", "Use App Settings From PUN's PhotonServerSettings"));
if (GUILayout.Button("PhotonServerSettings", EditorStyles.miniButton, GUILayout.Width(120)))
{
Selection.objects = new Object[] { PhotonNetwork.PhotonServerSettings };
EditorGUIUtility.PingObject(PhotonNetwork.PhotonServerSettings);
}
EditorGUILayout.EndHorizontal();
if (!this.usePunAppSettingsSp.boolValue)
{
base.DisplayAppSettings();
}
EditorGUILayout.PropertyField(this.usePunAuthValuesSp, new GUIContent("Use PUN's Auth Values", "Use the same Authentication Values From PUN client"));
}
protected override void ShowHeader()
{
base.ShowHeader();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(this.autoConnectAndJoinSp, new GUIContent("Auto Connect And Join", "Auto connect voice client and join a voice room when PUN client is joined to a PUN room"));
EditorGUILayout.PropertyField(this.autoLeaveAndDisconnectSp, new GUIContent("Auto Leave And Disconnect", "Auto disconnect voice client when PUN client is not joined to a PUN room"));
EditorGUILayout.PropertyField(this.workInOfflineModeSp, new GUIContent("Work In Offline Mode", "Whether or not Photon Voice client should follow PUN client if the latter is in offline mode."));
if (EditorGUI.EndChangeCheck())
{
this.serializedObject.ApplyModifiedProperties();
}
}
protected override void ShowAssetVersions()
{
base.ShowAssetVersions();
string version = this.GetVersionString(this.punChangelogVersion).TrimStart('v');
if (!PhotonNetwork.PunVersion.Equals(version, StringComparison.OrdinalIgnoreCase))
{
EditorGUILayout.LabelField(string.Format("PUN2, Inside Voice: {0} != Imported Separately: {1}", version, PhotonNetwork.PunVersion));
}
else
{
EditorGUILayout.LabelField(string.Format("PUN2: {0}", version));
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: fa70a22b498b27f41a0bb50f9a287764
timeCreated: 1537357720
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
{
"name": "PhotonVoice.PUN",
"references": [
"PhotonVoice",
"PhotonUnityNetworking",
"PhotonRealtime",
"PhotonVoice.API"
],
"includePlatforms": [],
"excludePlatforms": []
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d62e4537d6f8ca64c8d2affe565a5cd1
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,598 @@
// ----------------------------------------------------------------------------
// <copyright file="PhotonVoiceNetwork.cs" company="Exit Games GmbH">
// Photon Voice - Copyright (C) 2018 Exit Games GmbH
// </copyright>
// <summary>
// This class can be used to automatically join/leave Voice rooms when
// Photon Unity Networking (PUN) joins or leaves its rooms. The Voice room
// will use the same name as PUN, but with a "_voice_" postfix.
// It also sets a custom PUN Speaker factory to find the Speaker
// component for a character's voice. For this to work, the voice's UserData
// must be set to the character's PhotonView ID.
// (see "PhotonVoiceView.cs")
// </summary>
// <author>developer@photonengine.com</author>
// ----------------------------------------------------------------------------
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using Photon.Voice.Unity;
namespace Photon.Voice.PUN
{
/// <summary>
/// This class can be used to automatically sync client states between PUN and Voice.
/// It also sets a custom PUN Speaker factory to find the Speaker component for a character's voice.
/// For this to work attach a <see cref="PhotonVoiceView"/> next to the <see cref="PhotonView"/> of your player's prefab.
/// </summary>
[DisallowMultipleComponent]
[AddComponentMenu("Photon Voice/Photon Voice Network")]
[HelpURL("https://doc.photonengine.com/en-us/voice/v2/getting-started/voice-for-pun")]
public class PhotonVoiceNetwork : VoiceConnection
{
#region Public Fields
/// <summary> Suffix for voice room names appended to PUN room names. </summary>
public const string VoiceRoomNameSuffix = "_voice_";
/// <summary> Auto connect voice client and join a voice room when PUN client is joined to a PUN room </summary>
public bool AutoConnectAndJoin = true;
/// <summary> Auto disconnect voice client when PUN client is not joined to a PUN room </summary>
public bool AutoLeaveAndDisconnect = true;
/// <summary> Whether or not Photon Voice client should follow PUN client if the latter is in offline mode. </summary>
public bool WorkInOfflineMode = true;
#endregion
#region Private Fields
private EnterRoomParams voiceRoomParams = new EnterRoomParams
{
RoomOptions = new RoomOptions { IsVisible = false }
};
private bool clientCalledConnectAndJoin;
private bool clientCalledDisconnect;
private bool clientCalledConnectOnly;
private bool internalDisconnect;
private bool internalConnect;
private static object instanceLock = new object();
private static PhotonVoiceNetwork instance;
private static bool instantiated;
[SerializeField]
private bool usePunAppSettings = true;
[SerializeField]
private bool usePunAuthValues = true;
#endregion
#region Properties
/// <summary>
/// Singleton instance for PhotonVoiceNetwork
/// </summary>
public static PhotonVoiceNetwork Instance
{
get
{
lock (instanceLock)
{
if (AppQuits)
{
if (instance.Logger.IsWarningEnabled)
{
instance.Logger.LogWarning("PhotonVoiceNetwork Instance already destroyed on application quit. Won't create again - returning null.");
}
return null;
}
if (!instantiated)
{
PhotonVoiceNetwork[] objects = FindObjectsOfType<PhotonVoiceNetwork>();
if (objects == null || objects.Length < 1)
{
GameObject singleton = new GameObject();
singleton.name = "PhotonVoiceNetwork singleton";
instance = singleton.AddComponent<PhotonVoiceNetwork>();
if (instance.Logger.IsInfoEnabled)
{
instance.Logger.LogInfo("An instance of PhotonVoiceNetwork was automatically created in the scene.");
}
}
else if (objects.Length >= 1)
{
instance = objects[0];
if (objects.Length > 1)
{
if (instance.Logger.IsErrorEnabled)
{
instance.Logger.LogError("{0} PhotonVoiceNetwork instances found. Using first one only and destroying all the other extra instances.", objects.Length);
}
for (int i = 1; i < objects.Length; i++)
{
Destroy(objects[i]);
}
}
}
instantiated = true;
if (instance.Logger.IsDebugEnabled)
{
instance.Logger.LogDebug("PhotonVoiceNetwork singleton instance is now set.");
}
}
return instance;
}
}
set
{
lock (instanceLock)
{
if (value == null)
{
if (instantiated)
{
if (instance.Logger.IsErrorEnabled)
{
instance.Logger.LogError("Cannot set PhotonVoiceNetwork.Instance to null.");
}
}
else
{
Debug.LogError("Cannot set PhotonVoiceNetwork.Instance to null.");
}
return;
}
if (instantiated)
{
if (instance.GetInstanceID() != value.GetInstanceID())
{
if (instance.Logger.IsErrorEnabled)
{
instance.Logger.LogError("An instance of PhotonVoiceNetwork is already set. Destroying extra instance.");
}
Destroy(value);
}
return;
}
instance = value;
instantiated = true;
if (instance.Logger.IsDebugEnabled)
{
instance.Logger.LogDebug("PhotonVoiceNetwork singleton instance is now set.");
}
}
}
}
/// <summary>
/// Whether or not to use the same PhotonNetwork.AuthValues in PhotonVoiceNetwork.Instance.Client.AuthValues.
/// This means that the same UserID will be used in both clients.
/// If custom authentication is used and setup in PUN app, the same configuration should be done for the Voice app.
/// </summary>
public bool UsePunAuthValues
{
get
{
return this.usePunAuthValues;
}
set
{
this.usePunAuthValues = value;
}
}
#endregion
#region Public Methods
/// <summary>
/// Connect voice client to Photon servers and join a Voice room
/// </summary>
/// <returns>If true, connection command send from client</returns>
public bool ConnectAndJoinRoom()
{
if (!PhotonNetwork.InRoom)
{
if (this.Logger.IsErrorEnabled)
{
this.Logger.LogError("Cannot connect and join if PUN is not joined.");
}
return false;
}
if (this.Connect())
{
this.clientCalledConnectAndJoin = true;
this.clientCalledDisconnect = false;
return true;
}
if (this.Logger.IsErrorEnabled)
{
this.Logger.LogError("Connecting to server failed.");
}
return false;
}
/// <summary>
/// Disconnect voice client from all Photon servers
/// </summary>
public void Disconnect()
{
if (!this.Client.IsConnected)
{
if (this.Logger.IsErrorEnabled)
{
this.Logger.LogError("Cannot Disconnect if not connected.");
}
return;
}
this.clientCalledDisconnect = true;
this.clientCalledConnectAndJoin = false;
this.clientCalledConnectOnly = false;
this.Client.Disconnect();
}
#endregion
#region Private Methods
protected override void Awake()
{
Instance = this;
lock (instanceLock)
{
if (instantiated && instance.GetInstanceID() == this.GetInstanceID())
{
base.Awake();
}
}
}
private void OnEnable()
{
PhotonNetwork.NetworkingClient.StateChanged += this.OnPunStateChanged;
this.FollowPun(); // in case this is enabled or activated late
this.clientCalledConnectAndJoin = false;
this.clientCalledConnectOnly = false;
this.clientCalledDisconnect = false;
this.internalDisconnect = false;
}
protected override void OnDisable()
{
base.OnDisable();
PhotonNetwork.NetworkingClient.StateChanged -= this.OnPunStateChanged;
}
protected override void OnDestroy()
{
base.OnDestroy();
lock (instanceLock)
{
if (instantiated && instance.GetInstanceID() == this.GetInstanceID())
{
instantiated = false;
if (instance.Logger.IsDebugEnabled)
{
instance.Logger.LogDebug("PhotonVoiceNetwork singleton instance is being reset because destroyed.");
}
instance = null;
}
}
}
private void OnPunStateChanged(ClientState fromState, ClientState toState)
{
if (this.Logger.IsDebugEnabled)
{
this.Logger.LogDebug("OnPunStateChanged from {0} to {1}", fromState, toState);
}
this.FollowPun(toState);
}
protected override void OnVoiceStateChanged(ClientState fromState, ClientState toState)
{
base.OnVoiceStateChanged(fromState, toState);
if (toState == ClientState.Disconnected)
{
if (this.internalDisconnect)
{
this.internalDisconnect = false;
}
else if (!this.clientCalledDisconnect)
{
this.clientCalledDisconnect = this.Client.DisconnectedCause == DisconnectCause.DisconnectByClientLogic;
}
}
else if (toState == ClientState.ConnectedToMasterServer)
{
if (this.internalConnect)
{
this.internalConnect = false;
}
else if (!this.clientCalledConnectOnly && !this.clientCalledConnectAndJoin)
{
this.clientCalledConnectOnly = true;
this.clientCalledDisconnect = false;
}
}
this.FollowPun(toState);
}
private void FollowPun(ClientState toState)
{
switch (toState)
{
case ClientState.Joined:
case ClientState.Disconnected:
case ClientState.ConnectedToMasterServer:
this.FollowPun();
break;
}
}
protected override Speaker SimpleSpeakerFactory(int playerId, byte voiceId, object userData)
{
if (!(userData is int))
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("UserData ({0}) does not contain PhotonViewId. Remote voice {1}/{2} not linked. Do you have a Recorder not used with a PhotonVoiceView? is this expected?",
userData == null ? "null" : userData.ToString(), playerId, voiceId);
}
return null;
}
int photonViewId = (int)userData;
PhotonView photonView = PhotonView.Find(photonViewId);
if (photonView == null)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("No PhotonView with ID {0} found. Remote voice {1}/{2} not linked.", userData, playerId, voiceId);
}
return null;
}
PhotonVoiceView photonVoiceView = photonView.GetComponent<PhotonVoiceView>();
if (photonVoiceView == null)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("No PhotonVoiceView attached to the PhotonView with ID {0}. Remote voice {1}/{2} not linked.", userData, playerId, voiceId);
}
return null;
}
if (!photonVoiceView.IgnoreGlobalLogLevel)
{
photonVoiceView.LogLevel = this.LogLevel;
}
if (!photonVoiceView.IsSpeaker)
{
photonVoiceView.SetupSpeakerInUse();
}
return photonVoiceView.SpeakerInUse;
}
internal static string GetVoiceRoomName()
{
if (PhotonNetwork.InRoom)
{
return string.Format("{0}{1}", PhotonNetwork.CurrentRoom.Name, VoiceRoomNameSuffix);
}
return null;
}
private void ConnectOrJoin()
{
switch (this.ClientState)
{
case ClientState.PeerCreated:
case ClientState.Disconnected:
if (this.Logger.IsInfoEnabled)
{
this.Logger.LogInfo("PUN joined room, now connecting Voice client");
}
if (!this.Connect())
{
if (this.Logger.IsErrorEnabled)
{
this.Logger.LogError("Connecting to server failed.");
}
}
else
{
this.internalConnect = this.AutoConnectAndJoin && !this.clientCalledConnectOnly && !this.clientCalledConnectAndJoin;
}
break;
case ClientState.ConnectedToMasterServer:
if (this.Logger.IsInfoEnabled)
{
this.Logger.LogInfo("PUN joined room, now joining Voice room");
}
if (!this.JoinRoom(GetVoiceRoomName()))
{
if (this.Logger.IsErrorEnabled)
{
this.Logger.LogError("Joining a voice room failed.");
}
}
break;
default:
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("PUN joined room, Voice client is busy ({0}). Is this expected?", this.ClientState);
}
break;
}
}
private bool Connect()
{
AppSettings settings = null;
if (this.usePunAppSettings)
{
settings = new AppSettings();
settings = PhotonNetwork.PhotonServerSettings.AppSettings.CopyTo(settings); // creates an independent copy (cause we need to modify it slightly)
if (!string.IsNullOrEmpty(PhotonNetwork.CloudRegion))
{
settings.FixedRegion = PhotonNetwork.CloudRegion; // makes sure the voice connection follows into the same cloud region (as PUN uses now).
}
this.Client.SerializationProtocol = PhotonNetwork.NetworkingClient.SerializationProtocol;
}
// use the same user, authentication, auth-mode and encryption as PUN
if (this.UsePunAuthValues)
{
if (PhotonNetwork.AuthValues != null)
{
if (this.Client.AuthValues == null)
{
this.Client.AuthValues = new AuthenticationValues();
}
this.Client.AuthValues = PhotonNetwork.AuthValues.CopyTo(this.Client.AuthValues);
}
this.Client.AuthMode = PhotonNetwork.NetworkingClient.AuthMode;
this.Client.EncryptionMode = PhotonNetwork.NetworkingClient.EncryptionMode;
}
return this.ConnectUsingSettings(settings);
}
private bool JoinRoom(string voiceRoomName)
{
if (string.IsNullOrEmpty(voiceRoomName))
{
if (this.Logger.IsErrorEnabled)
{
this.Logger.LogError("Voice room name is null or empty.");
}
return false;
}
this.voiceRoomParams.RoomName = voiceRoomName;
return this.Client.OpJoinOrCreateRoom(this.voiceRoomParams);
}
// Follow PUN client state
// In case Voice client disconnects unexpectedly try to reconnect to the same room
// In case Voice client is connected to the wrong room switch to the correct one
private void FollowPun()
{
if (AppQuits)
{
return;
}
if (PhotonNetwork.OfflineMode && !this.WorkInOfflineMode)
{
return;
}
if (PhotonNetwork.NetworkClientState == this.ClientState)
{
if (PhotonNetwork.InRoom && this.AutoConnectAndJoin)
{
string expectedRoomName = GetVoiceRoomName();
string currentRoomName = this.Client.CurrentRoom.Name;
if (!currentRoomName.Equals(expectedRoomName))
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning(
"Voice room mismatch: Expected:\"{0}\" Current:\"{1}\", leaving the second to join the first.",
expectedRoomName, currentRoomName);
}
if (!this.Client.OpLeaveRoom(false))
{
if (this.Logger.IsErrorEnabled)
{
this.Logger.LogError("Leaving the current voice room failed.");
}
}
}
}
else if (this.ClientState == ClientState.ConnectedToMasterServer && this.AutoLeaveAndDisconnect && !this.clientCalledConnectAndJoin && !this.clientCalledConnectOnly)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Unexpected: PUN and Voice clients have the same client state: ConnectedToMasterServer, Disconnecting Voice client.");
}
this.internalDisconnect = true;
this.Client.Disconnect();
}
return;
}
if (PhotonNetwork.InRoom)
{
if (this.clientCalledConnectAndJoin || this.AutoConnectAndJoin && !this.clientCalledDisconnect)
{
this.ConnectOrJoin();
}
}
else if (this.Client.InRoom && this.AutoLeaveAndDisconnect && !this.clientCalledConnectAndJoin && !this.clientCalledConnectOnly)
{
if (this.Logger.IsInfoEnabled)
{
this.Logger.LogInfo("PUN left room, disconnecting Voice");
}
this.internalDisconnect = true;
this.Client.Disconnect();
}
}
internal void CheckLateLinking(Speaker speaker, int viewId)
{
if (!speaker || speaker == null)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Cannot check late linking for null Speaker");
}
return;
}
if (viewId <= 0)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Cannot check late linking for ViewID = {0} (<= 0)", viewId);
}
return;
}
if (!this.Client.InRoom)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Cannot check late linking while not joined to a voice room, client state: {0}", System.Enum.GetName(typeof(ClientState), this.ClientState));
}
return;
}
for (int i = 0; i < this.cachedRemoteVoices.Count; i++)
{
RemoteVoiceLink remoteVoice = this.cachedRemoteVoices[i];
if (remoteVoice.Info.UserData is int)
{
int photonViewId = (int)remoteVoice.Info.UserData;
if (viewId == photonViewId)
{
if (this.Logger.IsInfoEnabled)
{
this.Logger.LogInfo("Speaker 'late-linking' for the PhotonView with ID {0} with remote voice {1}/{2}.", viewId, remoteVoice.PlayerId, remoteVoice.VoiceId);
}
this.LinkSpeaker(speaker, remoteVoice);
break;
}
}
else if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("VoiceInfo.UserData should be int/ViewId, received: {0}, do you have a Recorder not used with a PhotonVoiceView? is this expected?",
remoteVoice.Info.UserData == null ? "null" : string.Format("{0} ({1})", remoteVoice.Info.UserData, remoteVoice.Info.UserData.GetType()));
if (remoteVoice.PlayerId == viewId / PhotonNetwork.MAX_VIEW_IDS)
{
this.Logger.LogWarning("Player with ActorNumber {0} has started recording (voice # {1}) too early without setting a ViewId maybe? (before PhotonVoiceView setup)", remoteVoice.PlayerId, remoteVoice.VoiceId);
}
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 81d9debcbaf99472bb70ffc2f99cb23f
timeCreated: 1540904568
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: dd940d333aeeaa048842e87b9b259188, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,501 @@
// ----------------------------------------------------------------------------
// <copyright file="PhotonVoiceView.cs" company="Exit Games GmbH">
// Photon Voice - Copyright (C) 2018 Exit Games GmbH
// </copyright>
// <summary>
// Component that should be attached to a networked PUN prefab that has
// PhotonView. It will bind remote Recorder with local Speaker of the same
// networked prefab. This component makes automatic voice stream routing easy
// for players' characters/avatars.
// </summary>
// <author>developer@photonengine.com</author>
// ----------------------------------------------------------------------------
namespace Photon.Voice.PUN
{
using Pun;
using UnityEngine;
using Unity;
/// <summary>
/// Component that should be attached to a networked PUN prefab that has <see cref="PhotonView"/>.
/// It will bind remote <see cref="Recorder"/> with local <see cref="Speaker"/> of the same networked prefab.
/// This component makes automatic voice stream routing easy for players' characters/avatars.
/// </summary>
[AddComponentMenu("Photon Voice/Photon Voice View")]
[RequireComponent(typeof(PhotonView))]
[HelpURL("https://doc.photonengine.com/en-us/voice/v2/getting-started/voice-for-pun")]
public class PhotonVoiceView : VoiceComponent
{
#region Private Fields
private PhotonView photonView;
[SerializeField]
private Recorder recorderInUse;
[SerializeField]
private Speaker speakerInUse;
private bool onEnableCalledOnce;
#endregion
#region Public Fields
/// <summary> If true, a Recorder component will be added to the same GameObject if not found already. </summary>
public bool AutoCreateRecorderIfNotFound;
/// <summary> If true, PhotonVoiceNetwork.PrimaryRecorder will be used by this PhotonVoiceView </summary>
public bool UsePrimaryRecorder;
/// <summary> If true, a Speaker component will be setup to be used for the DebugEcho mode </summary>
public bool SetupDebugSpeaker;
#endregion
#region Properties
/// <summary> The Recorder component currently used by this PhotonVoiceView </summary>
public Recorder RecorderInUse
{
get
{
return this.recorderInUse;
}
set
{
if (value != this.recorderInUse)
{
this.recorderInUse = value;
this.IsRecorder = false;
}
if (this.RequiresRecorder)
{
this.SetupRecorderInUse();
}
else if (this.IsPhotonViewReady)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("No need to set Recorder as the PhotonView does not belong to local player");
}
}
}
}
/// <summary> The Speaker component currently used by this PhotonVoiceView </summary>
public Speaker SpeakerInUse
{
get
{
return this.speakerInUse;
}
set
{
if (this.speakerInUse != value)
{
this.speakerInUse = value;
this.IsSpeaker = false;
}
if (this.RequiresSpeaker)
{
this.SetupSpeakerInUse();
}
else if (this.IsPhotonViewReady)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Speaker not set because the PhotonView does not belong to a remote player or SetupDebugSpeaker is disabled");
}
}
}
}
/// <summary> If true, this PhotonVoiceView is setup and ready to be used </summary>
public bool IsSetup
{
get { return this.IsPhotonViewReady && (!this.RequiresRecorder || this.IsRecorder) && (!this.RequiresSpeaker || this.IsSpeaker); }
}
/// <summary> If true, this PhotonVoiceView has a Speaker setup for playback of received audio frames from remote audio source </summary>
public bool IsSpeaker { get; private set; }
/// <summary> If true, this PhotonVoiceView has a Speaker that is currently playing received audio frames from remote audio source </summary>
public bool IsSpeaking
{
get { return this.IsSpeaker && this.SpeakerInUse.IsPlaying; }
}
/// <summary> If true, this PhotonVoiceView has a Recorder setup for transmission of audio stream from local audio source </summary>
public bool IsRecorder { get; private set; }
/// <summary> If true, this PhotonVoiceView has a Recorder that is currently transmitting audio stream from local audio source </summary>
public bool IsRecording
{
get { return this.IsRecorder && this.RecorderInUse.IsCurrentlyTransmitting; }
}
/// <summary> If true, the SpeakerInUse is linked to the remote voice stream </summary>
public bool IsSpeakerLinked
{
get { return this.IsSpeaker && this.SpeakerInUse.IsLinked; }
}
/// <summary> If true, the PhotonView attached to the same GameObject has a valid ViewID > 0 </summary>
public bool IsPhotonViewReady
{
get { return this.photonView && this.photonView != null && this.photonView.ViewID > 0; }
}
internal bool RequiresSpeaker
{
get { return this.SetupDebugSpeaker || this.IsPhotonViewReady && !this.photonView.IsMine; }
}
internal bool RequiresRecorder
{
get { return this.IsPhotonViewReady && this.photonView.IsMine; }
}
#endregion
#region Private Methods
protected override void Awake()
{
base.Awake();
this.photonView = this.GetComponent<PhotonView>();
this.Init();
}
private void OnEnable()
{
if (this.onEnableCalledOnce)
{
this.Init();
}
else
{
this.onEnableCalledOnce = true;
}
}
private void Start()
{
this.Init();
}
private void CheckLateLinking()
{
if (PhotonVoiceNetwork.Instance.Client.InRoom)
{
if (this.IsSpeaker)
{
if (!this.IsSpeakerLinked)
{
PhotonVoiceNetwork.Instance.CheckLateLinking(this.SpeakerInUse, this.photonView.ViewID);
}
else if (this.Logger.IsDebugEnabled)
{
this.Logger.LogDebug("Speaker already linked");
}
}
else if (this.Logger.IsDebugEnabled)
{
this.Logger.LogDebug("PhotonVoiceView does not have a Speaker and may not need late linking check");
}
}
else if (this.Logger.IsDebugEnabled)
{
this.Logger.LogDebug("Voice client is still not in a room, skipping late linking check");
}
}
internal void Setup()
{
if (this.IsSetup)
{
if (this.Logger.IsDebugEnabled)
{
this.Logger.LogDebug("PhotonVoiceView already setup");
}
return;
}
this.SetupRecorderInUse();
this.SetupSpeakerInUse();
}
private bool SetupRecorder()
{
if (this.recorderInUse == null) // not manually assigned by user
{
if (this.UsePrimaryRecorder)
{
if (PhotonVoiceNetwork.Instance.PrimaryRecorder != null)
{
this.recorderInUse = PhotonVoiceNetwork.Instance.PrimaryRecorder;
return this.SetupRecorder(this.recorderInUse);
}
if (this.Logger.IsErrorEnabled)
{
this.Logger.LogError("PrimaryRecorder is not set.");
}
}
Recorder[] recorders = this.GetComponentsInChildren<Recorder>();
if (recorders.Length > 0)
{
this.recorderInUse = recorders[0];
if (recorders.Length > 1 && this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Multiple Recorder components found attached to the GameObject or its children.");
}
return this.SetupRecorder(this.recorderInUse);
}
if (!this.AutoCreateRecorderIfNotFound)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("No Recorder found to be setup.");
}
return false;
}
this.recorderInUse = this.gameObject.AddComponent<Recorder>();
}
return this.SetupRecorder(this.recorderInUse);
}
private bool SetupRecorder(Recorder recorder)
{
if (recorder == null)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Cannot setup a null Recorder.");
}
return false;
}
if (!this.IsPhotonViewReady)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Recorder setup cannot be done before assigning a valid ViewID to the PhotonView attached to the same GameObject as the PhotonVoiceView.");
}
return false;
}
recorder.UserData = this.photonView.ViewID;
if (!recorder.IsInitialized)
{
this.RecorderInUse.Init(PhotonVoiceNetwork.Instance);
}
if (recorder.RequiresRestart)
{
recorder.RestartRecording();
}
return recorder.IsInitialized && recorder.UserData is int && this.photonView.ViewID == (int) recorder.UserData;
}
private bool SetupSpeaker()
{
if (this.speakerInUse == null) // not manually assigned by user
{
Speaker[] speakers = this.GetComponentsInChildren<Speaker>(true);
if (speakers.Length > 0)
{
this.speakerInUse = speakers[0];
if (speakers.Length > 1 && this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Multiple Speaker components found attached to the GameObject or its children. Using the first one we found.");
}
}
if (this.speakerInUse == null)
{
if (!PhotonVoiceNetwork.Instance.AutoCreateSpeakerIfNotFound)
{
return false;
}
if (PhotonVoiceNetwork.Instance.SpeakerPrefab != null)
{
GameObject go = Instantiate(PhotonVoiceNetwork.Instance.SpeakerPrefab, this.transform, false);
speakers = go.GetComponentsInChildren<Speaker>(true);
if (speakers.Length > 0)
{
this.speakerInUse = speakers[0];
if (speakers.Length > 1 && this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Multiple Speaker components found attached to the GameObject (PhotonVoiceNetwork.SpeakerPrefab) or its children. Using the first one we found.");
}
}
if (this.speakerInUse == null)
{
if (this.Logger.IsErrorEnabled)
{
this.Logger.LogError("SpeakerPrefab does not have a component of type Speaker in its hierarchy.");
}
Destroy(go);
return false;
}
}
else
{
this.speakerInUse = this.gameObject.AddComponent<Speaker>();
}
}
}
return this.SetupSpeaker(this.speakerInUse);
}
private bool SetupSpeaker(Speaker speaker)
{
if (speaker == null)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Cannot setup a null Speaker");
}
return false;
}
AudioSource audioSource = speaker.GetComponent<AudioSource>();
if (audioSource == null)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Unexpected: no AudioSource found attached to the same GameObject as the Speaker component");
}
return false;
}
if (audioSource.mute)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("audioSource.mute is true, playback may not work properly");
}
}
if (audioSource.volume <= 0f)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("audioSource.volume is zero, playback may not work properly");
}
}
if (!audioSource.enabled)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("audioSource.enabled is false, playback may not work properly");
}
}
return true;
}
internal void SetupRecorderInUse()
{
if (this.IsRecorder)
{
if (this.Logger.IsInfoEnabled)
{
this.Logger.LogInfo("Recorder already setup");
}
return;
}
if (!this.RequiresRecorder)
{
if (this.IsPhotonViewReady)
{
if (this.Logger.IsInfoEnabled)
{
this.Logger.LogInfo("Recorder not needed");
}
}
return;
}
this.IsRecorder = this.SetupRecorder();
if (!this.IsRecorder)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Recorder not setup for PhotonVoiceView: playback may not work properly.");
}
}
else
{
if (!this.RecorderInUse.IsRecording && !this.RecorderInUse.AutoStart)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("PhotonVoiceView.RecorderInUse.AutoStart is false, don't forget to start recording manually using recorder.StartRecording() or recorder.IsRecording = true.");
}
}
if (!this.RecorderInUse.TransmitEnabled)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("PhotonVoiceView.RecorderInUse.TransmitEnabled is false, don't forget to set it to true to enable transmission.");
}
}
if (!this.RecorderInUse.isActiveAndEnabled && this.RecorderInUse.RecordOnlyWhenEnabled)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("PhotonVoiceView.RecorderInUse may not work properly as RecordOnlyWhenEnabled is set to true and recorder is disabled or attached to an inactive GameObject.");
}
}
}
}
internal void SetupSpeakerInUse()
{
if (this.IsSpeaker)
{
if (this.Logger.IsInfoEnabled)
{
this.Logger.LogInfo("Speaker already setup");
}
return;
}
if (!this.RequiresSpeaker)
{
if (this.IsPhotonViewReady)
{
if (this.Logger.IsInfoEnabled)
{
this.Logger.LogInfo("Speaker not needed");
}
}
return;
}
this.IsSpeaker = this.SetupSpeaker();
if (!this.IsSpeaker)
{
if (this.Logger.IsWarningEnabled)
{
this.Logger.LogWarning("Speaker not setup for PhotonVoiceView: voice chat will not work.");
}
}
else
{
this.CheckLateLinking();
}
}
#endregion
#region Public Methods
/// <summary>
/// Initializes this PhotonVoiceView for Voice usage based on the PhotonView, Recorder and Speaker components.
/// </summary>
/// <remarks>
/// The initialization should happen automatically.
/// Call this method explicitly if this does not succeed.
/// The initialization is a two steps operation: step one is the setup of Recorder and Speaker to be used.
/// Step two is the late-linking -if needed- of the SpeakerInUse and corresponding remote voice info -if any- via ViewID.
/// </remarks>
public void Init()
{
if (this.IsPhotonViewReady)
{
this.Setup();
this.CheckLateLinking();
}
else if (this.Logger.IsDebugEnabled)
{
this.Logger.LogDebug("Tried to initialize PhotonVoiceView but PhotonView does not have a valid allocated ViewID yet.");
}
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 126494ae2a10a34499272ed97a6c9f5d
timeCreated: 1540904580
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: dd940d333aeeaa048842e87b9b259188, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 22faa279621bc10479cc398c2447f370
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,242 @@
namespace Photon.Voice.PUN.UtilityScripts
{
using Pun;
using Unity;
using Realtime;
using UnityEngine;
using ExitGames.Client.Photon;
/// <summary> Utility script to be attached next to PhotonVoiceView & PhotonView on the player prefab to be network instantiated.
/// Call voiceDebugScript.CantHearYou() on the networked object of the remote (or local) player if you can't hear the corresponding player. </summary>
[RequireComponent(typeof(PhotonVoiceView))]
public class VoiceDebugScript : MonoBehaviourPun
{
private PhotonVoiceView photonVoiceView;
/// <summary> Make sure recorder.TransmitEnabled and recorder.IsRecording are true. </summary>
public bool ForceRecordingAndTransmission;
/// <summary> Audio file to be broadcast when TestUsingAudioClip is enabled. </summary>
public AudioClip TestAudioClip;
/// <summary> Broadcast Audio file to make sure transmission over network works if microphone (audio input device/hardware) is not reliable. Requires setting AudioClip in TestAudioClip. </summary>
public bool TestUsingAudioClip;
/// <summary> Disable recorder.VoiceDetection for easier testing. </summary>
public bool DisableVad;
/// <summary> Set main voice component's log level to ALL (max). </summary>
public bool IncreaseLogLevels;
/// <summary> Debug DebugEcho mode (Can't Hear My Self?!). </summary>
public bool LocalDebug;
private void Awake()
{
this.photonVoiceView = this.GetComponent<PhotonVoiceView>();
}
private void Update()
{
this.MaxLogs();
if (this.photonVoiceView.IsRecorder)
{
if (this.TestUsingAudioClip)
{
if (!this.TestAudioClip || this.TestAudioClip == null)
{
Debug.LogError("Set an AudioClip first");
}
else
{
this.photonVoiceView.RecorderInUse.SourceType = Recorder.InputSourceType.AudioClip;
this.photonVoiceView.RecorderInUse.AudioClip = this.TestAudioClip;
this.photonVoiceView.RecorderInUse.LoopAudioClip = true;
if (this.photonVoiceView.RecorderInUse.RequiresRestart)
{
this.photonVoiceView.RecorderInUse.RestartRecording();
}
else
{
this.photonVoiceView.RecorderInUse.StartRecording();
}
this.photonVoiceView.RecorderInUse.TransmitEnabled = true;
}
}
if (this.ForceRecordingAndTransmission)
{
this.photonVoiceView.RecorderInUse.IsRecording = true;
this.photonVoiceView.RecorderInUse.TransmitEnabled = true;
}
if (this.DisableVad)
{
this.photonVoiceView.RecorderInUse.VoiceDetection = false;
}
}
}
[ContextMenu("CantHearYou")]
public void CantHearYou()
{
if (!PhotonVoiceNetwork.Instance.Client.InRoom)
{
Debug.LogError("local voice client is not joined to a voice room");
}
else if (!this.photonVoiceView.IsPhotonViewReady)
{
Debug.LogError("PhotonView is not ready yet; maybe PUN client is not joined to a room yet or this PhotonView is not valid");
}
else if (!this.photonVoiceView.IsSpeaker)
{
if (this.photonView.IsMine && !this.photonVoiceView.SetupDebugSpeaker)
{
Debug.LogError("local object does not have SetupDebugSpeaker enabled");
if (this.LocalDebug)
{
Debug.Log("setup debug speaker not enabled, enabling it now (1)");
this.photonVoiceView.SetupDebugSpeaker = true;
this.photonVoiceView.Setup();
}
}
else
{
Debug.LogError("locally not speaker (yet?) (1)");
this.photonVoiceView.Setup();
}
}
else
{
if (!this.photonVoiceView.IsSpeakerLinked)
{
Debug.LogError("locally speaker not linked, trying late linking & asking anyway");
// late linking maybe
PhotonVoiceNetwork.Instance.CheckLateLinking(this.photonVoiceView.SpeakerInUse, this.photonView.ViewID);
}
this.photonView.RPC("CantHearYou", this.photonView.Owner, PhotonVoiceNetwork.Instance.Client.CurrentRoom.Name, PhotonVoiceNetwork.Instance.Client.LoadBalancingPeer.ServerIpAddress, PhotonVoiceNetwork.Instance.Client.AppVersion);
}
}
[PunRPC]
private void CantHearYou(string roomName, string serverIp, string appVersion, PhotonMessageInfo photonMessageInfo)
{
string why;
if (!PhotonVoiceNetwork.Instance.Client.InRoom)
{
why = "voice client not in a room";
}
else if (!PhotonVoiceNetwork.Instance.Client.CurrentRoom.Name.Equals(roomName))
{
why = string.Format("voice client is on another room {0} != {1}",
PhotonVoiceNetwork.Instance.Client.CurrentRoom.Name, roomName);
}
else if (!PhotonVoiceNetwork.Instance.Client.LoadBalancingPeer.ServerIpAddress.Equals(serverIp))
{
why = string.Format("voice client is on another server {0} != {1}, maybe different Photon Cloud regions",
PhotonVoiceNetwork.Instance.Client.LoadBalancingPeer.ServerIpAddress, serverIp);
}
else if (!PhotonVoiceNetwork.Instance.Client.AppVersion.Equals(appVersion))
{
why = string.Format("voice client uses different AppVersion {0} != {1}",
PhotonVoiceNetwork.Instance.Client.AppVersion, appVersion);
}
else if (!this.photonVoiceView.IsRecorder)
{
why = "recorder not setup (yet?)";
this.photonVoiceView.Setup();
}
else if (!this.photonVoiceView.RecorderInUse.IsRecording)
{
why = "recorder is not recording";
this.photonVoiceView.RecorderInUse.IsRecording = true;
}
else if (!this.photonVoiceView.RecorderInUse.TransmitEnabled)
{
why = "recorder is not transmitting";
this.photonVoiceView.RecorderInUse.TransmitEnabled = true;
}
else if (this.photonVoiceView.RecorderInUse.InterestGroup != 0)
{
why = "recorder.InterestGroup is not zero? is this on purpose? switching it back to zero";
this.photonVoiceView.RecorderInUse.InterestGroup = 0;
}
else if (!(this.photonVoiceView.RecorderInUse.UserData is int) || (int)this.photonVoiceView.RecorderInUse.UserData != this.photonView.ViewID)
{
why = string.Format("recorder.UserData ({0}) != photonView.ViewID ({1}), fixing it now", this.photonVoiceView.RecorderInUse.UserData, this.photonView.ViewID);
this.photonVoiceView.RecorderInUse.UserData = this.photonView.ViewID;
this.photonVoiceView.RecorderInUse.RestartRecording();
}
else if (this.photonVoiceView.RecorderInUse.VoiceDetection && this.DisableVad) // todo: check WebRtcAudioDsp.VAD
{
why = "recorder vad is enabled, disable it for testing";
this.photonVoiceView.RecorderInUse.VoiceDetection = false;
}
else if (this.photonView.OwnerActorNr == photonMessageInfo.Sender.ActorNumber)
{
if (this.LocalDebug)
{
if (this.photonVoiceView.IsSpeaker)
{
why = "no idea why!, should be working (1)";
this.photonVoiceView.RecorderInUse.RestartRecording(true);
}
else if (!this.photonVoiceView.SetupDebugSpeaker) // unreachable probably
{
why = "setup debug speaker not enabled, enabling it now (2)";
this.photonVoiceView.SetupDebugSpeaker = true;
this.photonVoiceView.Setup();
}
else if (!this.photonVoiceView.RecorderInUse.DebugEchoMode)
{
why = "recorder debug echo mode not enabled, enabling it now";
this.photonVoiceView.RecorderInUse.DebugEchoMode = true;
}
else
{
why = "locally not speaker (yet?) (2)";
this.photonVoiceView.Setup();
}
}
else
{
why = "local object, are you trying to hear yourself? (feedback DebugEcho), LocalDebug is disabled, enable it if you want to diagnose this";
}
}
else
{
why = "no idea why!, should be working (2)";
this.photonVoiceView.RecorderInUse.RestartRecording(true);
}
this.Reply(why, photonMessageInfo.Sender);
}
private void Reply(string why, Player player)
{
this.photonView.RPC("HeresWhy", player, why);
}
[PunRPC]
private void HeresWhy(string why, PhotonMessageInfo photonMessageInfo)
{
Debug.LogErrorFormat("Player {0} replied to my CantHearYou message with {1}", photonMessageInfo.Sender, why);
}
private void MaxLogs()
{
if (this.IncreaseLogLevels)
{
this.photonVoiceView.LogLevel = DebugLevel.ALL;
PhotonVoiceNetwork.Instance.LogLevel = DebugLevel.ALL;
PhotonVoiceNetwork.Instance.GlobalRecordersLogLevel = DebugLevel.ALL;
PhotonVoiceNetwork.Instance.GlobalSpeakersLogLevel = DebugLevel.ALL;
if (this.photonVoiceView.IsRecorder)
{
this.photonVoiceView.RecorderInUse.LogLevel = DebugLevel.ALL;
}
if (this.photonVoiceView.IsSpeaker)
{
this.photonVoiceView.SpeakerInUse.LogLevel = DebugLevel.ALL;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 83be82b116045a747bf0141620a4a02f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: