Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions HighPrecisionTimer/HighPrecisionTimer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>HighPrecisionTimer</RootNamespace>
<AssemblyName>HighPrecisionTimer</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
Expand Down Expand Up @@ -58,4 +58,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>
4 changes: 2 additions & 2 deletions Popcron.Sheets/Popcron.Sheets.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Popcron.Sheets</RootNamespace>
<AssemblyName>Popcron.Sheets</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
Expand Down Expand Up @@ -216,4 +216,4 @@
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
</Project>
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,15 @@
vMix Universal Title Controller (UTC) is program, which work with vMix through official vMix API.
It can replace some paid or expensive software for making titles/scoreboards/lower thirds (by using pure vMix XAML/GT titles)
and add ability of base scripting.

---

## Plugins disponíveis

### SRT Monitor Data Provider

Monitore streams SRT diretamente dentro do vMixUTC, em modo Listener ou Caller, com preview de vídeo embutido.

**[⬇ Baixar SrtMonitorDataProvider.zip](https://github.com/rafalau/vMixUTC/releases/download/v1.1.0-srt/SrtMonitorDataProvider.zip)** (~86 MB — já inclui VLC) — *v1.1: Enable Auto Sync*

Instruções de instalação: [vMixUTCSRTDataProvider/README.md](vMixUTCSRTDataProvider/README.md)
4 changes: 2 additions & 2 deletions vMixAPI/State.cs
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ public bool Update()
}
}

public void UpdateAsync()
public void UpdateAsync(bool ignoreCache = false)
{
SendFunction("", true, x =>
{
Expand Down Expand Up @@ -453,7 +453,7 @@ public void UpdateAsync()
else
Dispatcher.BeginInvoke(updateAction);

});
}, ignoreCache: ignoreCache);
}

// Hold callback state strongly until async response is received and callback is dispatched.
Expand Down
13 changes: 13 additions & 0 deletions vMixController/Classes/MainWindowSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,19 @@ public void UpdatePages()
RaisePropertyChanged(PagesPropertyName);
}

private bool _autoSync = false;

public bool AutoSync
{
get { return _autoSync; }
set
{
if (_autoSync == value) return;
_autoSync = value;
RaisePropertyChanged(nameof(AutoSync));
}
}

