com.adrenak.univoice 4.4.0 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,7 @@ Some features of UniVoice:
10
10
  * 🌐 __Configurable Network__:
11
11
  - UniVoice is networking agnostic. Implement the `IAudioClient` and `IAudioServer` interfaces using the networking plugin of your choice to have it send audio data over any networking solution.
12
12
  - Built-in support for:
13
- - Mirror networking. Note that only Client and Server modes are currently supported. Host mode is not.
13
+ - Mirror networking
14
14
 
15
15
  * 🎤 __Configurable Audio Input__:
16
16
  - UniVoice is audio input agnostic. You can change the source of outgoing audio by implementing the `IAudioInput` interface.
@@ -65,7 +65,7 @@ This repository contains two samples:
65
65
  * `UniVoiceMirrorSetupSample.cs` is a drag and drop component, a simple integration sample script. You can add it to your Mirror NetworkManager to get voice chat to work. No code required, it's as simple as that! It'll work as long as you have setup your project properly. For more instructions see the top of the `UniVoiceMirrorSetupSample.cs` file.
66
66
  * A sample scene that shows the other clients in a UI as well as allows you to mute yourself/them. This sample is also Mirror based.
67
67
 
68
- > UniVoice currently only supports Mirror out of the box. All the samples rely on Mirror networking to work. Follow the instructions in the "Activating non-packaged dependencies" section below for enabling Mirror in your project before trying it out. Also note that the Host mode is not supported, your server should be in Server mode only.
68
+ > UniVoice currently only supports Mirror out of the box. All the samples rely on Mirror networking to work. Follow the instructions in the "Activating non-packaged dependencies" section below for enabling Mirror in your project before trying it out.
69
69
 
70
70
  ## Dependencies
