using System; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using KAsyncEngineLib; var options = ProbeOptions.Parse(args); Console.WriteLine($"Karisma TCP probe starting. target={options.Host}:{options.Port} timeout={options.Timeout.TotalSeconds:0}s"); var rawTcpOk = await ProbeRawTcpAsync(options).ConfigureAwait(false); var sdkResult = await ProbeSdkAsync(options).ConfigureAwait(false); Console.WriteLine(); Console.WriteLine("Summary"); Console.WriteLine($"- Raw TCP: {(rawTcpOk ? "OK" : "FAILED")}"); Console.WriteLine($"- SDK Connect(): {(sdkResult.ConnectRequestAccepted ? "ACCEPTED" : "REJECTED")}"); Console.WriteLine($"- SDK OnConnect: {sdkResult.ConnectOutcome}"); Console.WriteLine($"- SDK Detail: {sdkResult.Detail}"); Environment.ExitCode = rawTcpOk && sdkResult.ConnectRequestAccepted && sdkResult.ConnectOutcome == "SUCCESS" ? 0 : 1; static async Task ProbeRawTcpAsync(ProbeOptions options) { try { using var client = new TcpClient(); using var cts = new CancellationTokenSource(options.Timeout); await client.ConnectAsync(options.Host, options.Port, cts.Token).ConfigureAwait(false); Console.WriteLine($"[RAW] Connected local={client.Client.LocalEndPoint} remote={client.Client.RemoteEndPoint}"); return true; } catch (Exception ex) { Console.WriteLine($"[RAW] Failed: {ex.Message}"); return false; } } static Task ProbeSdkAsync(ProbeOptions options) { var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var thread = new Thread(() => { try { var handler = new ProbeEventHandler(); var engine = (IKAEngine)new KAEngineClass(); Console.WriteLine("[SDK] Calling Connect()..."); var connectRequested = engine.Connect(options.Host, options.Port, handler); Console.WriteLine($"[SDK] Connect() returned {(connectRequested != 0 ? "TRUE" : "FALSE")} raw={connectRequested}"); if (connectRequested == 0) { completion.TrySetResult(new SdkProbeResult(false, "FAILED", "Connect() returned 0.")); return; } if (!WaitForTaskWithMessagePump(handler.ConnectTask, options.Timeout)) { completion.TrySetResult(new SdkProbeResult(true, "TIMEOUT", $"OnConnect was not received within {options.Timeout.TotalSeconds:0} seconds.")); return; } var errorCode = handler.ConnectTask.Result; var outcome = errorCode == 0 ? "SUCCESS" : "FAILED"; completion.TrySetResult(new SdkProbeResult(true, outcome, $"OnConnect errorCode={errorCode}")); try { engine.Disconnect(); handler.CloseTask.Wait(TimeSpan.FromSeconds(2)); } catch { } } catch (Exception ex) { completion.TrySetResult(new SdkProbeResult(false, "EXCEPTION", ex.ToString())); } }) { IsBackground = true, Name = "KarismaTcpProbe" }; thread.SetApartmentState(ApartmentState.STA); thread.Start(); return completion.Task; } static bool WaitForTaskWithMessagePump(Task task, TimeSpan timeout) { User32.PeekMessage(out _, IntPtr.Zero, 0, 0, 0); var deadline = DateTime.UtcNow + timeout; while (!task.IsCompleted) { while (User32.PeekMessage(out var message, IntPtr.Zero, 0, 0, 1)) { User32.TranslateMessage(ref message); User32.DispatchMessage(ref message); } if (DateTime.UtcNow >= deadline) { return false; } Thread.Sleep(10); } return true; } internal sealed record ProbeOptions(string Host, int Port, TimeSpan Timeout) { public static ProbeOptions Parse(string[] args) { var host = "127.0.0.1"; var port = 30001; var timeout = TimeSpan.FromSeconds(5); for (var index = 0; index < args.Length; index++) { switch (args[index]) { case "--host" when index + 1 < args.Length: host = args[++index]; break; case "--port" when index + 1 < args.Length && int.TryParse(args[index + 1], out var parsedPort): port = parsedPort; index++; break; case "--timeout" when index + 1 < args.Length && double.TryParse(args[index + 1], out var parsedTimeoutSeconds): timeout = TimeSpan.FromSeconds(parsedTimeoutSeconds); index++; break; } } return new ProbeOptions(host, port, timeout); } } internal sealed record SdkProbeResult(bool ConnectRequestAccepted, string ConnectOutcome, string Detail); internal sealed class ProbeEventHandler : KAEventHandler { private readonly TaskCompletionSource _connectTask = new(TaskCreationOptions.RunContinuationsAsynchronously); private readonly TaskCompletionSource _closeTask = new(TaskCreationOptions.RunContinuationsAsynchronously); public Task ConnectTask => _connectTask.Task; public Task CloseTask => _closeTask.Task; public void OnConnect(int ErrorCode) { Console.WriteLine($"[SDK] OnConnect errorCode={ErrorCode}"); _connectTask.TrySetResult(ErrorCode); } public void OnClose(int ErrorCode) { Console.WriteLine($"[SDK] OnClose errorCode={ErrorCode}"); _closeTask.TrySetResult(ErrorCode); } public void OnLoadScene(eKResult Result, string SceneName) { } public void OnLoadSceneForce(eKResult Result, string SceneName) { } public void OnLogMessage(string LogMessage) { } public void OnMessageNo(uint MessageNo) { } public void OnBeginTransaction(eKResult Result) { } public void OnEndTransaction(eKResult Result) { } public void OnHeartBeat(eKResult Result) { } public void OnUnloadAll(eKResult Result) { } public void OnSetTrialPlayoutMode(eKResult Result) { } public void OnCheckVersion(eKResult Result, string ServerVersion, string SDKVersion) { } public void OnSetAudioOutput(eKResult Result) { } public void OnScenePrepare(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnScenePrepareEx(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnPlay(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnPlayOut(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnStop(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnStopAll(eKResult Result) { } public void OnPause(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnResume(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnQueryIsOnAir(eKResult Result, int OutputChannelIndex, int LayerNo, int bOnAir) { } public void OnTrigger(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnScenePlayingStarted(string SceneName, int OutputChannelIndex, int LayerNo) { } public void OnScenePlayed(string SceneName, int OutputChannelIndex, int LayerNo) { } public void OnSceneAnimationPlayed(string SceneName, int OutputChannelIndex, int LayerNo, string AnimationName) { } public void OnScenePaused(string SceneName, int OutputChannelIndex, int LayerNo, int bLastPause) { } public void OnSceneSaved(eKResult Result, string FileName) { } public void OnTriggerObject(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnResumeBackground(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnSaveMixedPreviewImage(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnPlayDirect(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnCutIn(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnCutOut(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnClearNextPreview(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnPlayRange(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnQueryPlaybackRangeCount(eKResult Result, string SceneName, int PlaybackRangeCount) { } public void OnQueryPlaybackRange(eKResult Result, string SceneName, int PlaybackRangeNo, int Start, int End) { } public void OnQueryOutputChannelIndex(eKResult Result, string SceneName, int OutputChannelIndex) { } public void OnPlayInNextPreview(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnPlayOutNextPreview(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnSetBackgroundFill(eKResult Result, string SceneName) { } public void OnSetBackgroundTexture(eKResult Result, string SceneName) { } public void OnSetBackgroundVideo(eKResult Result, string SceneName) { } public void OnSetBackgroundLiveIn(eKResult Result, string SceneName) { } public void OnUseBackground(eKResult Result, string SceneName) { } public void OnSetBackgroundVideoPlayInfo(eKResult Result, string SceneName) { } public void OnQueryBackgroundVideoPlayInfo(eKResult Result, string SceneName, ref sKVideoPlayInfo pVideoPlayInfo) { } public void OnSetSceneEffectType(eKResult Result, string SceneName) { } public void OnSaveSceneImage(eKResult Result, string SceneName) { } public void OnSaveScene(eKResult Result, string SceneName) { } public void OnUnloadScene(eKResult Result, string SceneName) { } public void OnReloadScene(eKResult Result, string SceneName) { } public void OnUpdateTextures(eKResult Result, string SceneName) { } public void OnSetSceneAudioFile(eKResult Result, string SceneName) { } public void OnEnableSceneAudio(eKResult Result, string SceneName) { } public void OnSetSceneDuration(eKResult Result, string SceneName) { } public void OnSetBackgroundPauseType(eKResult Result, string SceneName) { } public void OnSetBackgroundChangeType(eKResult Result, string SceneName) { } public void OnSetBackgroundPauseAtZeroFrameAsStandBy(eKResult Result, string SceneName) { } public void OnResetDuration(eKResult Result, string SceneName) { } public void OnSetDuration(eKResult Result, string SceneName) { } public void OnAddObject(eKResult Result, string SceneName) { } public void OnAddCloneObject(eKResult Result, string SceneName) { } public void OnUpdateThumbnail(eKResult Result, string SceneName) { } public void OnExportVideo(eKResult Result, string SceneName) { } public void OnStopVideoExporting(eKResult Result) { } public void OnQueryVideoExportingProgress(eKResult Result, string TargetName, int CurrentFrame, int TotalFrame) { } public void OnFinishedVideoExporting(eKResult Result, string FileName) { } public void OnAddPause(eKResult Result, string SceneName) { } public void OnDeletePause(eKResult Result, string SceneName) { } public void OnSetPause(eKResult Result, string SceneName) { } public void OnSetPauseWithIndex(eKResult Result, string SceneName) { } public void OnDeletePauseWithIndex(eKResult Result, string SceneName) { } public void OnQueryPauseCount(eKResult Result, string SceneName, int PauseCount) { } public void OnQueryObjectInfos(eKResult Result, string SceneName, KAObjectInfos pObjectInfos) { } public void OnQueryAnimationNames(eKResult Result, string SceneName, KAStrings pAnimationNames) { } public void OnQueryAnimationCount(eKResult Result, string SceneName, int AnimationCount) { } public void OnQueryObjectInfosByScreenPoint(eKResult Result, KAObjectInfos pObjectInfos) { } public void OnQuerySceneEffectType(eKResult Result, string SceneName, int bInEffect, eKEffectType EffectType, int Duration) { } public void OnQueryDuration(eKResult Result, string SceneName, string AnimationName, int Duration) { } public void OnQueryContentsOfTextObjects(eKResult Result, string SceneName, KAStrings pTexts) { } public void OnSetStyleColor(eKResult Result, string SceneName, string ObjectName) { } public void OnSetStyleTexture(eKResult Result, string SceneName, string ObjectName) { } public void OnSetFaceTextColor(eKResult Result, string SceneName, string ObjectName) { } public void OnSetEdgeTextColor(eKResult Result, string SceneName, string ObjectName) { } public void OnSetShadowTextColor(eKResult Result, string SceneName, string ObjectName) { } public void OnSetVisible(eKResult Result, string SceneName, string ObjectName) { } public void OnSetValue(eKResult Result, string SceneName, string ObjectName) { } public void OnAddText(eKResult Result, string SceneName, string ObjectName) { } public void OnStoreTextStyle(eKResult Result, string SceneName, string ObjectName) { } public void OnSetTextStyle(eKResult Result, string SceneName, string ObjectName) { } public void OnEditText(eKResult Result, string SceneName, string ObjectName) { } public void OnSetFont(eKResult Result, string SceneName, string ObjectName) { } public void OnSetTextRange(eKResult Result, string SceneName, string ObjectName) { } public void OnResetTextRange(eKResult Result, string SceneName, string ObjectName) { } public void OnQueryObjectType(eKResult Result, string SceneName, string ObjectName, eKObjectType ObjectType) { } public void OnSetChartCSVFile(eKResult Result, string SceneName, string ObjectName) { } public void OnSetChartCellData(eKResult Result, string SceneName, string ObjectName) { } public void OnQueryChartDataTable(eKResult Result, string SceneName, string ObjectName, KAChartDataTable Table) { } public void OnQuerySize(eKResult Result, string SceneName, string ObjectName, float Width, float Height) { } public void OnSetSize(eKResult Result, string SceneName, string ObjectName) { } public void OnSetCounterNumberKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetPositionKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetRotationKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetScaleKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetCylinderAngleKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetSphereAngleKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetCircleAngleKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetCropKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetCountDown(eKResult Result, string SceneName, string ObjectName) { } public void OnSetPosition(eKResult Result, string SceneName, string ObjectName) { } public void OnSetRotation(eKResult Result, string SceneName, string ObjectName) { } public void OnSetScale(eKResult Result, string SceneName, string ObjectName) { } public void OnAddPathPoint(eKResult Result, string SceneName, string ObjectName) { } public void OnClearPathPoints(eKResult Result, string SceneName, string ObjectName) { } public void OnAddPathShapePoint(eKResult Result, string SceneName, string ObjectName) { } public void OnClearPathShapePoints(eKResult Result, string SceneName, string ObjectName) { } public void OnQueryScrollRemainingDistance(eKResult Result, string SceneName, string ObjectName, int ScrollRemainingDistance) { } public void OnQueryScrollChildRemainingDistance(eKResult Result, string SceneName, string ObjectName, string ChildName, int ScrollRemainingDistance) { } public void OnAddScrollObject(eKResult Result, string SceneName, string ObjectName) { } public void OnAdjustScrollSpeed(eKResult Result, string SceneName, string ObjectName) { } public void OnSetScrollSpeed(eKResult Result, string SceneName, string ObjectName) { } public void OnSetVariableName(eKResult Result, string SceneName, string ObjectName) { } public void OnSetLoftPositionKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetChangeOut(eKResult Result, string SceneName) { } public void OnModifyPathPoint(eKResult Result, string SceneName, string ObjectName) { } public void OnInitScrollObject(eKResult Result, string SceneName, string ObjectName) { } public void OnSetCounterInfo(eKResult Result, string SceneName, string ObjectName) { } public void OnSetCounterNumber(eKResult Result, string SceneName, string ObjectName) { } public void OnSetCounterRange(eKResult Result, string SceneName, string ObjectName) { } public void OnSetCounterRemainingTime(eKResult Result, string SceneName, string ObjectName) { } public void OnSetCounterElapsedTime(eKResult Result, string SceneName, string ObjectName) { } public void OnSaveObjectImage(eKResult Result, string SceneName, string ObjectName) { } public void OnSetPositionOfPathAnimation(eKResult Result, string SceneName, string ObjectName) { } public void OnSetPositionKeyOfPathAnimation(eKResult Result, string SceneName, string ObjectName) { } public void OnSetStartFrame(eKResult Result, string SceneName, string ObjectName) { } public void OnSetObjectEffectType(eKResult Result, string SceneName, string ObjectName) { } public void OnSetObjectOutEffectDelay(eKResult Result, string SceneName, string ObjectName) { } public void OnSetColor(eKResult Result, string SceneName, string ObjectName) { } public void OnSetColorKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetEmissiveColor(eKResult Result, string SceneName, string ObjectName) { } public void OnSetEmissiveColorKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetTransparencyOpacity(eKResult Result, string SceneName, string ObjectName) { } public void OnSetTransparencyOpacityKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetExposure(eKResult Result, string SceneName, string ObjectName) { } public void OnSetExposureKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetMaterialTextureType(eKResult Result, string SceneName, string ObjectName) { } public void OnSetMaterialTextureFile(eKResult Result, string SceneName, string ObjectName) { } public void OnSetMaterialTextureOffset(eKResult Result, string SceneName, string ObjectName) { } public void OnSetMaterialTextureOffsetKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetMaterialTextureTiling(eKResult Result, string SceneName, string ObjectName) { } public void OnSetMaterialTextureTilingKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetMaterialTextureRotation(eKResult Result, string SceneName, string ObjectName) { } public void OnSetMaterialTextureRotationKey(eKResult Result, string SceneName, string ObjectName) { } public void OnSetMaterialTextureOpacity(eKResult Result, string SceneName, string ObjectName) { } public void OnSetMaterialTextureOpacityKey(eKResult Result, string SceneName, string ObjectName) { } public void OnQueryGroupType(eKResult Result, string SceneName, string ObjectName, eKGroupType GroupType) { } public void OnQueryImageType(eKResult Result, string SceneName, string ObjectName, eKImageType ImageType) { } public void OnSetVideoPlayInfo(eKResult Result, string SceneName, string ObjectName) { } public void OnQueryVideoPlayInfo(eKResult Result, string SceneName, string ObjectName, ref sKVideoPlayInfo pVideoPlayInfo) { } public void OnQueryIs3D(eKResult Result, string SceneName, string ObjectName, int b3D) { } public void OnQueryPosition(eKResult Result, string SceneName, string ObjectName, float X, float Y, float Z) { } public void OnSetImageType(eKResult Result, string SceneName, string ObjectName) { } public void OnSetMemo(eKResult Result, string SceneName, string ObjectName) { } public void OnQueryMemo(eKResult Result, string SceneName, string ObjectName, string Memo) { } public void OnQueryFont(eKResult Result, string SceneName, string ObjectName, ref sKFont Param) { } public void OnSetImageOriginalSize(eKResult Result, string SceneName, string ObjectName) { } public void OnApplyChangeEffectLibrary(eKResult Result, string SceneName) { } public void OnApplyObjectLibrary(eKResult Result, string SceneName, string ObjectName) { } public void OnApplyTextureEffectLibrary(eKResult Result, string SceneName, string ObjectName) { } public void OnSetTableValue(eKResult Result, string SceneName, string ObjectName) { } public void OnSetTableColor(eKResult Result, string SceneName, string ObjectName) { } public void OnQueryTableValue(eKResult Result, string SceneName, string ObjectName, int Row, int Column, string Value) { } public void OnQueryTableValues(eKResult Result, string SceneName, string ObjectName, KATableValues pValues) { } public void OnSetPathShapeOutlineThickness(eKResult Result, string SceneName, string ObjectName) { } public void OnEnablePathShapeOutline(eKResult Result, string SceneName, string ObjectName) { } public void OnSetPlaybackCamera(eKResult Result, string SceneName) { } public void OnSetMaterialTextureVideoPlayInfo(eKResult Result, string SceneName, string ObjectName) { } public void OnQueryMaterialTextureVideoPlayInfo(eKResult Result, string SceneName, string ObjectName, ref sKVideoPlayInfo VideoPlayInfo) { } public void OnQueryVideoFormat(eKResult Result, ref sKVideoFormat VideoFormat) { } public void OnQueryLiveStreamingStatus(eKResult Result, string StreamingURI, eKLiveStreamingStatus Status) { } public void OnPreloadLiveStreaming(eKResult Result, string StreamingURI) { } public void OnReleaseLiveStreaming(eKResult Result, string StreamingURI) { } public void OnUpdateImageResource(eKResult Result) { } public void OnQueryLayerCount(eKResult Result, int LayerCount) { } public void OnSetLayerViewportRate(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnSetLayerViewportRateEx(eKResult Result, int OutputChannelIndex, int LayerNo) { } public void OnSetFitting(eKResult Result, string SceneName) { } public void OnSetFittingOffset(eKResult Result, string SceneName) { } public void OnSetFittingScale(eKResult Result, string SceneName) { } public void OnSetLightColor(eKResult Result, string SceneName, string ObjectName) { } public void OnEnableLight(eKResult Result, string SceneName, string ObjectName) { } public void OnSetDirectionalLight(eKResult Result, string SceneName, string ObjectName) { } public void OnSetPointLight(eKResult Result, string SceneName, string ObjectName) { } public void OnSetSpotLight(eKResult Result, string SceneName, string ObjectName) { } public void OnSetInfinitePointLight(eKResult Result, string SceneName, string ObjectName) { } public void OnSetMaterialTextureLiveStreamingURI(eKResult Result, string SceneName, string ObjectName) { } public void OnSetBackgroundLiveStreamingURI(eKResult Result, string SceneName) { } public void OnLoadProject(eKResult Result, string FilePath, string AliasName) { } public void OnNewProject(eKResult Result, string AliasName) { } public void OnUnloadAllProject(eKResult Result) { } public void OnSaveProject(eKResult Result, string AliasName) { } public void OnQuerySceneItemCount(eKResult Result, string AliasName, int SceneItemCount) { } public void OnQuerySceneItemInfos(eKResult Result, string AliasName, KASceneItemInfos SceneItemInfos) { } public void OnAddSceneItem(eKResult Result, string AliasName, int Index) { } public void OnInsertSceneItem(eKResult Result, string AliasName) { } public void OnDeleteSceneItem(eKResult Result, string AliasNAme) { } public void OnQueryProjectFormat(eKResult Result, ref sKVideoFormat ProjectFormat) { } public void OnSetTimecode(eKResult Result, string AliasName) { } public void OnSetTimecodeInOut(eKResult Result, string AliasName) { } public void OnSetTimecodeTrack(eKResult Result, string AliasName) { } public void OnSetTimecodeInOutType(eKResult Result, string AliasName) { } public void OnDeleteTimecode(eKResult Result, string AliasName) { } public void OnQueryTimecode(eKResult Result, int TrackNo, int In, int Out, int bOnTrack) { } public void OnUnloadProject(eKResult Result, string AliasName) { } public void OnEnableSyncWithSceneEffect(eKResult Result, string AliasName) { } public void OnExportProjectVideo(eKResult Result, string AliasName) { } public void OnExportSceneImage(eKResult Result, string SceneName) { } public void OnStartVideoCapture(eKResult Result) { } public void OnStopVideoCapture(eKResult Result) { } public void OnCaptureImage(eKResult Result) { } } [StructLayout(LayoutKind.Sequential)] internal struct NativeMessage { public IntPtr hwnd; public uint message; public UIntPtr wParam; public IntPtr lParam; public uint time; public NativePoint pt; public uint lPrivate; } [StructLayout(LayoutKind.Sequential)] internal struct NativePoint { public int x; public int y; } internal static class User32 { [DllImport("user32.dll")] internal static extern bool PeekMessage(out NativeMessage lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg); [DllImport("user32.dll")] internal static extern bool TranslateMessage([In] ref NativeMessage lpMsg); [DllImport("user32.dll")] internal static extern IntPtr DispatchMessage([In] ref NativeMessage lpMsg); }