internal void AddRecentFile(string fileName)
{
if (RecentFiles == null)
Expand Down
91 changes: 91 additions & 0 deletions vMixController/Classes/VmixTcpSubscriber.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace vMixController.Classes
{
internal sealed class VmixTcpSubscriber : IDisposable
{
public event EventHandler ActsReceived;

private CancellationTokenSource _cts;
private Task _loopTask;
private Timer _debounce;
private const int TcpPort = 8099;
private const int DebounceMs = 300;

public void Start(string host)
{
Stop();
_cts = new CancellationTokenSource();
var token = _cts.Token;
_loopTask = Task.Run(() => LoopAsync(host, token));
}

public void Stop()
{
_cts?.Cancel();
_loopTask = null;
_cts?.Dispose();
_cts = null;
}

private async Task LoopAsync(string host, CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
try
{
using (var client = new TcpClient())
{
client.ReceiveTimeout = 2000;
await client.ConnectAsync(host, TcpPort).ConfigureAwait(false);

using (var stream = client.GetStream())
using (var writer = new StreamWriter(stream) { AutoFlush = true, NewLine = "\r\n" })
using (var reader = new StreamReader(stream))
{
await writer.WriteLineAsync("SUBSCRIBE ACTS").ConfigureAwait(false);

while (!ct.IsCancellationRequested)
{
string line;
try
{
line = await reader.ReadLineAsync().ConfigureAwait(false);
}
catch (IOException) { break; }

if (line == null) break;

// "SUBSCRIBE OK ACTS" is the subscription confirmation — skip it
// actual events arrive as "ACTS OK <function> ..."
if (line.StartsWith("ACTS ", StringComparison.Ordinal))
FireDebounced();
}
}
}
}
catch (OperationCanceledException) { break; }
catch { /* connection failed — retry after delay */ }

try { await Task.Delay(3000, ct).ConfigureAwait(false); }
catch (OperationCanceledException) { break; }
}
}

private void FireDebounced()
{
_debounce?.Dispose();
_debounce = new Timer(_ => ActsReceived?.Invoke(this, EventArgs.Empty), null, DebounceMs, Timeout.Infinite);
}

public void Dispose()
{
Stop();
_debounce?.Dispose();
}
}
}
1 change: 1 addition & 0 deletions vMixController/Controls/vMixControlContainer.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@
<Grid x:Name="Overlay" Background="#7F00FFFF" Visibility="{Binding ParentContainer.Control.Selected, ElementName=CC, Converter={wpfc:BoolToVisibilityConverter}}" IsHitTestVisible="False"/>
<local:vMixControlResizeThumb IsEnabled="{Binding ParentContainer.Control.Locked, ElementName=CC, Converter={wpfc:BoolToInverseBoolConverter}}" Width="4" Cursor="SizeWE" Template="{StaticResource ResizeThumbTemplate}" DataContext="{Binding ParentContainer.Control,ElementName=CC}" Grid.ColumnSpan="2" HorizontalAlignment="Right"/>
<local:vMixControlResizeThumb IsEnabled="{Binding ParentContainer.Control.Locked, ElementName=CC, Converter={wpfc:BoolToInverseBoolConverter}}" Width="4" Cursor="SizeWE" Template="{StaticResource ResizeThumbTemplate}" DataContext="{Binding ParentContainer.Control,ElementName=CC}" Grid.ColumnSpan="2" HorizontalAlignment="Left"/>
<local:vMixControlResizeThumb IsEnabled="{Binding ParentContainer.Control.Locked, ElementName=CC, Converter={wpfc:BoolToInverseBoolConverter}}" Height="4" Cursor="SizeNS" Template="{StaticResource ResizeThumbTemplate}" DataContext="{Binding ParentContainer.Control,ElementName=CC}" Grid.ColumnSpan="2" VerticalAlignment="Bottom" Visibility="{Binding ParentContainer.Control.IsResizeableVertical, ElementName=CC, Converter={wpfc:BoolToVisibilityConverter}}"/>
<local:vMixControlMoveThumb IsEnabled="{Binding ParentContainer.Control.Locked, ElementName=CC, Converter={wpfc:BoolToInverseBoolConverter}}" x:Name="moveThumb" Tag="{Binding ParentContainer.Control.Info, ElementName=CC}" Visibility="Collapsed" Grid.ColumnSpan="3" Template="{StaticResource MoveThumbTemplate}" DataContext="{Binding ParentContainer.Control, ElementName=CC}" Cursor="SizeAll"/>
</Grid>
</Border>
Expand Down
8 changes: 8 additions & 0 deletions vMixController/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,14 @@
</Style>
</MenuItem.Style>
</MenuItem>
<MenuItem IsCheckable="True" IsChecked="{Binding WindowSettings.AutoSync}" ToolTip="Sync automatically when vMix changes (TCP port 8099)">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Width="16" VerticalAlignment="Center" HorizontalAlignment="Center" FontFamily="{StaticResource FontAwesome}" Text="&#xF021;" Margin="0,0,6,0"/>
<TextBlock Text="Enable Auto Sync"/>
</StackPanel>
</MenuItem.Header>
</MenuItem>
</Menu>
<Grid Grid.Row="1" Background="{StaticResource ListBoxBackgroundBrush}">

Expand Down
4 changes: 2 additions & 2 deletions vMixController/Skins/ControlTemplates.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -915,8 +915,8 @@
</Grid>

