From dedfcdcd8fbe188bda0cfddbe28799ba47e58b41 Mon Sep 17 00:00:00 2001 From: Dedmen Miller Date: Sat, 1 Oct 2022 13:30:23 +0200 Subject: [PATCH 1/3] Refix again :sad: --- obs-websocket-dotnet/Events.cs | 79 ++++++++++++++++++- obs-websocket-dotnet/OBSWebsocket.cs | 5 +- .../Types/EventSubscription.cs | 31 ++++++++ .../Events/InputVolumeMetersEventArgs.cs | 4 +- .../Types/InputVolumeMeter.cs | 69 ++++++++++++++++ 5 files changed, 182 insertions(+), 6 deletions(-) create mode 100644 obs-websocket-dotnet/Types/EventSubscription.cs create mode 100644 obs-websocket-dotnet/Types/InputVolumeMeter.cs diff --git a/obs-websocket-dotnet/Events.cs b/obs-websocket-dotnet/Events.cs index 4a3504f..946e41b 100644 --- a/obs-websocket-dotnet/Events.cs +++ b/obs-websocket-dotnet/Events.cs @@ -6,6 +6,9 @@ using System.Collections.Generic; using System.Diagnostics; using OBSWebsocketDotNet.Types.Events; +using System.Data.Common; +using System.Net.WebSockets; +using Websocket.Client; namespace OBSWebsocketDotNet { @@ -265,10 +268,31 @@ public partial class OBSWebsocket /// public event EventHandler InputAudioMonitorTypeChanged; + + private event EventHandler inputVolumeMeters; /// /// A high-volume event providing volume levels of all active inputs every 50 milliseconds. /// - public event EventHandler InputVolumeMeters; + public event EventHandler InputVolumeMeters + { + // This event needs special subscription, handle that here + add + { + if (inputVolumeMeters == null || inputVolumeMeters.GetInvocationList().Length == 0) + { + RegisterEvent(EventSubscription.InputVolumeMeters); + } + inputVolumeMeters += value; + } + remove + { + inputVolumeMeters -= value; + if (inputVolumeMeters == null || inputVolumeMeters.GetInvocationList().Length == 0) + { + UnRegisterEvent(EventSubscription.InputVolumeMeters); + } + } + } /// /// The replay buffer has been saved. @@ -292,6 +316,57 @@ public partial class OBSWebsocket #endregion + + #region EventSubscription + + private EventSubscription registeredEvents = EventSubscription.All; + + private void RegisterEvent(EventSubscription newSubscription) + { + registeredEvents |= newSubscription; + SendReidentify(); + } + + private void UnRegisterEvent(EventSubscription removeSubscription) + { + registeredEvents &= ~removeSubscription; + SendReidentify(); + } + + /// + /// Send a Reidentify with new event subscriptions + /// + /// true if we sent the reidentify, false if failed + protected bool SendReidentify() + { + if (wsConnection == null || !wsConnection.IsStarted) return false; // #TODO check if we are in Identified/Connected state, if we didn't send our Identify yet, we shouldn't send Reidentify now + + var requestFields = new JObject + { + { "eventSubscriptions", (uint)registeredEvents } + }; + + try + { + // Throws ErrorResponseException if auth fails + SendRequest(MessageTypes.ReIdentify, null, requestFields, false); + } + catch (ErrorResponseException ex) + { + Disconnected?.Invoke(this, new ObsDisconnectionInfo( + ObsCloseCodes.UnknownReason, + "Reidentify Failed", + new DisconnectionInfo(DisconnectionType.Error, WebSocketCloseStatus.ProtocolError, "Reidentify Failed", String.Empty, new AuthFailureException()) + )); + Disconnect(); + return false; + } + + return true; + } + + #endregion + #region EventProcessing /// @@ -500,7 +575,7 @@ protected void ProcessEventType(string eventType, JObject body) break; case nameof(InputVolumeMeters): - InputVolumeMeters?.Invoke(this, new InputVolumeMetersEventArgs(JsonConvert.DeserializeObject>((string)body["inputs"]))); + inputVolumeMeters?.Invoke(this, new InputVolumeMetersEventArgs(body["inputs"].ToObject>())); break; case nameof(ReplayBufferSaved): diff --git a/obs-websocket-dotnet/OBSWebsocket.cs b/obs-websocket-dotnet/OBSWebsocket.cs index b3c3770..b4dccb2 100644 --- a/obs-websocket-dotnet/OBSWebsocket.cs +++ b/obs-websocket-dotnet/OBSWebsocket.cs @@ -287,7 +287,8 @@ protected void SendIdentify(string password, OBSAuthInfo authInfo = null) { var requestFields = new JObject { - { "rpcVersion", SUPPORTED_RPC_VERSION } + { "rpcVersion", SUPPORTED_RPC_VERSION }, + { "eventSubscriptions", (uint)registeredEvents } }; if (authInfo != null) @@ -301,7 +302,7 @@ protected void SendIdentify(string password, OBSAuthInfo authInfo = null) SendRequest(MessageTypes.Identify, null, requestFields, false); } - + /// /// Encode a Base64-encoded SHA-256 hash /// diff --git a/obs-websocket-dotnet/Types/EventSubscription.cs b/obs-websocket-dotnet/Types/EventSubscription.cs new file mode 100644 index 0000000..629a501 --- /dev/null +++ b/obs-websocket-dotnet/Types/EventSubscription.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OBSWebsocketDotNet.Types +{ + [Flags] + internal enum EventSubscription + { + None = 0, + General = (1 << 0), + Config = (1 << 1), + Scenes = (1 << 2), + Inputs = (1 << 3), + Transitions = (1 << 4), + Filters = (1 << 5), + Outputs = (1 << 6), + SceneItems = (1 << 7), + MediaInputs = (1 << 8), + Vendors = (1 << 9), + Ui = (1 << 10), + All = (General | Config | Scenes | Inputs | Transitions | Filters | Outputs | SceneItems | MediaInputs | Vendors | Ui), + + // High volume event need separate subscription + + InputVolumeMeters = (1 << 16), + InputActiveStateChanged = (1 << 17), + InputShowStateChanged = (1 << 18), + SceneItemTransformChanged = (1 << 19) + } +} diff --git a/obs-websocket-dotnet/Types/Events/InputVolumeMetersEventArgs.cs b/obs-websocket-dotnet/Types/Events/InputVolumeMetersEventArgs.cs index 647929c..11dace7 100644 --- a/obs-websocket-dotnet/Types/Events/InputVolumeMetersEventArgs.cs +++ b/obs-websocket-dotnet/Types/Events/InputVolumeMetersEventArgs.cs @@ -12,13 +12,13 @@ public class InputVolumeMetersEventArgs : EventArgs /// /// Array of active inputs with their associated volume levels /// - public List inputs { get; } + public List inputs { get; } /// /// Default Constructor /// /// Collection inputs as JObjects - public InputVolumeMetersEventArgs(List inputs) + public InputVolumeMetersEventArgs(List inputs) { this.inputs = inputs; } diff --git a/obs-websocket-dotnet/Types/InputVolumeMeter.cs b/obs-websocket-dotnet/Types/InputVolumeMeter.cs new file mode 100644 index 0000000..2f5c076 --- /dev/null +++ b/obs-websocket-dotnet/Types/InputVolumeMeter.cs @@ -0,0 +1,69 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; + +namespace OBSWebsocketDotNet.Types +{ + public class InputVolumeMeter + { + /// + /// Name of the input + /// + [JsonProperty(PropertyName = "inputName")] + public string InputName { set; get; } + + // Convert json Array of 3 scalars, into a struct + private class ChannelLevelConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(ChannelLevel); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType != JsonToken.StartArray) + throw new ProtocolViolationException("Expected InputVolumeMeter/inputLevelsMul to be an array"); + + JToken token = JToken.Load(reader); + var items = token.ToObject(); + + if (items.Length != 3) + throw new ProtocolViolationException($"Expected InputVolumeMeter/inputLevelsMul to be an 3 element array, but instead got {items.Length} element array"); + + ChannelLevel contentStruct; + contentStruct.PeakRaw = items[0]; + contentStruct.PeakWithVolume = items[1]; + contentStruct.magnitudeWithVolume = items[2]; + return contentStruct; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + } + + [JsonConverter(typeof(ChannelLevelConverter))] + public struct ChannelLevel + { + // https://github.com/obsproject/obs-websocket/blob/f4b72b69ce7f9ec6a5fdb1b06971e00d2b091bec/src/utils/Obs_VolumeMeter.cpp#L87 + + + public float magnitudeWithVolume; + public float PeakWithVolume; + public float PeakRaw; + } + + /// + /// Array of channels on this input + /// + [JsonProperty(PropertyName = "inputLevelsMul")] + public List InputLevels { set; get; } + + + } +} From ca4b3f47b6d0aa6942993976d35e2e7e8eab9c9b Mon Sep 17 00:00:00 2001 From: Dedmen Miller Date: Sat, 1 Oct 2022 13:32:10 +0200 Subject: [PATCH 2/3] Fix formatting, sort using directives --- obs-websocket-dotnet/Events.cs | 3 +-- obs-websocket-dotnet/OBSWebsocket.cs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/obs-websocket-dotnet/Events.cs b/obs-websocket-dotnet/Events.cs index 946e41b..958fc11 100644 --- a/obs-websocket-dotnet/Events.cs +++ b/obs-websocket-dotnet/Events.cs @@ -2,11 +2,10 @@ using Newtonsoft.Json.Linq; using OBSWebsocketDotNet.Communication; using OBSWebsocketDotNet.Types; +using OBSWebsocketDotNet.Types.Events; using System; using System.Collections.Generic; using System.Diagnostics; -using OBSWebsocketDotNet.Types.Events; -using System.Data.Common; using System.Net.WebSockets; using Websocket.Client; diff --git a/obs-websocket-dotnet/OBSWebsocket.cs b/obs-websocket-dotnet/OBSWebsocket.cs index b4dccb2..8c488de 100644 --- a/obs-websocket-dotnet/OBSWebsocket.cs +++ b/obs-websocket-dotnet/OBSWebsocket.cs @@ -302,7 +302,7 @@ protected void SendIdentify(string password, OBSAuthInfo authInfo = null) SendRequest(MessageTypes.Identify, null, requestFields, false); } - + /// /// Encode a Base64-encoded SHA-256 hash /// From bf31b71d106265c1aed4989fd8ea9970ba1aadb9 Mon Sep 17 00:00:00 2001 From: Dedmen Miller Date: Sat, 1 Oct 2022 13:32:48 +0200 Subject: [PATCH 3/3] Formatting --- obs-websocket-dotnet/Events.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/obs-websocket-dotnet/Events.cs b/obs-websocket-dotnet/Events.cs index 958fc11..e25b543 100644 --- a/obs-websocket-dotnet/Events.cs +++ b/obs-websocket-dotnet/Events.cs @@ -267,8 +267,6 @@ public partial class OBSWebsocket /// public event EventHandler InputAudioMonitorTypeChanged; - - private event EventHandler inputVolumeMeters; /// /// A high-volume event providing volume levels of all active inputs every 50 milliseconds. /// @@ -292,6 +290,7 @@ public event EventHandler InputVolumeMeters } } } + private event EventHandler inputVolumeMeters; /// /// The replay buffer has been saved.