mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-01-14 04:54:53 +00:00
Compare commits
9 Commits
mc-connect
...
v2.24.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fb30d5561 | ||
|
|
57cd77f019 | ||
|
|
7f2bb078c8 | ||
|
|
316bb849b4 | ||
|
|
a983e2c87f | ||
|
|
babb9a77df | ||
|
|
7629921113 | ||
|
|
3878c85a7a | ||
|
|
7ad8218af0 |
13
.config/dotnet-tools.json
Normal file
13
.config/dotnet-tools.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"csharpier": {
|
||||
"version": "1.2.4",
|
||||
"commands": [
|
||||
"csharpier"
|
||||
],
|
||||
"rollForward": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines minimum functionality for an audio zone
|
||||
/// </summary>
|
||||
public interface IAudioZone : IBasicVolumeWithFeedback
|
||||
{
|
||||
void SelectInput(ushort input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifies a device that contains audio zones
|
||||
/// </summary>
|
||||
public interface IAudioZones : IRouting
|
||||
{
|
||||
Dictionary<uint, IAudioZone> Zone { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines minimal volume and mute control methods
|
||||
/// </summary>
|
||||
public interface IBasicVolumeControls : IKeyName
|
||||
{
|
||||
/// <summary>
|
||||
/// Increases the volume
|
||||
/// </summary>
|
||||
/// <param name="pressRelease">Indicates whether the volume change is a press and hold action</param>
|
||||
void VolumeUp(bool pressRelease);
|
||||
|
||||
/// <summary>
|
||||
/// Decreases the volume
|
||||
/// </summary>
|
||||
/// <param name="pressRelease">Indicates whether the volume change is a press and hold action</param>
|
||||
void VolumeDown(bool pressRelease);
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the mute state
|
||||
/// </summary>
|
||||
void MuteToggle();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IBasicVolumeWithFeedback
|
||||
/// </summary>
|
||||
public interface IBasicVolumeWithFeedback : IBasicVolumeControls
|
||||
{
|
||||
BoolFeedback MuteFeedback { get; }
|
||||
void MuteOn();
|
||||
void MuteOff();
|
||||
void SetVolume(ushort level);
|
||||
IntFeedback VolumeLevelFeedback { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IBasicVolumeWithFeedbackAdvanced
|
||||
/// </summary>
|
||||
public interface IBasicVolumeWithFeedbackAdvanced : IBasicVolumeWithFeedback
|
||||
{
|
||||
int RawVolumeLevel { get; }
|
||||
|
||||
eVolumeLevelUnits Units { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IFullAudioSettings
|
||||
/// </summary>
|
||||
public interface IFullAudioSettings : IBasicVolumeWithFeedback
|
||||
{
|
||||
void SetBalance(ushort level);
|
||||
void BalanceLeft(bool pressRelease);
|
||||
void BalanceRight(bool pressRelease);
|
||||
|
||||
void SetBass(ushort level);
|
||||
void BassUp(bool pressRelease);
|
||||
void BassDown(bool pressRelease);
|
||||
|
||||
void SetTreble(ushort level);
|
||||
void TrebleUp(bool pressRelease);
|
||||
void TrebleDown(bool pressRelease);
|
||||
|
||||
bool hasMaxVolume { get; }
|
||||
void SetMaxVolume(ushort level);
|
||||
void MaxVolumeUp(bool pressRelease);
|
||||
void MaxVolumeDown(bool pressRelease);
|
||||
|
||||
bool hasDefaultVolume { get; }
|
||||
void SetDefaultVolume(ushort level);
|
||||
void DefaultVolumeUp(bool pressRelease);
|
||||
void DefaultVolumeDown(bool pressRelease);
|
||||
|
||||
void LoudnessToggle();
|
||||
void MonoToggle();
|
||||
|
||||
BoolFeedback LoudnessFeedback { get; }
|
||||
BoolFeedback MonoFeedback { get; }
|
||||
IntFeedback BalanceFeedback { get; }
|
||||
IntFeedback BassFeedback { get; }
|
||||
IntFeedback TrebleFeedback { get; }
|
||||
IntFeedback MaxVolumeFeedback { get; }
|
||||
IntFeedback DefaultVolumeFeedback { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IHasCurrentVolumeControls
|
||||
/// </summary>
|
||||
public interface IHasCurrentVolumeControls
|
||||
{
|
||||
IBasicVolumeControls CurrentVolumeControls { get; }
|
||||
event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
|
||||
|
||||
void SetDefaultLevels();
|
||||
|
||||
bool ZeroVolumeWhenSwtichingVolumeDevices { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines basic mute control methods
|
||||
/// </summary>
|
||||
public interface IHasMuteControl
|
||||
{
|
||||
void MuteToggle();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines mute control methods and properties with feedback
|
||||
/// </summary>
|
||||
public interface IHasMuteControlWithFeedback : IHasMuteControl
|
||||
{
|
||||
BoolFeedback MuteFeedback { get; }
|
||||
void MuteOn();
|
||||
void MuteOff();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IHasVolumeControl
|
||||
/// </summary>
|
||||
public interface IHasVolumeControl
|
||||
{
|
||||
void VolumeUp(bool pressRelease);
|
||||
void VolumeDown(bool pressRelease);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines volume control methods and properties with feedback
|
||||
/// </summary>
|
||||
public interface IHasVolumeControlWithFeedback : IHasVolumeControl
|
||||
{
|
||||
void SetVolume(ushort level);
|
||||
IntFeedback VolumeLevelFeedback { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IHasVolumeDevice
|
||||
/// </summary>
|
||||
public interface IHasVolumeDevice
|
||||
{
|
||||
IBasicVolumeControls VolumeDevice { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public enum eVolumeLevelUnits
|
||||
{
|
||||
Decibels,
|
||||
Percent,
|
||||
Relative,
|
||||
Absolute
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines minimal volume and mute control methods
|
||||
/// </summary>
|
||||
public interface IBasicVolumeControls
|
||||
{
|
||||
void VolumeUp(bool pressRelease);
|
||||
void VolumeDown(bool pressRelease);
|
||||
void MuteToggle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IHasVolumeControl
|
||||
/// </summary>
|
||||
public interface IHasVolumeControl
|
||||
{
|
||||
void VolumeUp(bool pressRelease);
|
||||
void VolumeDown(bool pressRelease);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines volume control methods and properties with feedback
|
||||
/// </summary>
|
||||
public interface IHasVolumeControlWithFeedback : IHasVolumeControl
|
||||
{
|
||||
void SetVolume(ushort level);
|
||||
IntFeedback VolumeLevelFeedback { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines basic mute control methods
|
||||
/// </summary>
|
||||
public interface IHasMuteControl
|
||||
{
|
||||
void MuteToggle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines mute control methods and properties with feedback
|
||||
/// </summary>
|
||||
public interface IHasMuteControlWithFeedback : IHasMuteControl
|
||||
{
|
||||
BoolFeedback MuteFeedback { get; }
|
||||
void MuteOn();
|
||||
void MuteOff();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IBasicVolumeWithFeedback
|
||||
/// </summary>
|
||||
public interface IBasicVolumeWithFeedback : IBasicVolumeControls
|
||||
{
|
||||
BoolFeedback MuteFeedback { get; }
|
||||
void MuteOn();
|
||||
void MuteOff();
|
||||
void SetVolume(ushort level);
|
||||
IntFeedback VolumeLevelFeedback { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IBasicVolumeWithFeedbackAdvanced
|
||||
/// </summary>
|
||||
public interface IBasicVolumeWithFeedbackAdvanced : IBasicVolumeWithFeedback
|
||||
{
|
||||
int RawVolumeLevel { get; }
|
||||
|
||||
eVolumeLevelUnits Units { get; }
|
||||
}
|
||||
|
||||
public enum eVolumeLevelUnits
|
||||
{
|
||||
Decibels,
|
||||
Percent,
|
||||
Relative,
|
||||
Absolute
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IHasCurrentVolumeControls
|
||||
/// </summary>
|
||||
public interface IHasCurrentVolumeControls
|
||||
{
|
||||
IBasicVolumeControls CurrentVolumeControls { get; }
|
||||
event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
|
||||
|
||||
void SetDefaultLevels();
|
||||
|
||||
bool ZeroVolumeWhenSwtichingVolumeDevices { get; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IFullAudioSettings
|
||||
/// </summary>
|
||||
public interface IFullAudioSettings : IBasicVolumeWithFeedback
|
||||
{
|
||||
void SetBalance(ushort level);
|
||||
void BalanceLeft(bool pressRelease);
|
||||
void BalanceRight(bool pressRelease);
|
||||
|
||||
void SetBass(ushort level);
|
||||
void BassUp(bool pressRelease);
|
||||
void BassDown(bool pressRelease);
|
||||
|
||||
void SetTreble(ushort level);
|
||||
void TrebleUp(bool pressRelease);
|
||||
void TrebleDown(bool pressRelease);
|
||||
|
||||
bool hasMaxVolume { get; }
|
||||
void SetMaxVolume(ushort level);
|
||||
void MaxVolumeUp(bool pressRelease);
|
||||
void MaxVolumeDown(bool pressRelease);
|
||||
|
||||
bool hasDefaultVolume { get; }
|
||||
void SetDefaultVolume(ushort level);
|
||||
void DefaultVolumeUp(bool pressRelease);
|
||||
void DefaultVolumeDown(bool pressRelease);
|
||||
|
||||
void LoudnessToggle();
|
||||
void MonoToggle();
|
||||
|
||||
BoolFeedback LoudnessFeedback { get; }
|
||||
BoolFeedback MonoFeedback { get; }
|
||||
IntFeedback BalanceFeedback { get; }
|
||||
IntFeedback BassFeedback { get; }
|
||||
IntFeedback TrebleFeedback { get; }
|
||||
IntFeedback MaxVolumeFeedback { get; }
|
||||
IntFeedback DefaultVolumeFeedback { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IHasVolumeDevice
|
||||
/// </summary>
|
||||
public interface IHasVolumeDevice
|
||||
{
|
||||
IBasicVolumeControls VolumeDevice { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies a device that contains audio zones
|
||||
/// </summary>
|
||||
public interface IAudioZones : IRouting
|
||||
{
|
||||
Dictionary<uint, IAudioZone> Zone { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines minimum functionality for an audio zone
|
||||
/// </summary>
|
||||
public interface IAudioZone : IBasicVolumeWithFeedback
|
||||
{
|
||||
void SelectInput(ushort input);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,10 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using PepperDash.Essentials.Core.Devices;
|
||||
using Serilog.Events;
|
||||
|
||||
@@ -25,17 +19,25 @@ namespace PepperDash.Essentials.Core.Fusion
|
||||
/// <summary>
|
||||
/// Evaluates the room info and custom properties from Fusion and updates the system properties aa needed
|
||||
/// </summary>
|
||||
/// <param name="roomInfo"></param>
|
||||
public void EvaluateRoomInfo(string roomKey, RoomInformation roomInfo)
|
||||
/// <param name="room">The room associated with this Fusion instance</param>
|
||||
/// <param name="roomInfo">The room information from Fusion</param>
|
||||
/// <param name="useFusionRoomName"></param>
|
||||
public void EvaluateRoomInfo(IEssentialsRoom room, RoomInformation roomInfo, bool useFusionRoomName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var reconfigurableDevices = DeviceManager.AllDevices.Where(d => d is ReconfigurableDevice);
|
||||
var reconfigurableDevices = DeviceManager.AllDevices.OfType<ReconfigurableDevice>();
|
||||
|
||||
foreach (var device in reconfigurableDevices)
|
||||
{
|
||||
// Get the current device config so new values can be overwritten over existing
|
||||
var deviceConfig = (device as ReconfigurableDevice).Config;
|
||||
var deviceConfig = device.Config;
|
||||
|
||||
if (device is IEssentialsRoom)
|
||||
{
|
||||
// Skipping room name as this will affect ALL room instances in the configuration and cause unintended consequences when multiple rooms are present and multiple Fusion instances are used
|
||||
continue;
|
||||
}
|
||||
|
||||
if (device is RoomOnToDefaultSourceWhenOccupied)
|
||||
{
|
||||
@@ -85,36 +87,49 @@ namespace PepperDash.Essentials.Core.Fusion
|
||||
|
||||
deviceConfig.Properties = JToken.FromObject(devProps);
|
||||
}
|
||||
else if (device is IEssentialsRoom)
|
||||
{
|
||||
// Set the room name
|
||||
if (!string.IsNullOrEmpty(roomInfo.Name))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Current Room Name: {0}. New Room Name: {1}", deviceConfig.Name, roomInfo.Name);
|
||||
// Set the name in config
|
||||
deviceConfig.Name = roomInfo.Name;
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Room Name Successfully Changed.");
|
||||
}
|
||||
|
||||
// Set the help message
|
||||
var helpMessage = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomHelpMessage"));
|
||||
if (helpMessage != null)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Debug, "Current Help Message: {0}. New Help Message: {1}", deviceConfig.Properties["help"]["message"].Value<string>(ToString()), helpMessage.CustomFieldValue);
|
||||
deviceConfig.Properties["helpMessage"] = (string)helpMessage.CustomFieldValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the config on the device
|
||||
(device as ReconfigurableDevice).SetConfig(deviceConfig);
|
||||
device.SetConfig(deviceConfig);
|
||||
}
|
||||
|
||||
if (!(room is ReconfigurableDevice reconfigurable))
|
||||
{
|
||||
Debug.LogWarning("FusionCustomPropertiesBridge: Room is not a ReconfigurableDevice. Cannot map custom properties.");
|
||||
return;
|
||||
}
|
||||
|
||||
var roomConfig = reconfigurable.Config;
|
||||
|
||||
var updateConfig = false;
|
||||
|
||||
// Set the room name
|
||||
if (!string.IsNullOrEmpty(roomInfo.Name) && useFusionRoomName)
|
||||
{
|
||||
Debug.LogDebug("Current Room Name: {currentName}. New Room Name: {fusionName}", roomConfig.Name, roomInfo.Name);
|
||||
// Set the name in config
|
||||
roomConfig.Name = roomInfo.Name;
|
||||
updateConfig = true;
|
||||
|
||||
Debug.LogDebug("Room Name Successfully Changed.");
|
||||
}
|
||||
|
||||
// Set the help message
|
||||
var helpMessage = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomHelpMessage"));
|
||||
if (helpMessage != null)
|
||||
{
|
||||
roomConfig.Properties["helpMessage"] = helpMessage.CustomFieldValue;
|
||||
updateConfig = true;
|
||||
}
|
||||
|
||||
if (updateConfig)
|
||||
{
|
||||
reconfigurable.SetConfig(roomConfig);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, "FusionCustomPropetiesBridge: Error mapping properties: {0}", e);
|
||||
Debug.LogError("FusionCustomPropetiesBridge: Exception mapping properties for {roomKey}: {message}", room.Key, e.Message);
|
||||
Debug.LogDebug(e, "Stack Trace: ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
using Crestron.SimplSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Timers;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
using Crestron.SimplSharp.CrestronXml;
|
||||
using Crestron.SimplSharp.CrestronXml.Serialization;
|
||||
@@ -10,11 +15,6 @@ using PepperDash.Core.Logging;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Timers;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Fusion
|
||||
{
|
||||
@@ -1091,7 +1091,7 @@ namespace PepperDash.Essentials.Core.Fusion
|
||||
}
|
||||
RoomInfoChange?.Invoke(this, new EventArgs());
|
||||
|
||||
CustomPropertiesBridge.EvaluateRoomInfo(Room.Key, roomInformation);
|
||||
CustomPropertiesBridge.EvaluateRoomInfo(Room, roomInformation, _config.UseFusionRoomName);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -27,7 +27,7 @@ public class IEssentialsRoomFusionControllerPropertiesConfig
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning( "Failed to parse IpId '{0}' as UInt16", IpId);
|
||||
Debug.LogWarning("Failed to parse IpId '{0}' as UInt16", IpId);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,13 @@ public class IEssentialsRoomFusionControllerPropertiesConfig
|
||||
[JsonProperty("roomKey")]
|
||||
public string RoomKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to use the Fusion room name for this room
|
||||
/// </summary>
|
||||
/// <remarks>Defaults to true to preserve current behavior. Set to false to skip updating the room name from Fusion</remarks>
|
||||
[JsonProperty("useFusionRoomName")]
|
||||
public bool UseFusionRoomName { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to use HTML format for help requests
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Routing
|
||||
{
|
||||
@@ -9,20 +9,20 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
/// Manages routing feedback by subscribing to route changes on midpoint and sink devices,
|
||||
/// tracing the route back to the original source, and updating the CurrentSourceInfo on sink devices.
|
||||
/// </summary>
|
||||
public class RoutingFeedbackManager:EssentialsDevice
|
||||
public class RoutingFeedbackManager : EssentialsDevice
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RoutingFeedbackManager"/> class.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key for this manager device.</param>
|
||||
/// <param name="name">The name of this manager device.</param>
|
||||
public RoutingFeedbackManager(string key, string name): base(key, name)
|
||||
{
|
||||
public RoutingFeedbackManager(string key, string name)
|
||||
: base(key, name)
|
||||
{
|
||||
AddPreActivationAction(SubscribeForMidpointFeedback);
|
||||
AddPreActivationAction(SubscribeForSinkFeedback);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes to the RouteChanged event on all devices implementing <see cref="IRoutingWithFeedback"/>.
|
||||
/// </summary>
|
||||
@@ -41,12 +41,13 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
/// </summary>
|
||||
private void SubscribeForSinkFeedback()
|
||||
{
|
||||
var sinkDevices = DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitchingWithInputPort>();
|
||||
var sinkDevices =
|
||||
DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitchingWithInputPort>();
|
||||
|
||||
foreach (var device in sinkDevices)
|
||||
{
|
||||
device.InputChanged += HandleSinkUpdate;
|
||||
}
|
||||
foreach (var device in sinkDevices)
|
||||
{
|
||||
device.InputChanged += HandleSinkUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -55,11 +56,15 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
/// </summary>
|
||||
/// <param name="midpoint">The midpoint device that reported a route change.</param>
|
||||
/// <param name="newRoute">The descriptor of the new route.</param>
|
||||
private void HandleMidpointUpdate(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute)
|
||||
private void HandleMidpointUpdate(
|
||||
IRoutingWithFeedback midpoint,
|
||||
RouteSwitchDescriptor newRoute
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
var devices = DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitchingWithInputPort>();
|
||||
var devices =
|
||||
DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitchingWithInputPort>();
|
||||
|
||||
foreach (var device in devices)
|
||||
{
|
||||
@@ -68,7 +73,13 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error handling midpoint update from {midpointKey}:{Exception}", this, midpoint.Key, ex);
|
||||
Debug.LogMessage(
|
||||
ex,
|
||||
"Error handling midpoint update from {midpointKey}:{Exception}",
|
||||
this,
|
||||
midpoint.Key,
|
||||
ex
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +89,10 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
/// </summary>
|
||||
/// <param name="sender">The sink device that reported an input change.</param>
|
||||
/// <param name="currentInputPort">The new input port selected on the sink device.</param>
|
||||
private void HandleSinkUpdate(IRoutingSinkWithSwitching sender, RoutingInputPort currentInputPort)
|
||||
private void HandleSinkUpdate(
|
||||
IRoutingSinkWithSwitching sender,
|
||||
RoutingInputPort currentInputPort
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -86,7 +100,13 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error handling Sink update from {senderKey}:{Exception}", this, sender.Key, ex);
|
||||
Debug.LogMessage(
|
||||
ex,
|
||||
"Error handling Sink update from {senderKey}:{Exception}",
|
||||
this,
|
||||
sender.Key,
|
||||
ex
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,13 +116,27 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
/// </summary>
|
||||
/// <param name="destination">The destination sink device to update.</param>
|
||||
/// <param name="inputPort">The currently selected input port on the destination device.</param>
|
||||
private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Updating destination {destination} with inputPort {inputPort}", this, destination?.Key, inputPort?.Key);
|
||||
private void UpdateDestination(
|
||||
IRoutingSinkWithSwitching destination,
|
||||
RoutingInputPort inputPort
|
||||
)
|
||||
{
|
||||
Debug.LogMessage(
|
||||
Serilog.Events.LogEventLevel.Debug,
|
||||
"Updating destination {destination} with inputPort {inputPort}",
|
||||
this,
|
||||
destination?.Key,
|
||||
inputPort?.Key
|
||||
);
|
||||
|
||||
if(inputPort == null)
|
||||
if (inputPort == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "Destination {destination} has not reported an input port yet", this,destination.Key);
|
||||
Debug.LogMessage(
|
||||
Serilog.Events.LogEventLevel.Debug,
|
||||
"Destination {destination} has not reported an input port yet",
|
||||
this,
|
||||
destination.Key
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -111,11 +145,19 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
{
|
||||
var tieLines = TieLineCollection.Default;
|
||||
|
||||
firstTieLine = tieLines.FirstOrDefault(tl => tl.DestinationPort.Key == inputPort.Key && tl.DestinationPort.ParentDevice.Key == inputPort.ParentDevice.Key);
|
||||
firstTieLine = tieLines.FirstOrDefault(tl =>
|
||||
tl.DestinationPort.Key == inputPort.Key
|
||||
&& tl.DestinationPort.ParentDevice.Key == inputPort.ParentDevice.Key
|
||||
);
|
||||
|
||||
if (firstTieLine == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No tieline found for inputPort {inputPort}. Clearing current source", this, inputPort);
|
||||
Debug.LogMessage(
|
||||
Serilog.Events.LogEventLevel.Debug,
|
||||
"No tieline found for inputPort {inputPort}. Clearing current source",
|
||||
this,
|
||||
inputPort
|
||||
);
|
||||
|
||||
var tempSourceListItem = new SourceListItem
|
||||
{
|
||||
@@ -123,12 +165,13 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
Name = inputPort.Key,
|
||||
};
|
||||
|
||||
|
||||
destination.CurrentSourceInfo = tempSourceListItem; ;
|
||||
destination.CurrentSourceInfo = tempSourceListItem;
|
||||
;
|
||||
destination.CurrentSourceInfoKey = "$transient";
|
||||
return;
|
||||
}
|
||||
} catch (Exception ex)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error getting first tieline: {Exception}", this, ex);
|
||||
return;
|
||||
@@ -143,7 +186,12 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
|
||||
if (sourceTieLine == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route found to source for inputPort {inputPort}. Clearing current source", this, inputPort);
|
||||
Debug.LogMessage(
|
||||
Serilog.Events.LogEventLevel.Debug,
|
||||
"No route found to source for inputPort {inputPort}. Clearing current source",
|
||||
this,
|
||||
inputPort
|
||||
);
|
||||
|
||||
var tempSourceListItem = new SourceListItem
|
||||
{
|
||||
@@ -155,32 +203,45 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
destination.CurrentSourceInfoKey = string.Empty;
|
||||
return;
|
||||
}
|
||||
} catch(Exception ex)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error getting sourceTieLine: {Exception}", this, ex);
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root TieLine {tieLine}", this, sourceTieLine);
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root TieLine {tieLine}", this, sourceTieLine);
|
||||
|
||||
// Does not handle combinable scenarios or other scenarios where a display might be part of multiple rooms yet.
|
||||
var room = DeviceManager.AllDevices.OfType<IEssentialsRoom>().FirstOrDefault((r) => {
|
||||
if(r is IHasMultipleDisplays roomMultipleDisplays)
|
||||
{
|
||||
return roomMultipleDisplays.Displays.Any(d => d.Value.Key == destination.Key);
|
||||
}
|
||||
var room = DeviceManager
|
||||
.AllDevices.OfType<IEssentialsRoom>()
|
||||
.FirstOrDefault(
|
||||
(r) =>
|
||||
{
|
||||
if (r is IHasMultipleDisplays roomMultipleDisplays)
|
||||
{
|
||||
return roomMultipleDisplays.Displays.Any(d =>
|
||||
d.Value.Key == destination.Key
|
||||
);
|
||||
}
|
||||
|
||||
if(r is IHasDefaultDisplay roomDefaultDisplay)
|
||||
{
|
||||
return roomDefaultDisplay.DefaultDisplay.Key == destination.Key;
|
||||
}
|
||||
if (r is IHasDefaultDisplay roomDefaultDisplay)
|
||||
{
|
||||
return roomDefaultDisplay.DefaultDisplay.Key == destination.Key;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if(room == null)
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
if (room == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "No room found for display {destination}", this, destination.Key);
|
||||
Debug.LogMessage(
|
||||
Serilog.Events.LogEventLevel.Debug,
|
||||
"No room found for display {destination}",
|
||||
this,
|
||||
destination.Key
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -190,29 +251,45 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
|
||||
if (sourceList == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "No source list found for source list key {key}. Unable to find source for tieLine {sourceTieLine}", this, room.SourceListKey, sourceTieLine);
|
||||
Debug.LogMessage(
|
||||
Serilog.Events.LogEventLevel.Debug,
|
||||
"No source list found for source list key {key}. Unable to find source for tieLine {sourceTieLine}",
|
||||
this,
|
||||
room.SourceListKey,
|
||||
sourceTieLine
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found sourceList for room {room}", this, room.Key);
|
||||
|
||||
var sourceListItem = sourceList.FirstOrDefault(sli => {
|
||||
//// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose,
|
||||
// "SourceListItem {sourceListItem}:{sourceKey} tieLine sourceport device key {sourcePortDeviceKey}",
|
||||
// this,
|
||||
// sli.Key,
|
||||
// sli.Value.SourceKey,
|
||||
// sourceTieLine.SourcePort.ParentDevice.Key);
|
||||
var sourceListItem = sourceList.FirstOrDefault(sli =>
|
||||
{
|
||||
//// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose,
|
||||
// "SourceListItem {sourceListItem}:{sourceKey} tieLine sourceport device key {sourcePortDeviceKey}",
|
||||
// this,
|
||||
// sli.Key,
|
||||
// sli.Value.SourceKey,
|
||||
// sourceTieLine.SourcePort.ParentDevice.Key);
|
||||
|
||||
return sli.Value.SourceKey.Equals(sourceTieLine.SourcePort.ParentDevice.Key,StringComparison.InvariantCultureIgnoreCase);
|
||||
});
|
||||
return sli.Value.SourceKey.Equals(
|
||||
sourceTieLine.SourcePort.ParentDevice.Key,
|
||||
StringComparison.InvariantCultureIgnoreCase
|
||||
);
|
||||
});
|
||||
|
||||
var source = sourceListItem.Value;
|
||||
var sourceKey = sourceListItem.Key;
|
||||
|
||||
if (source == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No source found for device {key}. Creating transient source for {destination}", this, sourceTieLine.SourcePort.ParentDevice.Key, destination);
|
||||
Debug.LogMessage(
|
||||
Serilog.Events.LogEventLevel.Debug,
|
||||
"No source found for device {key}. Creating transient source for {destination}",
|
||||
this,
|
||||
sourceTieLine.SourcePort.ParentDevice.Key,
|
||||
destination
|
||||
);
|
||||
|
||||
var tempSourceListItem = new SourceListItem
|
||||
{
|
||||
@@ -221,7 +298,7 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
};
|
||||
|
||||
destination.CurrentSourceInfoKey = "$transient";
|
||||
destination.CurrentSourceInfo = tempSourceListItem;
|
||||
destination.CurrentSourceInfo = tempSourceListItem;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -229,7 +306,6 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
|
||||
destination.CurrentSourceInfoKey = sourceKey;
|
||||
destination.CurrentSourceInfo = source;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -249,29 +325,49 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
{
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device {sourceDevice} is midpoint", this, midpoint);
|
||||
|
||||
if(midpoint.CurrentRoutes == null || midpoint.CurrentRoutes.Count == 0)
|
||||
if (midpoint.CurrentRoutes == null || midpoint.CurrentRoutes.Count == 0)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Midpoint {midpointKey} has no routes",this, midpoint.Key);
|
||||
Debug.LogMessage(
|
||||
Serilog.Events.LogEventLevel.Debug,
|
||||
"Midpoint {midpointKey} has no routes",
|
||||
this,
|
||||
midpoint.Key
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => {
|
||||
var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route =>
|
||||
{
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", this, route, tieLine);
|
||||
|
||||
return route.OutputPort != null && route.InputPort != null && route.OutputPort?.Key == tieLine.SourcePort.Key && route.OutputPort?.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key;
|
||||
return route.OutputPort != null
|
||||
&& route.InputPort != null
|
||||
&& route.OutputPort?.Key == tieLine.SourcePort.Key
|
||||
&& route.OutputPort?.ParentDevice.Key
|
||||
== tieLine.SourcePort.ParentDevice.Key;
|
||||
});
|
||||
|
||||
if (currentRoute == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route through midpoint {midpoint} for outputPort {outputPort}", this, midpoint.Key, tieLine.SourcePort);
|
||||
Debug.LogMessage(
|
||||
Serilog.Events.LogEventLevel.Debug,
|
||||
"No route through midpoint {midpoint} for outputPort {outputPort}",
|
||||
this,
|
||||
midpoint.Key,
|
||||
tieLine.SourcePort
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found currentRoute {currentRoute} through {midpoint}", this, currentRoute, midpoint);
|
||||
|
||||
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => {
|
||||
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl =>
|
||||
{
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", tl.DestinationPort.Key, currentRoute.InputPort.Key);
|
||||
return tl.DestinationPort.Key == currentRoute.InputPort.Key && tl.DestinationPort.ParentDevice.Key == currentRoute.InputPort.ParentDevice.Key; });
|
||||
return tl.DestinationPort.Key == currentRoute.InputPort.Key
|
||||
&& tl.DestinationPort.ParentDevice.Key
|
||||
== currentRoute.InputPort.ParentDevice.Key;
|
||||
});
|
||||
|
||||
if (nextTieLine != null)
|
||||
{
|
||||
@@ -286,19 +382,26 @@ namespace PepperDash.Essentials.Core.Routing
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLIne Source Device {sourceDeviceKey} is IRoutingSource: {isIRoutingSource}", this, tieLine.SourcePort.ParentDevice.Key, tieLine.SourcePort.ParentDevice is IRoutingSource);
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source Device interfaces: {typeFullName}:{interfaces}", this, tieLine.SourcePort.ParentDevice.GetType().FullName, tieLine.SourcePort.ParentDevice.GetType().GetInterfaces().Select(i => i.Name));
|
||||
|
||||
if (tieLine.SourcePort.ParentDevice is IRoutingSource || tieLine.SourcePort.ParentDevice is IRoutingOutputs) //end of the chain
|
||||
if (
|
||||
tieLine.SourcePort.ParentDevice is IRoutingSource
|
||||
|| tieLine.SourcePort.ParentDevice is IRoutingOutputs
|
||||
) //end of the chain
|
||||
{
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root: {tieLine}", this, tieLine);
|
||||
return tieLine;
|
||||
}
|
||||
|
||||
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == tieLine.SourcePort.Key && tl.DestinationPort.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key );
|
||||
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl =>
|
||||
tl.DestinationPort.Key == tieLine.SourcePort.Key
|
||||
&& tl.DestinationPort.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key
|
||||
);
|
||||
|
||||
if (nextTieLine != null)
|
||||
{
|
||||
return GetRootTieLine(nextTieLine);
|
||||
}
|
||||
} catch (Exception ex)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error walking tieLines: {Exception}", this, ex);
|
||||
return null;
|
||||
|
||||
@@ -61,13 +61,18 @@ namespace PepperDash.Essentials.Devices.Common.DSP
|
||||
/// <summary>
|
||||
/// Base class for DSP control points
|
||||
/// </summary>
|
||||
public abstract class DspControlPoint : IKeyed
|
||||
public abstract class DspControlPoint : IKeyName
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Key
|
||||
/// </summary>
|
||||
public string Key { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Name
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the DspControlPoint class
|
||||
/// </summary>
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
/// <param name="messagePath">The message path.</param>
|
||||
/// <param name="device">The device.</param>
|
||||
public DeviceVolumeMessenger(string key, string messagePath, IBasicVolumeControls device)
|
||||
: base(key, messagePath, device as IKeyName)
|
||||
: base(key, messagePath, device)
|
||||
{
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,14 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value))
|
||||
}));
|
||||
};
|
||||
|
||||
inputSlot.IsOnline.OutputChange += (sender, args) =>
|
||||
{
|
||||
PostStatusMessage(JToken.FromObject(new
|
||||
{
|
||||
inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value))
|
||||
}));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user