<StackPanel x:Shared="false" x:Key="ExternalDataWidgetControl" d:DataContext="{d:DesignInstance widget:vMixControlExternalData}">
<ContentControl Content="{Binding DataProvider.CustomUI}"/>
<Button IsEnabled="{Binding DataProvider.IsProvidingCustomProperties}" Visibility="{Binding DataProvider.IsProvidingCustomProperties, Converter={wpfc:BoolToVisibilityConverter}}" Margin="{StaticResource StdMargin}" Command="{Binding OpenPropertiesCommand}" Content="{loc:Loc Key=Widget.ExternalData.Properties}"></Button>
<ContentControl Height="{Binding Height}" Content="{Binding DataProvider.CustomUI}"/>
<Button IsEnabled="{Binding DataProvider.IsProvidingCustomProperties}" Visibility="{Binding DataProvider.IsProvidingCustomProperties, Converter={wpfc:BoolToVisibilityConverter}}" Margin="{StaticResource StdMargin}" Command="{Binding OpenPropertiesCommand}" Content="{loc:Loc Key=Widget.ExternalData.Properties}"/>
</StackPanel>

<Grid x:Shared="false" x:Key="TimerWidgetControl" Margin="{StaticResource StdMargin}" d:DataContext="{d:DesignInstance widget:vMixControlTimer}">
Expand Down
33 changes: 32 additions & 1 deletion vMixController/ViewModel/MainViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ public MainWindowSettings WindowSettings

_windowSettings.PropertyChanged += WindowSettings_PropertyChanged;
RaisePropertyChanged(nameof(WindowSettings));
UpdateAutoSync();
}
}

Expand All @@ -400,6 +401,24 @@ private void WindowSettings_PropertyChanged(object sender, System.ComponentModel
CheckvMixConnection(null, new EventArgs());
});

if (e.PropertyName == nameof(Classes.MainWindowSettings.AutoSync))
UpdateAutoSync();
}

private void UpdateAutoSync()
{
if (WindowSettings?.AutoSync == true)
_autoSyncTimer.Start();
else
_autoSyncTimer.Stop();
}

private void AutoSyncTick(object sender, EventArgs e)
{
if (Model != null)
Model.UpdateAsync(ignoreCache: true);
else
SyncTovMixState();
}

private void LocalizationManager_CultureChanged(object sender, EventArgs e)
Expand Down Expand Up @@ -2374,6 +2393,10 @@ private void Model_OnStateUpdated(object sender, vMixAPI.StateSyncedEventArgs e)

