diff --git a/obs-websocket-dotnet/Events.cs b/obs-websocket-dotnet/Events.cs
index 4a3504f..e25b543 100644
--- a/obs-websocket-dotnet/Events.cs
+++ b/obs-websocket-dotnet/Events.cs
@@ -2,10 +2,12 @@
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.Net.WebSockets;
+using Websocket.Client;
namespace OBSWebsocketDotNet
{
@@ -268,7 +270,27 @@ public partial class OBSWebsocket
///
/// 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);
+ }
+ }
+ }
+ private event EventHandler inputVolumeMeters;
///
/// The replay buffer has been saved.
@@ -292,6 +314,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 +573,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..8c488de 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)
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; }
+
+
+ }
+}