71
71
  [com.adrenak.brw](https://www.github.com/adrenak/brw) for reading and writing messages for communication. See `MirrorServer.cs` and `MirrorClient.cs` where they're used.
@@ -29,27 +29,40 @@ namespace Adrenak.UniVoice.Networks {
29
29
  public event Action<int> OnPeerLeft;
30
30
  public event Action<int, AudioFrame> OnReceivedPeerAudioFrame;
31
31
 
32
+ readonly MirrorModeObserver mirrorEvents;
33
+
32
34
  public MirrorClient() {
33
35
  PeerIDs = new List<int>();
34
36
  YourVoiceSettings = new VoiceSettings();
35
37
 
36
- NetworkManager.singleton.transport.OnClientConnected += OnClientConnected;
37
- NetworkManager.singleton.transport.OnClientDisconnected += OnClientDisconnected;
38
+ mirrorEvents = MirrorModeObserver.New("for MirrorClient");
39
+ mirrorEvents.ModeChanged += OnModeChanged;
40
+
38
41
  NetworkClient.RegisterHandler<MirrorMessage>(OnReceivedMessage, false);
39
42
  }
40
43
 
41
44
  public void Dispose() {
42
- NetworkManager.singleton.transport.OnClientConnected -= OnClientConnected;
43
- NetworkManager.singleton.transport.OnClientDisconnected -= OnClientDisconnected;
44
- NetworkClient.UnregisterHandler<MirrorMessage>();
45
+ PeerIDs.Clear();
45
46
  }
46
47
 
47
- void OnClientConnected() {
48
+ void OnModeChanged(NetworkManagerMode oldMode, NetworkManagerMode newMode) {
49
+ // For some reason, handlers don't always work as expected when the connection mode changes
48
50
  NetworkClient.ReplaceHandler<MirrorMessage>(OnReceivedMessage);
51
+
52
+ bool clientOnlyToOffline = newMode == NetworkManagerMode.Offline && oldMode == NetworkManagerMode.ClientOnly;
53
+ bool hostToServerOnlyOrOffline = oldMode == NetworkManagerMode.Host;
54
+
55
+ if (clientOnlyToOffline || hostToServerOnlyOrOffline) {
56
+ // We unregister the handler only when the device was a client.
57
+ // If it was a Host that's now a ServerOnly, we still need the handler as it's used in MirrorServer
58
+ if (clientOnlyToOffline)
59
+ NetworkClient.UnregisterHandler<MirrorMessage>();
60
+
61
+ OnClientDisconnected();
62
+ }
49
63
  }
50
64
 
51
65
  void OnClientDisconnected() {
52
- NetworkClient.ReplaceHandler<MirrorMessage>(OnReceivedMessage);
53
66
  YourVoiceSettings = new VoiceSettings();
54
67
  var oldPeerIds = PeerIDs;
55
68
  PeerIDs.Clear();
@@ -59,7 +72,6 @@ namespace Adrenak.UniVoice.Networks {
59
72
  OnLeft?.Invoke();
60
73
  }
61
74
 
62
-
63
75
  void OnReceivedMessage(MirrorMessage msg) {
64
76
  var reader = new BytesReader(msg.data);
65
77
  var tag = reader.ReadString();
@@ -69,13 +81,16 @@ namespace Adrenak.UniVoice.Networks {
69
81
  // peers that are already connected to the server
70
82
  case MirrorMessageTags.PEER_INIT:
71
83
  ID = reader.ReadInt();
72
- Debug.unityLogger.Log(LogType.Log, TAG,
73
- $"Initialized with ID {ID}");
74
- OnJoined?.Invoke(ID, PeerIDs);
75
84
  PeerIDs = reader.ReadIntArray().ToList();
76
- if(PeerIDs.Count > 0)
77
- Debug.unityLogger.Log(LogType.Log, TAG,
78
- $"Peers {string.Join(", ", PeerIDs)}");
85
+
86
+ string log = $"Initialized with ID {ID}. ";
87
+ if (PeerIDs.Count > 0)
88
+ log += $"Peer list: {string.Join(", ", PeerIDs)}";
89
+ else
90
+ log += "There are currently no peers.";
91
+ Debug.unityLogger.Log(LogType.Log, TAG, log);
92
+
93
+ OnJoined?.Invoke(ID, PeerIDs);
79
94
  foreach (var peerId in PeerIDs)
80
95
  OnPeerJoined?.Invoke(peerId);
81
96
  break;
@@ -84,9 +99,9 @@ namespace Adrenak.UniVoice.Networks {
84
99
  case MirrorMessageTags.PEER_JOINED:
85
100
  var newPeerID = reader.ReadInt();
86
101
  if (!PeerIDs.Contains(newPeerID)) {
87
- Debug.unityLogger.Log(LogType.Log, TAG,
88
- $"Peer {newPeerID} has joined");
89
102
  PeerIDs.Add(newPeerID);
103
+ Debug.unityLogger.Log(LogType.Log, TAG,
104
+ $"Peer {newPeerID} joined. Peer list is now {string.Join(", ", PeerIDs)}");
90
105
  OnPeerJoined?.Invoke(newPeerID);
91
106
  }
92
107
  break;
@@ -95,9 +110,14 @@ namespace Adrenak.UniVoice.Networks {
95
110
  case MirrorMessageTags.PEER_LEFT:
96
111
  var leftPeerID = reader.ReadInt();
97
112
  if (PeerIDs.Contains(leftPeerID)) {
98
- Debug.unityLogger.Log(LogType.Log, TAG,
99
- $"Peer {leftPeerID} has left");
100
113
  PeerIDs.Remove(leftPeerID);
114
+ string log2 = $"Peer {leftPeerID} left. ";
115
+ if (PeerIDs.Count == 0)
116
+ log2 += "There are no peers anymore.";
117
+ else
118
+ log2 += $"Peer list is now {string.Join(", ", PeerIDs)}";
119
+
120
+ Debug.unityLogger.Log(LogType.Log, TAG, log2);
101
121
  OnPeerLeft?.Invoke(leftPeerID);
102
122
  }
103
123
  break;
@@ -11,6 +11,8 @@ namespace Adrenak.UniVoice.Networks {
11
11
  /// when it changes
12
12
  /// </summary>
13
13
  public class MirrorModeObserver : MonoBehaviour {
14
+ const string TAG = "[MirrorModeObserver]";
15
+
14
16
  /// <summary>
15
17
  /// Event fired when the Mirror NetworkManager changes the mode
16
18
  /// </summary>
@@ -25,8 +27,8 @@ namespace Adrenak.UniVoice.Networks {
25
27
  /// Creates a new instance of this class on a GameObject
26
28
  /// </summary>
27
29
  /// <returns></returns>
28
- public static MirrorModeObserver New() {
29
- var go = new GameObject("MirrorEventProvider");
30
+ public static MirrorModeObserver New(string name = "") {
31
+ var go = new GameObject($"MirrorEventProvider {name}");
30
32
  DontDestroyOnLoad(go);
31
33
  return go.AddComponent<MirrorModeObserver>();
32
34
  }
@@ -34,7 +36,12 @@ namespace Adrenak.UniVoice.Networks {
34
36
  void Update() {
35
37
  var newMode = NetworkManager.singleton.mode;
36
38
  if (lastMode != newMode) {
37
- ModeChanged?.Invoke(lastMode, newMode);
39
+ try {
40
+ ModeChanged?.Invoke(lastMode, newMode);
41
+ }
42
+ catch (Exception e) {
43
+ Debug.Log(LogType.Error, TAG, "Exception while handling Mirror Mode change: " + e);
44
+ }
38
45
  lastMode = newMode;
39
46
  }
40
47
  }
@@ -40,43 +40,64 @@ namespace Adrenak.UniVoice.Networks {
40
40
  ClientIDs = new List<int>();
41
41
  ClientVoiceSettings = new Dictionary<int, VoiceSettings>();
42
42
 
43
- mirrorEvents = MirrorModeObserver.New();
43
+ mirrorEvents = MirrorModeObserver.New("for MirrorServer");
44
44
  mirrorEvents.ModeChanged += OnModeChanged;
45
45
 
46
46
  NetworkServer.RegisterHandler<MirrorMessage>(OnReceivedMessage, false);
47
+ }
48
+
49
+ public void Dispose() {
50
+ mirrorEvents.ModeChanged -= OnModeChanged;
51
+ NetworkServer.UnregisterHandler<MirrorMessage>();
52
+ OnServerShutdown();
53
+ }
47
54
 
55
+ void OnServerStarted() {
48
56
  #if MIRROR_89_OR_NEWER
49
57
  NetworkManager.singleton.transport.OnServerConnectedWithAddress += OnServerConnected;
50
58
  #else
51
59
  NetworkManager.singleton.transport.OnServerConnected += OnServerConnected;
52
60
  #endif
53
61
  NetworkManager.singleton.transport.OnServerDisconnected += OnServerDisconnected;
62
+ OnServerStart?.Invoke();
54
63
  }
55
-
56
- void IDisposable.Dispose() {
57
- mirrorEvents.ModeChanged -= OnModeChanged;
58
-
59
- NetworkServer.UnregisterHandler<MirrorMessage>();
60
64
 
65
+ void OnServerShutdown() {
61
66
  #if MIRROR_89_OR_NEWER
62
67
  NetworkManager.singleton.transport.OnServerConnectedWithAddress -= OnServerConnected;
63
68
  #else
64
69
  NetworkManager.singleton.transport.OnServerConnected -= OnServerConnected;
65
- #endif
70
+ #endif
66
71
  NetworkManager.singleton.transport.OnServerDisconnected -= OnServerDisconnected;
72
+ ClientIDs.Clear();
73
+ ClientVoiceSettings.Clear();
74
+ OnServerStop?.Invoke();
67
75
  }
68
76
 
69
77
  void OnModeChanged(NetworkManagerMode oldMode, NetworkManagerMode newMode) {
78
+ // For some reason, handlers don't always work as expected when the connection mode changes
70
79
  NetworkServer.ReplaceHandler<MirrorMessage>(OnReceivedMessage, false);
71
80
 
72
- if((newMode == NetworkManagerMode.ServerOnly || newMode == NetworkManagerMode.Host)
73
- && (oldMode != NetworkManagerMode.ServerOnly && oldMode != NetworkManagerMode.Host)) {
74
- OnServerStart?.Invoke();
81
+ // If in Host mode, the server and internal client have both started and the client connects immediately.
82
+ // The host client seems to have ID 0 always, so we trigger a new client connection using id 0.
83
+ if(newMode == NetworkManagerMode.Host) {
84
+ OnServerStarted();
85
+ OnServerConnected(0, "localhost");
86
+ }
87
+ else if(newMode == NetworkManagerMode.ServerOnly) {
88
+ // If a Host changes to ServerOnly, we disconnect the internal client
89
+ if (oldMode == NetworkManagerMode.Host)
90
+ OnServerDisconnected(0);
91
+ // But if this machine is going from Offline to ServerOnly, only the server is starting
92
+ else if(oldMode == NetworkManagerMode.Offline)
93
+ OnServerStarted();
75
94
  }
76
- else if(newMode == NetworkManagerMode.Offline) {
77
- ClientIDs.Clear();
78
- ClientVoiceSettings.Clear();
79
- OnServerStop?.Invoke();
95
+ // If a Host or ServerOnly goes offline
96
+ else if(newMode == NetworkManagerMode.Offline && (oldMode == NetworkManagerMode.ServerOnly || oldMode == NetworkManagerMode.Host)) {
97
+ // We check if it was a Host before and disconnect the internal client
98
+ if (oldMode == NetworkManagerMode.Host)
99
+ OnServerDisconnected(0);
100
+ OnServerShutdown();
80
101
  }
81
102
  }
82
103
 
@@ -146,6 +167,7 @@ namespace Adrenak.UniVoice.Networks {
146
167
  #else
147
168
  void OnServerConnected(int connId) {
148
169
  #endif
170
+ // Not sure if this needs to be done, but being extra cautious here
149
171
  NetworkServer.ReplaceHandler<MirrorMessage>(OnReceivedMessage, false);
150
172
 
151
173
  Debug.unityLogger.Log(LogType.Log, TAG, $"Client {connId} connected");
@@ -172,9 +194,10 @@ namespace Adrenak.UniVoice.Networks {
172
194
  // required but I faced some issues with immediate initialization earlier.
173
195
  SendToClientDelayed(connId, newClientPacket.Bytes, Channels.Reliable, 100);
174
196
 
175
- string peerListString = string.Join(", ", otherPeerIDs);
176
- Debug.unityLogger.Log(LogType.Log, TAG,
177
- $"Initializing new client with ID {connId} and peer list {peerListString}");
197
+ string log = $"Initializing new client with ID {connId}";
198
+ if (otherPeerIDs.Length > 0)
199
+ log += $" and peer list {string.Join(", ", otherPeerIDs)}";
200
+ Debug.unityLogger.Log(LogType.Log, TAG, log);
178
201
  }
179
202
  // To the already existing peers, we let them know a new peer has joined
180
203
  // by sending the new peer ID to them.
@@ -191,11 +214,11 @@ namespace Adrenak.UniVoice.Networks {
191
214
  }
192
215
 
193
216
  void OnServerDisconnected(int connId) {
217
+ // Not sure if this needs to be done, but being extra cautious here
194
218
  NetworkServer.ReplaceHandler<MirrorMessage>(OnReceivedMessage, false);
195
219
 
196
220
  ClientIDs.Remove(connId);
197
- Debug.unityLogger.Log(LogType.Log, TAG,
198
- $"Client {connId} disconnected");
221
+ Debug.unityLogger.Log(LogType.Log, TAG, $"Client {connId} disconnected");
199
222
 
200
223
  // Notify all remaining peers that a peer has left
201
224
  foreach (var peerId in ClientIDs) {
@@ -117,7 +117,7 @@ namespace Adrenak.UniVoice.Samples {
117
117
  // ---- CREATE AUDIO CLIENT AND SUBSCRIBE TO EVENTS ----
118
118
  IAudioClient<int> client = new MirrorClient();
119
119
  client.OnJoined += (id, peerIds) => {
120
- Debug.unityLogger.Log(LogType.Log, TAG, $"You are Peer ID {id} your peers are {string.Join(", ", peerIds)}");
120
+ Debug.unityLogger.Log(LogType.Log, TAG, $"You are Peer ID {id}");
121
121
  };
122
122
 
123
123
  client.OnLeft += () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.adrenak.univoice",
3
- "version": "4.4.0",
3
+ "version": "4.5.0",
4
4
  "displayName": "Adrenak.UniVoice",
5
5
  "description": "Voice chat/VoIP framework for Unity.",
6
6
  "unity": "2021.2",