bool ProcessHotkey(Key key, Key systemKey, ModifierKeys modifiers, bool onPress = true)
{
if (Keyboard.FocusedElement is System.Windows.Controls.Primitives.TextBoxBase ||
Keyboard.FocusedElement is System.Windows.Controls.PasswordBox)
return false;

FocusManager.SetFocusedElement(App.Current.MainWindow, (IInputElement)App.Current.MainWindow);

var result = false;
Expand Down Expand Up @@ -2660,6 +2683,8 @@ public RelayCommand ResetScalingCommand

DispatcherTimer _connectTimer = new DispatcherTimer();
DispatcherTimer _metricsTimer = new DispatcherTimer();
DispatcherTimer _autoSyncTimer = new DispatcherTimer();
Classes.VmixTcpSubscriber _tcpSubscriber = new Classes.VmixTcpSubscriber();

string _documentsPath;

Expand Down Expand Up @@ -2744,6 +2769,9 @@ public MainViewModel()
_connectTimer.Tick += CheckvMixConnection;
_connectTimer.Start();

_autoSyncTimer.Interval = TimeSpan.FromSeconds(1);
_autoSyncTimer.Tick += AutoSyncTick;

_metricsTimer.Interval = TimeSpan.FromSeconds(30);
_metricsTimer.Tick += (sender, args) =>
{
Expand All @@ -2754,7 +2782,7 @@ public MainViewModel()
_metricsTimer.Start();

//For loading NCalc before adding buttons to avoid throttle at button click
var _expression = new NCalc.Expression("1+1");
var _expression = new NCalc.SafeExpression("1+1");
_expression.TryEvaluate(out _, out _);

_logger.Info("Loading mapped functions.");
Expand Down Expand Up @@ -3220,6 +3248,9 @@ protected virtual void Dispose(bool managed)
_connectTimer.Stop();
_connectTimer.Tick -= CheckvMixConnection;
_metricsTimer.Stop();
_autoSyncTimer.Stop();
_autoSyncTimer.Tick -= AutoSyncTick;
_tcpSubscriber.Dispose();
LocalizationManager.Instance.CultureChanged -= LocalizationManager_CultureChanged;
vMixAPI.StateFabrique.OnStateCreated -= State_OnStateCreated;
}
Expand Down
2 changes: 2 additions & 0 deletions vMixController/Widgets/vMixControlExternalData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ namespace vMixController.Widgets
[Serializable]
public class vMixControlExternalData : vMixControlTextField, IvMixAutoUpdateWidget
{
public override bool IsResizeableVertical => true;

[NonSerialized]
DispatcherTimer _timer = new DispatcherTimer();

Expand Down
2 changes: 2 additions & 0 deletions vMixController/vMixController.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>settings-gears %281%29.ico</ApplicationIcon>
Expand Down Expand Up @@ -423,6 +424,7 @@
<Compile Include="Classes\Utils.cs" />
<Compile Include="Classes\Scripting\vMixNewFunctionReference.cs" />
<Compile Include="Classes\Scripting\vMixFunctionReference.cs" />
<Compile Include="Classes\VmixTcpSubscriber.cs" />
<Compile Include="Classes\XmlDocumentMessenger.cs" />
<Compile Include="Classes\ScheduledEvent.cs" />
<Compile Include="Controls\ComboBox.cs" />
Expand Down
15 changes: 15 additions & 0 deletions vMixControllerMultiState.sln
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vMixStreamDeckLibrary", "vM
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSystemDataProvider", "FileSystemDataProvider\FileSystemDataProvider.csproj", "{65524B0F-6D11-4BA7-9D79-1A9884E60126}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SrtMonitorDataProvider", "vMixUTCSRTDataProvider\vMixUTCSRTDataProvider.csproj", "{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -264,6 +266,18 @@ Global
{65524B0F-6D11-4BA7-9D79-1A9884E60126}.Release|x64.Build.0 = Release|Any CPU
{65524B0F-6D11-4BA7-9D79-1A9884E60126}.Release|x86.ActiveCfg = Release|Any CPU
{65524B0F-6D11-4BA7-9D79-1A9884E60126}.Release|x86.Build.0 = Release|Any CPU
{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678}.Debug|x64.ActiveCfg = Debug|Any CPU
{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678}.Debug|x64.Build.0 = Debug|Any CPU
{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678}.Debug|x86.ActiveCfg = Debug|Any CPU
{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678}.Debug|x86.Build.0 = Debug|Any CPU
{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678}.Release|Any CPU.Build.0 = Release|Any CPU
{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678}.Release|x64.ActiveCfg = Release|Any CPU
{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678}.Release|x64.Build.0 = Release|Any CPU
{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678}.Release|x86.ActiveCfg = Release|Any CPU
{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -281,6 +295,7 @@ Global
{C16DECA7-0A86-4285-9B3A-99DFD499B4FD} = {E322E6DA-3818-4CBD-A2F6-A94D6C8393BE}
{252E5F34-FA82-488A-939D-EF8DDAAB7D2A} = {E322E6DA-3818-4CBD-A2F6-A94D6C8393BE}
{65524B0F-6D11-4BA7-9D79-1A9884E60126} = {3F500D83-895F-4D44-9CA7-251D4B17B6FE}
{F8A24B3C-E1D2-4F56-A78B-C90D12EF5678} = {3F500D83-895F-4D44-9CA7-251D4B17B6FE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {27068E02-1682-44D7-819A-74759A261167}
Expand Down
4 changes: 4 additions & 0 deletions vMixUTCSRTDataProvider/FodyWeavers.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura/>
</Weavers>
Loading