#cs ---------------------------------------------------------------------------- AutoIt Version: 3.3.13.20 (Beta) Author: MALOSSANE TIMOTHEE Version : 0.9 Description: AutoIt library to connect to CasParCG server Currently supports AMCP 2.1 Protocol http://casparcg.com/wiki/CasparCG_2.1_AMCP_Protocol List of functions MAIN CASPARCG FUNCTIONS 00 => AMCP_LoadBG($Param, $Param2, $Param3 = "") ;http://casparcg.com/wiki/CasparCG_2.1_AMCP_Protocol#LOAD 01 => AMCP_Load($Param, $Param2) ;http://casparcg.com/wiki/CasparCG_2.1_AMCP_Protocol#LOAD 02 => AMCP_Play($Param, $Param2) ;http://casparcg.com/wiki/CasparCG_2.1_AMCP_Protocol#PLAY 03 => AMCP_Pause() 04 => AMCP_Resume() 05 => AMCP_Stop() 06 => AMCP_Clear($Param) 07 => AMCP_ClearChannel($Param = "1") 08 => AMCP_ClearLayer($Param, $Param2 = "1") 09 => AMCP_Swap($Param, $Param2, $SwapTransforms = False) 10 => AMCP_SwapWithTransForms($Param, $Param2) 11 => AMCP_CaptureToPNG($Param = 1) 12 => AMCP_Mix($CHANNEL_LAYER = "1", $COMMAND = "", $bWaitForAnswerBeforeReturn = False) HELP/INFO FUNCTIONS 13 => AMCP_GetVersion($Param = "") 14 => AMCP_Help($Param = "") 15 => AMCP_Restart() 16 => AMCP_Kill() 17 => AMCP_GetInfos($Param) 18 => AMCP_ListMedias($Param) 19 => AMCP_ListMedias($Param = "") 20 => AMCP_ListFonts() 21 => AMCP_ListTemplates($Param = "") 22 => AMCP_ListChannels() CUSTOM FUNCTION 23 => AMCP_CustomCommand($Param, $WaitForAnswer = True) NETWORK INTERNAL FUNCTIONS, DO NOT USE IF YOU DON'T KNOW WHAT YOU'RE DOING 24 => AMCP_Send($hSocket, $sText, $bWaitForAnswerBeforeReturn = False, $iWaitForAnswerTimeOut = 5000) 25 => AMCP_ResponseReceived($hSocket, $sReceived, $iError) 26 => AMCP_ParseResponse(ByRef $iHeaderCode, ByRef $sBody, $sTxt) 27 => AMCP_Connect($sIPAddress = "127.0.0.1", $iPort = 5250) 28 => AMCP_Connected($hSocket, $iError) ; Event driven 29 => AMCP_Disconnected($hSocket, $iError) ; Event driven 30 => AMCP_Disconnect($iSocket) 31 => AMCP_Log($__text) 32 => AMCP_SetTCPTimeout($iTimeout = 100) QUEUE FUNCTIONS 33 => AMCP_AddToQueue 34 => AMCP_SendQueue 35 => AMCP_ClearQueue #ce ---------------------------------------------------------------------------- #include "TCP.au3" #include Global $__AMCP_LastConnectedSocket = 0 Global $__AMCP_IsConnected = False Global $__AMCP_ResponseReceived = False Global $__AMCP_ResponseCode = 0 Global $__AMCP_Response = "" Global $__AMCP_RegisterFuncConnected = "" Global $__AMCP_RegisterFuncDisconnected = "" Global $__AMCP_ServerSocket = 0 Global $__AMCP_ServerFunc = "AMCP_ServerResponseReceived" ;GLOBAL Const $AMCP_ErrorNotInitialized = -1 Global Const $AMCP_ErrorNotConnected = -2 Global Const $AMCP_ERROR0 = "WARNING - No response" Global Const $AMCP_ERROR400 = "ERROR - Command not understood and data (terminated by \r\n) is being returned" Global Const $AMCP_ERROR401 = "ERROR - Illegal video_channel" Global Const $AMCP_ERROR402 = "ERROR - Parameter missing" Global Const $AMCP_ERROR403 = "ERROR - Illegal parameter" Global Const $AMCP_ERROR404 = "ERROR - Media file not found" Global Const $AMCP_ERROR500 = "FAILED - Internal server error" Global Const $AMCP_ERROR501 = "FAILED - Internal server error" Global Const $AMCP_ERROR502 = "FAILED - Media file unreadable" Global Const $AMCP_ERROR503 = "FAILED - Access error" Global $__QUEUE[1][20], $__AMCP_QueueModified = False $__QUEUE[0][0] = "" ;Init #Region CASPARCG BASIC FUNCTIONS ;LOADBG [channel:int]{-[layer:int]} [clip:string] {[loop:LOOP]} {[transition:CUT,MIX,PUSH,WIPE,SLIDE] [duration:int] {[tween:string]|linear}{[direction:LEFT,RIGHT]|RIGHT}|CUT 0} {SEEK [frame:int]} {LENGTH [frames:int]} {FILTER [filter:string]} {[auto:AUTO]} ;Loads a producer in the background and prepares it for playout. If no layer is specified the default layer index will be used. ;clip will be parsed by available registered producer factories. If a successfully match is found, the producer will be loaded into the background. ;If a file with the same name (extension excluded) but with the additional postfix _a is found this file will be used as key for the main clip. ;loop will cause the clip to loop. ;When playing and looping the clip will start at frame. ;When playing and loop the clip will end after frames number of frames. ;auto will cause the clip to automatically start when foreground clip has ended (without play). The clip is considered "started" after the optional transition has ended. Func AMCP_LoadBG($Param, $Param2, $Param3 = "") ;http://casparcg.com/wiki/CasparCG_2.1_AMCP_Protocol#LOAD $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "LOADBG " & $Param & " " & $Param2 & " " & $Param3, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_LoadBG::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_LoadBG ;Loads a clip to the foreground and plays the first frame before pausing. If any clip is playing on the target foreground then this clip will be replaced. ;LOAD [video_channel:int]{-[layer:int]|-0} [clip:string] {"additional parameters"} Func AMCP_Load($Param, $Param2) ;http://casparcg.com/wiki/CasparCG_2.1_AMCP_Protocol#LOAD $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "LOAD " & $Param & " " & $Param2, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_Load::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_Load ;Moves clip from background to foreground and starts playing it. If a transition (see LOADBG) is prepared, it will be executed. ;If additional parameters (see LOADBG) are provided then the provided clip will first be loaded to the background. ;PLAY [video_channel:int]{-[layer:int]|-0} {[clip:string]} {"additional parameters"} Func AMCP_Play($Param, $Param2) ;http://casparcg.com/wiki/CasparCG_2.1_AMCP_Protocol#PLAY $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "PLAY " & $Param & " " & $Param2, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::" &"AMCP_Play::"& Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_Play Func AMCP_Pause() Return AMCP_Log("WARNING::" &"AMCP_Pause::"& "Not Implemented") EndFunc ;==>AMCP_Pause Func AMCP_Resume() Return AMCP_Log("WARNING::" &"AMCP_Resume::"& "Not Implemented") EndFunc ;==>AMCP_Resume Func AMCP_Stop() Return AMCP_Log("WARNING::" &"AMCP_Stop::"& "Not Implemented") EndFunc ;==>AMCP_Stop ;Removes all clips (both foreground and background) of the specified layer. If no layer is specified then all layers in the specified video_channel are cleared. ;CLEAR [video_channel:int]{-[layer:int]} Func AMCP_Clear($Param) Local $cmd = "CLEAR " & $Param $retCode = AMCP_Send($__AMCP_LastConnectedSocket, $cmd, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_Clear::" & Eval("AMCP_ERROR" & $retCode)) Else If $__AMCP_ServerSocket <> 0 Then Call($__AMCP_ServerFunc,$__AMCP_ServerSocket, $cmd) ; We send to internal server too EndIf Return $__AMCP_Response EndFunc ;==>AMCP_Clear ;Removes all clips of the specified video_channel are cleared. Func AMCP_ClearChannel($Param = "1") Return AMCP_Clear($Param) EndFunc ;==>AMCP_ClearChannel ;Removes all clips of the specified channel Func AMCP_ClearLayer($Param, $Param2 = "1") Return AMCP_Clear($Param2 & "-" & $Param) EndFunc ;==>AMCP_ClearLayer ;Swaps layers between channels (both foreground and background will be swapped). By specifying TRANSFORMS the transformations of the layers are swapped as well. ;If layers are not specified then all layers in respective video channel will be swapped. Func AMCP_Swap($Param, $Param2, $SwapTransforms = False) Local $cmd = "SWAP " & $Param & " " & $Param2 If $SwapTransforms Then $cmd &= " TRANSFORMS" $retCode = AMCP_Send($__AMCP_LastConnectedSocket, $cmd, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_Swap::" & Eval("AMCP_ERROR" & $retCode)) Else If $__AMCP_ServerSocket <> 0 Then Call($__AMCP_ServerFunc,$__AMCP_ServerSocket, $cmd) ; We send to internal server too EndIf Return $__AMCP_Response EndFunc ;==>AMCP_Swap ;Swaps layers between channels (both foreground and background will be swapped). The transformations of the layers are swapped as well. ;If layers are not specified then all layers in respective video channel will be swapped. Func AMCP_SwapWithTransForms($Param, $Param2) Return AMCP_Swap($Param, $Param2, True) EndFunc ;==>AMCP_SwapWithTransForms ;Adds a consumer to the specified video channel. The string consumer will be parsed by the available consumer factories. If a successful match is found a consumer will be created and added to the video_channel. Different consumers require different parameters, some examples are below. Consumers can alternatively be specified by adding them to the CasparCG config file. ;Specifying consumer_index overrides the index that the consumer itself decides and can later be used with the REMOVE command to remove the consumer. ;ADD [video_channel:int]{-[consumer_index:int]} [consumer:string] [parameters:string] Func ACMP_AddConsumer($Param, $Param2) ;http://casparcg.com/wiki/CasparCG_2.1_AMCP_Protocol#ADD $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "ADD " & $Param & " " & $Param2, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_AddConsumer::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>ACMP_AddConsumer ;Removes an existing consumer from video_channel. If consumer_index is given, the consumer will be removed via its id. If parameters are given instead, the consumer matching those parameters will be removed. ;REMOVE [video_channel:int]{-[consumer_index:int]} {[parameters:string]} Func ACMP_RemoveConsumer($Param, $Param2) ;http://casparcg.com/wiki/CasparCG_2.1_AMCP_Protocol#REMOVE $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "REMOVE " & $Param & " " & $Param2, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_RemoveConsumer::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>ACMP_RemoveConsumer ;Saves an RGBA PNG bitmap still image of the contents of the specified channel in the media folder. ;...will produce a PNG image with the current date and time as the filename for example 20130620T192220.png Func AMCP_CaptureToPNG($Param = 1) $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "PRINT " & $Param, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_CaptureToPNG::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_CaptureToPNG ;MIXER Transformation ;http://casparcg.com/wiki/CasparCG_2.1_AMCP_Protocol#Mixer_Commands ;CHANNEL_LAYER can depend on the COMMAND you type ;CHANNEL_LAYER is almost all the time with format [video_channel:int]{-[layer:int]|-0} ;COMMAND can be : ; KEYER {keyer:0,1|0} ; CHROMA {[enable:0,1] {[target_hue:float] [hue_width:float] [min_saturation:float] [min_brightness:float][softness:float] [spill_suppress:float] [spill_suppress_saturation:float] [show_mask:0,1]}} {[duration:int] {[tween:string]|linear}|0 linear}} ; BLEND {[blend:string]|normal} ; OPACITY {[opacity:float] {[duration:int] {[tween:string]|linear}|0 linear}} ; BRIGHTNESS {[brightness:float] {[duration:int] {[tween:string]|linear}|0 linear}} ; SATURATION {[saturation:float] {[duration:int] {[tween:string]|linear}|0 linear}} ; CONTRAST {[contrast:float] {[duration:int] {[tween:string]|linear}|0 linear}} ; LEVELS {[min-input:float] [max-input:float] [gamma:float] [min-output:float] [max-output:float]{[duration:int] {[tween:string]|linear}|0 linear}} ; FILL {[x:float] [y:float] [x-scale:float] [y-scale:float] {[duration:int] {[tween:string]|linear}|0 ; CLIP {[x:float] [y:float] [width:float] [height:float] {[duration:int] {[tween:string]|linear}|0 linear}} ; ANCHOR {[x:float] [y:float] {[duration:int] {[tween:string]|linear}|0 linear}} ; CROP {[left-edge:float] [top-edge:float] [right-edge:float] [bottom-edge:float] {[duration:int]{[tween:string]|linear}|0 linear}} ; ROTATION {[angle:float] {[duration:int] {[tween:string]|linear}|0 linear}} ; PERSPECTIVE {[top-left-x:float] [top-left-y:float] [top-right-x:float] [top-right-y:float][bottom-right-x:float] [bottom-right-y:float] [bottom-left-x:float] [bottom-left-y:float] {[duration:int] {[tween:string]|linear}|0 linear}} ; MIPMAP {[mipmap:0,1]|0} ; VOLUME {[volume:float] {[duration:int] {[tween:string]|linear}|0 linear}} ; MASTERVOLUME {[volume:float]} ; STRAIGHT_ALPHA_OUTPUT {[straight_alpha:0,1|0]} ; GRID [resolution:int] {[duration:int] {[tween:string]|linear}|0 linear}} ; COMMIT ; CLEAR ;For every command , the parameters explained : ; x ; The new x position, 0 = left edge of monitor, 0.5 = middle of monitor, 1.0 = right edge of monitor. Higher and lower values allowed. ; y ; The new y position, 0 = top edge of monitor, 0.5 = middle of monitor, 1.0 = bottom edge of monitor. Higher and lower values allowed. ; x-scale ; The new x scale, 1 = 1x the screen width, 0.5 = half the screen width. Higher and lower values allowed. Negative values flips the layer. ; y-scale ; The new y scale, 1 = 1x the screen height, 0.5 = half the screen height. Higher and lower values allowed. Negative values flips the layer. ; The positioning and scaling is done around the anchor point set by MIXER ANCHOR. Func AMCP_Mix($CHANNEL_LAYER = "1", $COMMAND = "", $bWaitForAnswerBeforeReturn = False) Local $cmd = "MIXER " & $CHANNEL_LAYER & " " & $COMMAND $retCode = AMCP_Send($__AMCP_LastConnectedSocket, $cmd, $bWaitForAnswerBeforeReturn) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_Mix::" & Eval("AMCP_ERROR" & $retCode)) Else If $__AMCP_ServerSocket <> 0 Then Call($__AMCP_ServerFunc,$__AMCP_ServerSocket, $cmd) ; We send to internal server too ;~ AMCP_Log("TEST " & $__AMCP_ServerFunc&" "&$__AMCP_ServerSocket &" "& $cmd) EndIf EndIf Return $__AMCP_Response EndFunc ;==>AMCP_MIXER #EndRegion CASPARCG BASIC FUNCTIONS #Region CASPARCG SERVER INFOS HELP FUNCTIONS ;Returns the version of specified component. If component is not given, returns Server version ;Possible components : SERVER | FLASH | TEMPLATEHOST | CEF Func AMCP_GetVersion($Param = "") $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "VERSION " & $Param, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_GetVersion::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_GetVersion ;Shows online help for a specific command or a list of all commands. Func AMCP_Help($Param = "") $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "HELP " & $Param, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_Help::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_Help ;Shuts the server down, but exits with return code 5 instead of 0. Intended for use in combination with casparcg_auto_restart.bat Func AMCP_Restart() $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "RESTART", True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_Restart::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_Restart ;Shuts the server down. Func AMCP_Kill() $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "KILL", True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_Kill::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_Kill ;Answer will depend on the parameter you ask ; [video_channel:int]{-[layer:int]} ; Get information about a channel or a specific layer on a channel. ; If layer is ommitted information about the whole channel is returned. ; TEMPLATE [template:string] | CONFIG | PATHS | QUEUES | THREADS | [video_channel:int]{-[layer:int]} DELAY ; http://casparcg.com/wiki/CasparCG_2.1_AMCP_Protocol#INFO Func AMCP_GetInfos($Param) $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "INFO " & $Param, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_GetInfos::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_GetInfos ;Returns information about a media file. ;If a file with the same name exist in multiple directories, all of them are returned. Func AMCP_GetMediaInfos($Param) $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "CINF " & $Param, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_GetMediaInfos::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_ListMedias ;Lists media files in the media folder. Use the command INFO PATHS to get the path to the media folder. ;if the optional sub_directory is specified only the media files in that sub directory will be returned. Func AMCP_ListMedias($Param = "") $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "CLS " & $Param, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_ListMedias::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_ListMedias ;Lists all font files in the fonts folder. Use the command INFO PATHS to get the path to the fonts folder. ;Columns in order from left to right are: Font name and font path. Func AMCP_ListFonts() $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "FLS", True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_ListFonts::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_ListFonts ;Retrieves a list of the available templates ;Lists template files in the templates folder. Use the command INFO PATHS to get the path to the templates folder. ; if the optional sub_directory is specified only the template files in that sub directory will be returned. Func AMCP_ListTemplates($Param = "") $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "TLS " & $Param, True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_ListTemplates::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_ListTemplates ;Retrieves a list of the available channels. Func AMCP_ListChannels() $retCode = AMCP_Send($__AMCP_LastConnectedSocket, "INFO", True) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_ListChannels::" & Eval("AMCP_ERROR" & $retCode)) EndIf Return $__AMCP_Response EndFunc ;==>AMCP_ListChannels ;Send custom command Func AMCP_CustomCommand($Param, $WaitForAnswer = True) $retCode = AMCP_Send($__AMCP_LastConnectedSocket, $Param, $WaitForAnswer) If $retCode = 0 Or $retCode >= 400 Then AMCP_Log("ERROR::"&"AMCP_CustomCommand::" & Eval("AMCP_ERROR" & $retCode)) Else If $__AMCP_ServerSocket <> 0 Then Call($__AMCP_ServerFunc,$__AMCP_ServerSocket, $Param) ; We send to internal server too EndIf Return $__AMCP_Response EndFunc ;==>AMCP_CustomCommand #EndRegion CASPARCG SERVER INFOS HELP FUNCTIONS #Region CASPARCG AMCP NETWORK MAIN FUNCTIONS ;Send data to CasparCG Server ;If you wait for response before continuing, will return CasparCG ACMP Code or 0 if any error ;If you don't wait for response, will answer the number of bytes sent to connected socket or 0 if any error Func AMCP_Send($hSocket, $sText, $bWaitForAnswerBeforeReturn = False, $iWaitForAnswerTimeOut = 5000) $__AMCP_ResponseReceived = False $__AMCP_ResponseCode = 0 $__AMCP_Response = "" AMCP_Log("INFO::Trying to send::" & $sText) If Not $__AMCP_IsConnected Then AMCP_Log("ERROR::"&"AMCP_Send::"&" You must be connected before trying to send any data. ") Return 0 EndIf If StringRight($sText, 2) <> @CRLF Then $sText &= @CRLF $iReturn = _TCP_Send($hSocket, $sText) If $bWaitForAnswerBeforeReturn Then $t = TimerInit() While Not $__AMCP_ResponseReceived And TimerDiff($t) <= $iWaitForAnswerTimeOut Sleep(5) WEnd $iReturn = $__AMCP_ResponseCode EndIf Return $iReturn EndFunc ;==>AMCP_Send ;Event-driven function called when response received from server Func AMCP_ResponseReceived($hSocket, $sReceived, $iError) If $iError Then AMCP_Log("WARNING::AMCP_ResponseReceived::[" & $iError & "] We received this: " & $sReceived) Return 0 EndIf ;AMCP_Log("EVENT:: We received this: "& $sReceived) If Not AMCP_ParseResponse($__AMCP_ResponseCode, $__AMCP_Response, $sReceived) Then ;Parsing successfull Return 0 ; Response is not completed EndIf $__AMCP_ResponseReceived = True Return 1 EndFunc ;==>AMCP_ResponseReceived Func AMCP_ParseResponse(ByRef $iHeaderCode, ByRef $sBody, $sTxt) If $sTxt = "" Then Return -1 $aTemp = StringSplit($sTxt, @CRLF, 1) ;AMCP_Log("DEBUG:: Response part received") $iStart = 1 If $aTemp[0] > 1 Then ; Plus d'une ligne retournée, on teste si la première est bien le header de type "200 PLAY OK \r\n" (Dans le cas ou la reponse est très longue et donc tronquée) If StringRegExp($aTemp[1],"[0-9]{3} [ A-Z]+?") Then $iHeaderCode = Int(StringLeft($aTemp[1], 3)) ;AMCP_Log("RESPONSECODE::" & $iHeaderCode) $iStart = 2 EndIf EndIf For $i = $iStart To $aTemp[0] ; Loop through the array returned by StringSplit to display the individual values. Not taking the last value which is empty \r\n If $aTemp[$i] = "" Then ;AMCP_Log("DEBUG:: Response part was the last one. Completed response.") Return 1 ; Response completed, we have the last \r\n EndIf $sBody &= $aTemp[$i] Next Return 0 EndFunc ;==>AMCP_ParseResponse ;Connect to CasparCG Server Func AMCP_Connect($sIPAddress = "127.0.0.1", $iPort = 5250) If $__AMCP_IsConnected = True Then AMCP_Log("Warning :: Already connected to CasparCG server [" & $sIPAddress & "]" & ", Trying to reconnect...") AMCP_Log("INFO::AMCP_Connect::Trying to open TCP socket to "&$sIPAddress&":"&$iPort) $iSocket = _TCP_Client_Create($sIPAddress, $iPort) If $iSocket = -1 Then ; The server is probably offline/port is not opened on the server. Local $iError = @error AMCP_Log("ERROR::AMCP_Connect::Could not connect to " & $sIPAddress & ":" & $iPort & ", Error code: " & $iError) $__AMCP_IsConnected = False Return 0 EndIf _TCP_RegisterEvent($iSocket, $TCP_CONNECT, "AMCP_Connected") ; And func "Connected" will get called when the client is connected. _TCP_RegisterEvent($iSocket, $TCP_DISCONNECT, "AMCP_Disconnected") ; And "Disconnected" will get called when the server disconnects us, or when the connection is lost. _TCP_RegisterEvent($iSocket, $TCP_RECEIVE, "AMCP_ResponseReceived") ; Function "Received" will get called when something is received AMCP_Connected($iSocket,0,$sIPAddress,$iPort) Return $iSocket EndFunc ;==>AMCP_Connect Func AMCP_CreateShadowServer($FuncName = $__AMCP_ServerFunc,$iPort = 5269) $iServerSocket = _TCP_Server_Create($iPort) If $iServerSocket = -1 Then Local $iError = @error AMCP_Log("ERROR::AMCP_CreateShadowServer:: Could not create shadow server. Passive synchronization won't be enabled during this session. " & " Error code: " & $iError) Return 0 EndIf Global $__AMCP_ServerSocket = $iServerSocket Global $__AMCP_ServerFunc = $FuncName _TCP_RegisterEvent($iServerSocket, $TCP_RECEIVE, $FuncName) ; Function "Received" will get called when something is received Return 1 EndFunc ;~ Event-driven function called when response received from server Func AMCP_ServerResponseReceived($hSocket, $sReceived, $iError) If $iError Then AMCP_Log("WARNING::AMCP_ServerResponseReceived:: [" & $iError & "] We received this: " & $sReceived) Return 0 EndIf AMCP_Log("INFO::AMCP_ServerQueryReceived::" & $sReceived) Return 1 EndFunc ;==>AMCP_ResponseReceived Func AMCP_RegisterEventConnected($func_name) ;Call with empty string to unRegister $__AMCP_RegisterFuncConnected = String($func_name) AMCP_Log("DEBUG::Register func when event connected is fired : "&$__AMCP_RegisterFuncConnected) EndFunc Func AMCP_RegisterEventDisconnected($func_name) $__AMCP_RegisterFuncDisconnected = String($func_name) EndFunc ;Event-driven function called when user connects Func AMCP_Connected($hSocket, $iError,$ip="",$port="") ; Event driven If Not $iError Then AMCP_Log("INFO::Connected to CasparCG server " & " [Socket:" & $hSocket & "]") ;~ If IsDeclared("ip") AND IsDeclared("port") Then AMCP_Log("EVENT::Successfully connected to CasparCG server " & $ip & ":" & $port & " [Socket:" & $hSocket & "]") $__AMCP_IsConnected = True $__AMCP_LastConnectedSocket = $hSocket If $__AMCP_RegisterFuncConnected <> "" Then Call($__AMCP_RegisterFuncConnected,$ip,$port) Else AMCP_Log("INFO::Connexion unsuccessfull to CasparCG server " & " [Socket:" & $hSocket & "], Error code: " & $iError) $__AMCP_IsConnected = False $__AMCP_LastConnectedSocket = 0 If $__AMCP_RegisterFuncDisconnected <> "" Then Call($__AMCP_RegisterFuncDisconnected) EndIf EndFunc ;==>AMCP_Connected ;Event-driven function called when user is disconnected ;TODO :: Automatic reconnection Func AMCP_Disconnected($hSocket, $iError) AMCP_Log("INFO:: We have been disconnected from CasparCG server " & " [Socket:" & $hSocket & "], calling func:"&$__AMCP_RegisterFuncDisconnected) $__AMCP_IsConnected = False $__AMCP_LastConnectedSocket = 0 If $__AMCP_RegisterFuncDisconnected <> "" Then Call($__AMCP_RegisterFuncDisconnected) EndFunc ;==>AMCP_Disconnected ;TODO, SEND BYE to proper disconnect before shutting down socket. Func AMCP_Disconnect($iSocket = $__AMCP_LastConnectedSocket) If $__AMCP_IsConnected Then ;AMCP_Send($iSocket, "BYE", True) AMCP_Disconnected($iSocket,0) _TCP_Client_Stop($iSocket) AMCP_Log("INFO::Successfully disconnected from CasparCG server [" & $iSocket & "]") Return 1 Else AMCP_Log("WARNING:: Could not disconnect from CasparCG server [" & $iSocket & "]" & ", Error : Not connected") Return 0 EndIf EndFunc ;==>AMCP_Disconnect ;Logging function Func AMCP_Log($__text) ConsoleWrite("AMCP::" & $__text & @CRLF) ;~ _Log_Gui_Add($__text) EndFunc ;==>AMCP_Log ;Change TCP timeout, default is 100 milliseconds Func AMCP_SetTCPTimeout($iTimeout = 100) Opt("TCPTimeout", $iTimeout) EndFunc ;==>AMCP_SetTCPTimeout #EndRegion CASPARCG AMCP NETWORK MAIN FUNCTIONS ;Return array of layers that are active on CasparCG chosen channel. Func AMCP_GetActiveLayers($Channel="1") $ret = AMCP_GetInfos($Channel) ;AMCP_Log($ret) ;$ret = StringRegExp($ret,"(?is).*?(.*?).*?",3) $ret = StringRegExp($ret,"(?is).*?(.*?).*?(.*?).*?",3) If Not @error Then Return $ret EndIf Return 0 EndFunc ;~ (?is).*?(?:.*?(.*?).*?)?.*?(.*?).*? #Region CASPARCG QUEUE FUNCTIONS Func AMCP_AddToQueue($v0,$v1 = null, $v2 = null, $v3 = null, $v4 = null, $v5 = null, $v6 = null, $v7 = null, $v8 = null, $v9 = null, $v10 = null, $v11 = null, $v12 = null, $v13 = null, $v14 = null, $v15 = null, $v16 = null, $v17 = null, $v18 = null, $v19 = null) #forceref $v1, $v2, $v3, $v4, $v5, $v6, $v7, $v8, $v9, $v10, $v11, $v12, $v13, $v14, $v15, $v16, $v17, $v18, $v19 ;First increase array to add the new element $__QUEUE[0][0] += 1 $i = $__QUEUE[0][0] ReDim $__QUEUE[$i+1][20] ;Now add the new element $__QUEUE[$i][0] = $v0 For $j = 1 To @NumParams-1 $__QUEUE[$i][$j] = Eval("v" & $j) Next $__AMCP_QueueModified = True EndFunc Func AMCP_ClearQueue() ReDim $__QUEUE[1][20] $__QUEUE[0][0] = 0 $__AMCP_QueueModified = False EndFunc Func AMCP_SendQueue($RemoveSupersededEntries = True) AMCP_Log("DEBUG::AMCP_SendQueue::Starting") Local $localQueue = $__QUEUE ; To protect from event change user during this function execution AMCP_ClearQueue() ; We immediately clear the queue so that it can start to be refilled by user even if we didn't finish this function execution For $i = 1 To $localQueue[0][0] Local $array[1]=["CallArgArray"] Local $command = $localQueue[$i][0]&" " For $j = 1 to 19 If $localQueue[$i][$j] = "" Then ExitLoop $command &= $localQueue[$i][$j]&" " _ArrayAdd($array,$localQueue[$i][$j]) Next ; Let's check if the command we're supposed to send has not been superseded later. (For example we move a layer to X and Y and then to X' and Y', useless to do the first move) If $RemoveSupersededEntries Then $Superseded = False Local $argsToCheck = StringSplit($command," ",2) If UBound($argsToCheck) > 2 Then ;If <=2 not enough arg we play all, no further check Local $stringToCheck = $argsToCheck[0]&" "&$argsToCheck[1]&" "&$argsToCheck[2] ; Ex "MIXER 1-1 FILL" For $j = $i+1 To $localQueue[0][0] $theCheck = $localQueue[$j][0] & " " & $localQueue[$j][1] & " " & $localQueue[$j][2] If StringInStr($theCheck,$stringToCheck) = 1 Then AMCP_Log("WARNING::AMCP_SendQueue::This queue item ["&$stringToCheck&"] won't be played because superseded after.") $Superseded = True EndIf Next EndIf EndIf If not $Superseded Then Call($localQueue[$i][0],$array) If @error = 0xDEAD And @extended = 0xBEEF Then AMCP_Log("ERROR::AMCP_SendQueue::Unable to call following command : "&$localQueue[$i][0]&" with params: "&_ArrayToString($array)) Next ;~ AMCP_Log("AMCP_SendQueue::Empty queue") EndFunc #EndRegion