Closed fender closed 3 years ago
Dissonance starts itself in the same mode as the underlying network system. In your case it looks like that's Photon Bolt, so you can find the relevant code in Assets/Dissonance/Integrations/PhotonBolt/BoltCommsNetwork.cs
on line 226:
if (BoltNetwork.IsConnected)
{
if (BoltNetwork.IsServer)
{
if (Mode != NetworkMode.Host)
RunAsHost(Unit.None, Unit.None); // <-----
}
else
{
if (Mode != NetworkMode.Client)
RunAsClient(Unit.None); // <-----
}
}
else
{
if (Mode != NetworkMode.None)
Stop(); // <-----
}
The lines that I have marked change the Dissonance network mode. As you can see there's not one which starts Dissonance as a dedicated server, only as a Host
(mixed client/server). I'm not sure why this is and I'll definitely look into it in more detail once I'm back full time in January.
You can probably just add another case like this (assuming that Bolt sets both the IsClient
and IsServer
flags when it's a host):
if (BoltNetwork.IsServer)
{
if (BoltNetwork.IsClient)
{
if (Mode != NetworkMode.Host)
RunAsHost(Unit.None, Unit.None); // <----- Start as host (client & server)
}
else
{
if (Mode != NetworkMode.DedicatedServer)
RunAsDedicatedServer(Unit.None); // <----- Start as just a server
}
}
We can assume that when BoltNetwork.IsServer
is true
then we're running a dedicated server build. However, the edge case in Bolt is that you can run a single player game offline where both BoltNetwork.IsServer
and BoltNetwork.IsSinglePlayer
become true
. Would something like this suffice?
if (BoltNetwork.IsServer)
{
if (BoltNetwork.IsSinglePlayer)
{
if (Mode != NetworkMode.Host)
RunAsHost(Unit.None, Unit.None); // <----- Start as host (client & server)
}
else
{
if (Mode != NetworkMode.DedicatedServer)
RunAsDedicatedServer(Unit.None); // <----- Start as just a server
}
}
If it's single player you might just want to do this instead of running as host:
if (Mode != NetworkMode.None)
Stop();
This way Dissonance is totally deactivated in single player mode.
Good shout. My dedicated server seems to have created the server correctly:
[Dissonance:Core] (16:35:14.632) DissonanceComms: Loading default playback prefab
[Dissonance:Core] (16:35:14.641) DissonanceComms: Starting Dissonance Voice Comms (6.4.6)
- Network: [DissonanceSetup(Clone) (Dissonance.Integrations.PhotonBolt.BoltCommsNetwork)]
- Quality Settings: [Quality: Medium, FrameSize: Medium, FEC: True, DenoiseAmount: High, VoiceDuckLevel: 0.75 VAD: MediumSensitivity]
- Codec: [Codec: Opus, FrameSize: 1920, SampleRate: 48kHz]
[Dissonance:Network] (16:35:14.667) BoltServer: Created server with SessionId:1015807102
[Dissonance:Network] (16:35:14.667) BoltServer: Connected
However, the first client that joined got a new error. This caused them to become self-muted (If I try to uncheck Mute in Dissonance Comms once playing as the client via the editor, it doesn't uncheck and gives me a different error).
[Dissonance:Recording] (16:35:35.913) CapturePipelineManager: Unexpected exception encountered starting microphone capture; local voice transmission will be disabled: System.ArgumentException: TimeSpan does not accept floating point Not-a-Number values.
at System.TimeSpan.Interval (System.Double value, System.Int32 scale) [0x00012] in <9577ac7a62ef43179789031239ba8798>:0
at System.TimeSpan.FromSeconds (System.Double value) [0x00000] in <9577ac7a62ef43179789031239ba8798>:0
at Dissonance.Audio.Capture.BasicMicrophoneCapture.StartCapture (System.String inputMicName) [0x00218] in /Users/joefender/Workspace/Seance/Assets/Plugins/Dissonance/Core/Audio/Capture/BasicMicrophoneCapture.cs:132
at Dissonance.Audio.Capture.CapturePipelineManager.RestartTransmissionPipeline (System.String reason) [0x0004f] in /Users/joefender/Workspace/Seance/Assets/Plugins/Dissonance/Core/Audio/Capture/CapturePipelineManager.cs:339
UnityEngine.Debug:LogError(Object)
Dissonance.LogMessage:Log() (at Assets/Plugins/Dissonance/Core/Log.cs:66)
Dissonance.Logs:SendLogMessage(String, LogLevel) (at Assets/Plugins/Dissonance/Core/Log.cs:95)
Dissonance.Log:WriteLog(LogLevel, String) (at Assets/Plugins/Dissonance/Core/Log.cs:178)
Dissonance.Log:WriteLogFormat(LogLevel, String, Exception) (at Assets/Plugins/Dissonance/Core/Log.cs:187)
Dissonance.Log:Error(String, Exception) (at Assets/Plugins/Dissonance/Core/Log.cs:428)
Dissonance.Audio.Capture.CapturePipelineManager:RestartTransmissionPipeline(String) (at Assets/Plugins/Dissonance/Core/Audio/Capture/CapturePipelineManager.cs:381)
Dissonance.Audio.Capture.CapturePipelineManager:Update(Boolean, Single) (at Assets/Plugins/Dissonance/Core/Audio/Capture/CapturePipelineManager.cs:204)
Dissonance.DissonanceComms:Update() (at Assets/Plugins/Dissonance/DissonanceComms.cs:612)
The only use of FromSeconds
in BasicMicrophoneCapture
is this line:
Latency = TimeSpan.FromSeconds(frameSize / (float)_format.SampleRate);
Could you check what values are being passed into that? For it to be creating a NaN
value it looks like _clip.frequency
must be zero, which isn't a valid thing for the Microphone API to return.
@martindevans Thanks, that helped pinpoint the issue. Turns out I had an audio issue with my Unity build so please disregard my previous comment.
So I have 2 clients connected to a dedicated server. But for some reason data isn't being sent over the network to the Server after pushing to talk. I can confirm that "(speaking)" is shown next to my local player in the DissonanceComms inspector.
Do you have matching VoiceBroadcastTrigger
(on the speaking side) and VoiceReceiptTrigger
(on the receiving side) components? Dissonance only sends voice across the network when it needs to.
Sorry for the slow reply. I'm only just back off my Christmas/New Year break :)
@martindevans Ah, I see. So I've just added the receipt trigger so now my single DissonanceSetup prefab looks like this:
This is being instantiated both on clients and the dedicated server, is there any issues with that? Also, note that we have a custom CFVoiceBroadcastTrigger
component that inherits from VoiceBroadcastTrigger
only to override the IsUserActivated
function.
I'm seeing an issue, possible race condition as it doesn't happen every time, where as soon as a client joins a dedicated server it disconnects and then goes into an infinite loop of trying to start the server itself.
Dedicated server logs:
[Dissonance:Core] (15:15:03.934) DissonanceComms: Starting Dissonance Voice Comms (6.4.6)
- Network: [DissonanceSetup(Clone) (Dissonance.Integrations.PhotonBolt.BoltCommsNetwork)]
- Quality Settings: [Quality: Medium, FrameSize: Medium, FEC: True, DenoiseAmount: High, VoiceDuckLevel: 0.75 VAD: MediumSensitivity]
- Codec: [Codec: Opus, FrameSize: 1920, SampleRate: 48kHz]
(Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
[Dissonance:Network] (15:15:04.039) BoltServer: Created server with SessionId:655596750
(Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
[Dissonance:Network] (15:15:04.044) BoltServer: Connected
(Filename: ./Runtime/Export/Debug/Debug.bindings.h Line: 35)
Then the client connects and gets these logs:
Apologies for the 101 questions here. We've had success (twice) with Dissonance on games before but this is our first time doing dedicated servers. Appreciate the help!
@martindevans Forgot to mention probably the most important part. This is our current BoltCommsNetwork.cs
Update loop for the PhotonBolt integration:
protected override void Update()
{
if (IsInitialized)
{
if (BoltNetwork.IsConnected)
{
if (BoltNetwork.IsServer)
{
if (BoltNetwork.IsSinglePlayer)
{
if (Mode != NetworkMode.Host)
RunAsHost(Unit.None, Unit.None);
}
else
{
if (Mode != NetworkMode.DedicatedServer)
RunAsDedicatedServer(Unit.None);
}
}
else
{
if (Mode != NetworkMode.Client)
RunAsClient(Unit.None);
}
}
else
{
if (Mode != NetworkMode.None)
RunAsHost(Unit.None, Unit.None);
}
}
base.Update();
}
The two items in the log that catch my eye are:
The second one is shutting down the client (because the first error happened). This will then trigger the RunAsThing
code to restart the client next frame - if you're always getting that fatal error that explains the disconnection loop. Can you have a closer look at the stacktrace for the first error (reference not set to instance of object) and see exactly what's null? I think that's the root problem.
Just a small note: the two RunAsHost
items there don't look like what you want. You're running Dissonance as a host (i.e. a local server and a local client) in two cases; when it's in single player mode or when it's not in a session at all. I think you probably want to run nothing in these cases (i.e. call Stop();
here instead).
@martindevans Yeah, I took a look at the error and it seems to be from within an update loop of one of your scripts but I couldn't make out the exact cause here.
[Dissonance:Network] (15:18:30.144) BoltClient: Object reference not set to an instance of an object
UnityEngine.Debug:LogError(Object)
Dissonance.LogMessage:Log() (at Assets/Plugins/Dissonance/Core/Log.cs:66)
Dissonance.Logs:SendLogMessage(String, LogLevel) (at Assets/Plugins/Dissonance/Core/Log.cs:95)
Dissonance.Log:WriteLog(LogLevel, String) (at Assets/Plugins/Dissonance/Core/Log.cs:178)
Dissonance.Log:Error(String) (at Assets/Plugins/Dissonance/Core/Log.cs:422)
Dissonance.Networking.BaseClient`3:RunUpdate(DateTime) (at Assets/Plugins/Dissonance/Core/Networking/BaseClient.cs:207)
Dissonance.Networking.BaseClient`3:Update() (at Assets/Plugins/Dissonance/Core/Networking/BaseClient.cs:175)
Dissonance.Networking.Session:Update() (at Assets/Plugins/Dissonance/Core/Networking/BaseCommsNetwork.cs:159)
Dissonance.Networking.BaseCommsNetwork`5:Update() (at Assets/Plugins/Dissonance/Core/Networking/BaseCommsNetwork.cs:330)
Dissonance.Integrations.PhotonBolt.BoltCommsNetwork:Update() (at Assets/Dissonance/Integrations/PhotonBolt/BoltCommsNetwork.cs:261)
In regards to Stop()
calls, we're using Dissonance still in single player to capture back the audio buffer for us when someone speaks so we can process our speech recognition tasks. It makes it easier if we don't have to change that code so hopefully its OK to just keep calling RunAsHost()
in those scenarios?
BaseClient (Assets/Plugins/Dissonance/Core/Networking/BaseClient.cs) has a try/catch
block which contains the entire update process (Line 192). Could you temporarily comment out this block? That will hopefully give you a more useful stacktrace (at the moment it just points into the catch
block).
we're using Dissonance still in single player
That's fine then, RunAsHost
is the right approach for that :)
@martindevans Sure, done:
It kinda seems like it disconnects before it even receives the first error, then tries to connect as the server which in turn causes the first error?
It appears that it's failing in this method:
public void SendReliableToServer(ArraySegment<byte> data)
{
if (BoltNetwork.IsServer)
SendPacketReceived(BoltPeer.Local, data, _serverPacketListeners);
else
{
var packet = DissonanceToServer.Create(GlobalTargets.OnlyServer); // <--------------- This is line 127 for me. Might not line up for you if you've added any lines while debugging.
packet.BinaryData = ToDirectArray(data);
packet.Send();
}
}
Could you drop in a breakpoint there and check exactly what is null?
The two most likely possibilities are:
data.Array
is null then Dissonance is trying to send a null packate (Dissonance bug?)DissonanceToServer.Create
is returning null then that's a BOLT issue (BOLT misconfiguration or bug?)@martindevans That was a huge help, thank you. It helped me track down an issue with the Bolt configuration as DissonanceToServer.Create
was returning null. Turns out you must use Manual accept mode for dedicated servers with Bolt or things get all weird. I can confirm things are not working with Dissonance and multiple clients on the dedicated servers.
We've also got all the speech recognition stuff I mentioned elsewhere set up now for this game too. Dissonance has been such a valuable asset for us so far so thank you. (This game is an upcoming mobile one, not DEVOUR)
I'm running Dissonance on my game of which we're hosting dedicated servers. Our servers are basically like any other game client, except they do not spawn a player into the game world and just manage the game state.
From what I can tell, the server client is trying to actually capture/playback audio. How can I turn that off but still ensure that audio data is relayed between the clients?
These are the logs when my game server starts the scene:
For Dissonance to work for all clients connected, do I need to leave
DissonanceComms
enabled so that it relays the data?Dissonance version used: Latest
Unity version: 2020.1.17f1
Editor Operating System and version: Linux (for dedicated servers)