6 Commits

Author SHA1 Message Date
jwetzell 66ae48cf33 * QMessage.cs:
* QWorkspace.cs:
* QEventHandlers.cs: Cleanup

* QControlKit.csproj:
* QControlKitXamDemo.csproj:
* QControlKitXamDemo.iOS.csproj:
* QControlKitXamDemo.Android.csproj: Update packages
2021-12-28 10:18:58 -06:00
jwetzell 9601d59d81 * QBrowser.cs: Change log levels
* QClient.cs: Change to Queue for TCP sending messages

* QControlKit.csproj:
* Info.plist:
* MainPage.xaml.cs:
* QControlKitXamDemo.csproj:
* QControlKitXamDemo.iOS.csproj:
* QControlKitXamDemo.Android.csproj: Updates

* TCPClient.cs: Start work on send queue for TCP
2021-11-18 00:42:31 -06:00
jwetzell 406bcc9e7f Update publish.yml 2021-09-05 11:32:25 -05:00
jwetzell 015913b2a1 Update version number 2021-09-05 11:28:43 -05:00
jwetzell 6f20d7ba19 * QControlKit.csproj: Update Packages
* QBrowser.cs: Fix zeroconf server loss detection
2021-09-04 10:41:49 -05:00
jwetzell 6dd0f766e8 Add Workspace Event Handlers 2021-07-28 09:07:55 -05:00
13 changed files with 107 additions and 98 deletions
+3 -3
View File
@@ -1,8 +1,8 @@
name: Publish to NuGet name: Publish to NuGet
on: on:
release: push:
types: branches:
- created # When a release is made - master # Default release branch
jobs: jobs:
publish: publish:
name: build, pack & publish name: build, pack & publish
+3 -2
View File
@@ -1,4 +1,6 @@
namespace QControlKit.Events using System;
namespace QControlKit.Events
{ {
public delegate void QServerFoundHandler(object source, QServerFoundArgs args); public delegate void QServerFoundHandler(object source, QServerFoundArgs args);
public delegate void QServerLostHandler(object source, QServerLostArgs args); public delegate void QServerLostHandler(object source, QServerLostArgs args);
@@ -16,7 +18,6 @@
public delegate void QWorkspaceConnectionErrorHandler(object source, QWorkspaceConnectionErrorArgs args); public delegate void QWorkspaceConnectionErrorHandler(object source, QWorkspaceConnectionErrorArgs args);
public delegate void QQLabPreferencesUpdatedHandler(object source, QQLabPreferencesUpdatedArgs args); public delegate void QQLabPreferencesUpdatedHandler(object source, QQLabPreferencesUpdatedArgs args);
public delegate void QCueUpdatedHandler(object source, QCueUpdatedArgs args); public delegate void QCueUpdatedHandler(object source, QCueUpdatedArgs args);
public delegate void QCuePropertiesUpdatedHandler(object source, QCuePropertiesUpdatedArgs args); public delegate void QCuePropertiesUpdatedHandler(object source, QCuePropertiesUpdatedArgs args);
public delegate void QCueListsUpdatesHandler(object source, QCueListsUpdatedArgs args); public delegate void QCueListsUpdatesHandler(object source, QCueListsUpdatedArgs args);
+7 -9
View File
@@ -26,13 +26,17 @@ namespace QControlKit
public async void ProbeForQLabInstances() public async void ProbeForQLabInstances()
{ {
Log.Debug("[qbrowser] probing for instances");
IReadOnlyList<IZeroconfHost> results = await IReadOnlyList<IZeroconfHost> results = await
ZeroconfResolver.ResolveAsync(QBonjour.TCPService,TimeSpan.FromSeconds(3)); ZeroconfResolver.ResolveAsync(QBonjour.TCPService,TimeSpan.FromSeconds(3));
foreach (var zeroconfHost in results) foreach (var zeroconfHost in results)
{ {
Log.Debug($"[qbrowser] found host {zeroconfHost.IPAddress}:{zeroconfHost.DisplayName}");
foreach (var service in zeroconfHost.Services) foreach (var service in zeroconfHost.Services)
{ {
Log.Debug($"[qbrowser] found {service.Key}:{service.Value}");
if (service.Key.Equals(QBonjour.TCPService)) if (service.Key.Equals(QBonjour.TCPService))
{ {
@@ -62,15 +66,9 @@ namespace QControlKit
foreach(var server in qServers) foreach(var server in qServers)
{ {
bool serverToBeRemoved = true; IZeroconfHost found = results.ToList().Find(x => x.IPAddress.Equals(server.host));
foreach(var zeroconfHost in results){
QServer existingServer = serverForAddress(zeroconfHost.IPAddress); if (found == null)
if(server != null)
{
serverToBeRemoved = false;
}
}
if (serverToBeRemoved)
{ {
server.disconnect(); server.disconnect();
servers.Remove(server); servers.Remove(server);
+1 -1
View File
@@ -59,7 +59,7 @@ namespace QControlKit
public void sendMessage(string address, params object[] args) public void sendMessage(string address, params object[] args)
{ {
tcpClient.Send(new OscMessage(address, args)); tcpClient.QueueForSending(new OscMessage(address, args));
Log.Debug($"[client] send message {address} : {args}"); Log.Debug($"[client] send message {address} : {args}");
} }
+7 -3
View File
@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Authors>Joel Wetzell</Authors> <Authors>Joel Wetzell</Authors>
<Version>1.0.0-devel</Version> <Version>1.0.0-devel</Version>
<PackOnBuild>true</PackOnBuild> <PackOnBuild>true</PackOnBuild>
<PackageVersion>0.0.19</PackageVersion> <PackageVersion>0.0.21</PackageVersion>
<PackageId>QControlKit</PackageId> <PackageId>QControlKit</PackageId>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<Summary>Unofficial C# port of Figure53's QLabKit.objc</Summary> <Summary>Unofficial C# port of Figure53's QLabKit.objc</Summary>
@@ -16,14 +16,18 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Serilog" Version="2.10.0" /> <PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Zeroconf" Version="3.4.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Zeroconf" Version="3.5.11" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Constants\" /> <Folder Include="Constants\" />
<Folder Include="Cue\" /> <Folder Include="Cue\" />
<Folder Include="SharpOSC\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="Cue\" /> <None Remove="Cue\" />
<None Remove="SharpOSC" />
<None Remove="Zeroconf" />
<None Remove="SharpOSC\" />
</ItemGroup> </ItemGroup>
</Project> </Project>
+1
View File
@@ -103,6 +103,7 @@ namespace QControlKit
return (parts.Length == 4 && parts[3].Equals("connect")); return (parts.Length == 4 && parts[3].Equals("connect"));
} }
} }
#endregion #endregion
//host method //host method
+8 -41
View File
@@ -24,9 +24,6 @@ namespace QControlKit
private QCue root; private QCue root;
private Timer heartbeatTimer;
private int heartbeatAttempts;
public bool defaultSendUpdatesOSC; public bool defaultSendUpdatesOSC;
public string version; public string version;
@@ -35,6 +32,8 @@ namespace QControlKit
public event QWorkspaceUpdatedHandler WorkspaceUpdated; public event QWorkspaceUpdatedHandler WorkspaceUpdated;
public event QCueListChangedPlaybackPositionHandler CueListChangedPlaybackPosition; public event QCueListChangedPlaybackPositionHandler CueListChangedPlaybackPosition;
public event QWorkspaceConnectionErrorHandler WorkspaceConnectionError; public event QWorkspaceConnectionErrorHandler WorkspaceConnectionError;
public event QWorkspaceDisconnectedHandler WorkspaceDisconnected;
public event QWorkspaceConnectedHandler WorkspaceConnected;
private void Init() private void Init()
{ {
@@ -172,14 +171,14 @@ namespace QControlKit
if(hasPasscode && passcode == null) if(hasPasscode && passcode == null)
{ {
Log.Error($"[workspace] *** workspace <{name}> requires a passcode but none was supplied."); Log.Error($"[workspace] *** workspace <{name}> requires a passcode but none was supplied.");
OnWorkspaceConnectionError(this, new QWorkspaceConnectionErrorArgs { status = "badpass" }); OnWorkspaceConnectionError(this, new QWorkspaceConnectionErrorArgs { status = QConnectionStatus.BadPass });
return; return;
} }
if (!client.connect()) if (!client.connect())
{ {
Log.Error($"[workspace] *** couldn't connect to server client is not connected."); Log.Error($"[workspace] *** couldn't connect to server client is not connected.");
OnWorkspaceConnectionError(this, new QWorkspaceConnectionErrorArgs { status = "unreachable" }); OnWorkspaceConnectionError(this, new QWorkspaceConnectionErrorArgs { status = QConnectionStatus.Error });
return; return;
} }
@@ -216,8 +215,6 @@ namespace QControlKit
Log.Information($"[workspace] disconnecting from <{name}>"); Log.Information($"[workspace] disconnecting from <{name}>");
if (!connected) if (!connected)
return; return;
if (heartbeatTimer != null)
stopHeartbeat();
stopReceivingUpdates(); stopReceivingUpdates();
disconnectFromWorkspace(); disconnectFromWorkspace();
@@ -266,39 +263,7 @@ namespace QControlKit
#endregion #endregion
#region Heartbeat #region Heartbeat
//TODO //TODO? Do I even need this if I only allow TCP and just watch for a change in the state of the TCP connection
public void startHeartbeat()
{
clearHeartbeatTimeout();
sendHeartbeat();
}
public void stopHeartbeat()
{
clearHeartbeatTimeout();
heartbeatAttempts = -1;
}
public void clearHeartbeatTimeout()
{
heartbeatTimer.Stop();
heartbeatTimer = null;
heartbeatAttempts = 0;
//TODO
}
public void sendHeartbeat()
{
client.sendMessage("/thump");
//TODO
}
public void heartbeatTimeout(object sender, ElapsedEventArgs e)
{
//TODO
}
#endregion #endregion
@@ -424,7 +389,7 @@ namespace QControlKit
{ {
//clear passcode if there was one set in the connect() method //clear passcode if there was one set in the connect() method
this.passcode = null; this.passcode = null;
Log.Error($"[workspace] *** Password for workspace {name} was incorrect!"); Log.Error($"[workspace] *** Password for workspace <{name}> was incorrect!");
} }
else else
{ {
@@ -437,6 +402,7 @@ namespace QControlKit
private void OnWorkspaceConnected(object source, QWorkspaceConnectedArgs args) private void OnWorkspaceConnected(object source, QWorkspaceConnectedArgs args)
{ {
Log.Information($"[workspace] Connection to <{name}> successful, finishing things up."); Log.Information($"[workspace] Connection to <{name}> successful, finishing things up.");
WorkspaceConnected?.Invoke(this, new QWorkspaceConnectedArgs());
finishConnection(); finishConnection();
} }
@@ -444,6 +410,7 @@ namespace QControlKit
{ {
//this might not be called with TCP? //this might not be called with TCP?
Log.Warning($"[workspace] *** Workspace has indicated it is disconnecting"); Log.Warning($"[workspace] *** Workspace has indicated it is disconnecting");
WorkspaceDisconnected?.Invoke(this, new QWorkspaceDisconnectedArgs());
} }
private void OnCueListsUpdated(object source, QCueListsUpdatedArgs args) private void OnCueListsUpdated(object source, QCueListsUpdatedArgs args)
+30 -3
View File
@@ -31,7 +31,12 @@ namespace SharpOSC
} }
public delegate void MessageReceivedHandler(object source, MessageEventArgs args); public delegate void MessageReceivedHandler(object source, MessageEventArgs args);
public event MessageReceivedHandler MessageReceived; public event MessageReceivedHandler MessageReceived;
private Queue<OscPacket> SendQueue = new Queue<OscPacket>();
private Thread receivingThread; private Thread receivingThread;
private Thread sendThread;
string _address; string _address;
TcpClient client; TcpClient client;
@@ -54,6 +59,10 @@ namespace SharpOSC
client = new TcpClient(Address, Port); client = new TcpClient(Address, Port);
receivingThread = new Thread(ReceiveLoop); receivingThread = new Thread(ReceiveLoop);
receivingThread.Start(); receivingThread.Start();
sendThread = new Thread(SendLoop);
sendThread.Start();
Log.Debug($"[tcpclient] connected to <{Address}:{Port}>"); Log.Debug($"[tcpclient] connected to <{Address}:{Port}>");
return true; return true;
} }
@@ -65,6 +74,23 @@ namespace SharpOSC
} }
public void QueueForSending(OscPacket packet)
{
SendQueue.Enqueue(packet);
}
private void SendLoop()
{
while (client != null && client.Connected)
{
if(SendQueue.Count > 0)
{
OscPacket packet = SendQueue.Dequeue();
Send(packet);
}
}
}
public void Send(byte[] message) public void Send(byte[] message)
{ {
byte[] slipData = SlipEncode(message); byte[] slipData = SlipEncode(message);
@@ -91,7 +117,7 @@ namespace SharpOSC
public void ReceiveLoop() public void ReceiveLoop()
{ {
while (client.Connected) while (client != null && client.Connected)
{ {
Receive(); Receive();
} }
@@ -124,10 +150,11 @@ namespace SharpOSC
} while (netStream.DataAvailable); } while (netStream.DataAvailable);
//Console.WriteLine("Raw TCP In: " + System.Text.Encoding.UTF8.GetString(responseData.ToArray())); //Console.WriteLine("Raw TCP In: " + System.Text.Encoding.UTF8.GetString(responseData.ToArray()));
OscMessage response = (OscMessage)OscPacket.GetPacket(responseData.Skip(1).ToArray()); OscPacket packet = OscPacket.GetPacket(responseData.Skip(1).ToArray());
OscMessage responseMessage = (OscMessage)packet;
//watch.Stop(); //watch.Stop();
//Console.WriteLine($"TCPCLient - message receive took {watch.ElapsedMilliseconds}ms and {reads} reads"); //Console.WriteLine($"TCPCLient - message receive took {watch.ElapsedMilliseconds}ms and {reads} reads");
OnMessageReceived(response); OnMessageReceived(responseMessage);
} }
} catch(Exception e) } catch(Exception e)
{ {
@@ -57,7 +57,7 @@
<PackageReference Include="Serilog.Sinks.Xamarin"> <PackageReference Include="Serilog.Sinks.Xamarin">
<Version>0.2.0.64</Version> <Version>0.2.0.64</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2083" /> <PackageReference Include="Xamarin.Forms" Version="5.0.0.2291" />
<PackageReference Include="Xamarin.Essentials" Version="1.7.0" /> <PackageReference Include="Xamarin.Essentials" Version="1.7.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -2,37 +2,43 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>UIDeviceFamily</key> <key>UIDeviceFamily</key>
<array> <array>
<integer>1</integer> <integer>1</integer>
<integer>2</integer> <integer>2</integer>
</array> </array>
<key>UISupportedInterfaceOrientations</key> <key>UISupportedInterfaceOrientations</key>
<array> <array>
<string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>UISupportedInterfaceOrientations~ipad</key> <key>UISupportedInterfaceOrientations~ipad</key>
<array> <array>
<string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string> <string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>8.0</string> <string>8.0</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>QControlKitXamDemo</string> <string>QControlKitXamDemo</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>com.companyname.QControlKitXamDemo</string> <string>com.companyname.QControlKitXamDemo</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>QControlKitXamDemo</string> <string>QControlKitXamDemo</string>
<key>XSAppIconAssets</key> <key>XSAppIconAssets</key>
<string>Assets.xcassets/AppIcon.appiconset</string> <string>Assets.xcassets/AppIcon.appiconset</string>
<key>NSBonjourServices</key>
<array>
<string>_qlab._tcp</string>
</array>
<key>NSLocalNetworkUsageDescription</key>
<string>Scan network for QLab instances</string>
</dict> </dict>
</plist> </plist>
@@ -51,6 +51,7 @@
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements> <CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<MtouchLink>None</MtouchLink> <MtouchLink>None</MtouchLink>
<MtouchInterpreter>-all</MtouchInterpreter> <MtouchInterpreter>-all</MtouchInterpreter>
<CodesignProvision>Wildcard</CodesignProvision>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
<DebugType>none</DebugType> <DebugType>none</DebugType>
@@ -130,7 +131,7 @@
<PackageReference Include="Serilog.Sinks.Xamarin"> <PackageReference Include="Serilog.Sinks.Xamarin">
<Version>0.2.0.64</Version> <Version>0.2.0.64</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2083" /> <PackageReference Include="Xamarin.Forms" Version="5.0.0.2291" />
<PackageReference Include="Xamarin.Essentials" Version="1.7.0" /> <PackageReference Include="Xamarin.Essentials" Version="1.7.0" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
@@ -30,7 +30,11 @@ namespace QControlKitXamDemo
{ {
Task.Run(async () => Task.Run(async () =>
{ {
browser.ProbeForQLabInstances(); Device.BeginInvokeOnMainThread(() =>
{
browser.ProbeForQLabInstances();
});
}); });
return true; return true;
}); });
@@ -12,7 +12,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Serilog" Version="2.10.0" /> <PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2083" /> <PackageReference Include="Xamarin.Forms" Version="5.0.0.2291" />
<PackageReference Include="Xamarin.Essentials" Version="1.7.0" /> <PackageReference Include="Xamarin.Essentials" Version="1.7.0" />
</ItemGroup> </ItemGroup>