; 2017-08-03
; //// Monitoring the TCP connection between obs32.exe and the ip camera (RTSP port 554) ////
; - If OBS isn't open yet, opens and starts streaming
; - Attempts to restart ip camera connection when lost
;
; NOTE:
; PRELIMINARY VERSION
; WARNING - as it is, it creates a logfile; if things don't go as planned, the log file can become VERY LARGE!
; (let's say 10MB per hour)
;
;
; ADAPTED FROM:
; NETWORK CONNECTIONS VIEWER, written by trancexx
; https://www.autoitscript.com/forum/topic/87581-check-a-tcp-ip-connection/
; exits if another instance is already running
#include <Misc.au3>
If _Singleton("ConnView_STRIPED_DOWN", 1) = 0 Then
__Log("FATAL ERROR: Another instance of this program is already running. Exiting...")
Exit
EndIf
#include <Array.au3>
Global Const $sFullPath = "C:\Program Files (x86)\obs-studio\bin\32bit\"
Global Const $sPIDname = "obs32.exe"
Global Const $sWinTitle = "[TITLE:OBS; CLASS:Qt5QWindowIcon]"
Global Const $sWinText = "obs32"
Global Const $sProfile = "Untitled" ; profile name - if no match, opens profile from last execution
Global Const $sCollection = "Untitled" ; scene collection name - if no match, opens scene collection from last execution
Global Const $sRemoteIP = "192.168.1.64" ; your camera ip
Global Const $iRemotePort = 554 ; RTSP port
Global Const $iSleepTime = 2000 ; delay to check for connection
Global Const $sSendHide = "{CTRLDOWN}{ALTDOWN}{SHIFTDOWN}H{CTRLUP}{ALTUP}{SHIFTUP}" ; OBS hotkey to hide media (stop)
Global Const $sSendShow = "{CTRLDOWN}{ALTDOWN}{SHIFTDOWN}S{CTRLUP}{ALTUP}{SHIFTUP}" ; OBS hotkey to show media (play)
Opt("MustDeclareVars", 1)
Opt("WinWaitDelay", 0) ; 0 ms
Global Const $hNTDLL = DllOpen("ntdll.dll")
Global Const $hKERNEL32 = DllOpen("kernel32.dll")
Global Const $hUSER32 = DllOpen("user32.dll")
Global Const $hIPHLPAPI = DllOpen("iphlpapi.dll")
Global Const $hWS232 = DllOpen("ws2_32.dll")
Global Const $hPSAPI = DllOpen("psapi.dll")
Global Const $hWTSAPI32 = DllOpen("wtsapi32.dll")
Global Const $hADVAPI32 = DllOpen("advapi32.dll")
Global $aTCPArray
Global $hLog = FileOpen("log.txt", 1)
Func __Log($comment)
Local $sLine = __DATETIME()&@TAB&$comment
ConsoleWrite("-> (Logged) " & $sLine & @CRLF)
FileWriteLine($hLog, $sLine)
EndFunc
; START LOOP
While 1
While Not ProcessExists($sPIDname)
__Log("ERROR: Process """ & $sPIDname & """ not found. Starting process...")
ShellExecute ($sFullPath&$sPIDname, "--profile """&$sProfile&""" --collection """&$sCollection&""" --startstreaming", $sFullPath)
ProcessWait($sPIDname, $iSleepTime*5)
;Exit -2
WEnd
$aTCPArray = _CV_GetExtendedTcpTable()
If @error Then
__Log("FATAL ERROR: Unable to get TCP table. Exiting...")
Exit -2
EndIf
;_ArrayDisplay($aTCPArray, "TCP Table")
If UBound($aTCPArray) < 1 Then
__Log("Connection not found between """ & $sPIDname & """ and IP address " & $sRemoteIP & " at port " & $iRemotePort)
__Restart_Media()
Else
If UBound($aTCPArray) > 1 Then
__Log("WARNING: More than one connection exists between """ & $sPIDname & """ and IP address " & $sRemoteIP & " at port " & $iRemotePort)
EndIf
For $i = 0 To UBound($aTCPArray) - 1
If $aTCPArray[$i][2] <> "ESTABLISHED" Then
__Log("ERROR: Connection between """ & $sPIDname & """ and IP address " & $sRemoteIP & " at port " & $iRemotePort & " has state """ & $aTCPArray[$i][2] & """")
__Restart_Media()
Else
ConsoleWrite("+> " & __DATETIME()&@TAB& "IP Camera stream connection to OBS seems to be ok" & @CRLF)
EndIf
Next
EndIf
Sleep($iSleepTime)
WEnd
Func _CV_GetExtendedTcpTable()
Local $aCall = DllCall($hIPHLPAPI, "dword", "GetExtendedTcpTable", _
"ptr*", 0, _
"dword*", 0, _
"int", 1, _ ; 1, sort in ascending order
"dword", 2, _ ; AF_INET4
"dword", 5, _ ; TCP_TABLE_OWNER_PID_ALL
"dword", 0)
If @error Then
Return SetError(1, 0, 0)
EndIf
If $aCall[0] <> 122 Then ; ERROR_INSUFFICIENT_BUFFER
Return SetError(2, 0, 0)
EndIf
Local $iSize = $aCall[2]
Local $tByteStructure = DllStructCreate("byte[" & $iSize & "]")
$aCall = DllCall($hIPHLPAPI, "dword", "GetExtendedTcpTable", _
"ptr", DllStructGetPtr($tByteStructure), _
"dword*", $iSize, _
"int", 1, _ ; 1, sort in ascending order
"dword", 2, _ ; AF_INET4
"dword", 5, _ ; TCP_TABLE_OWNER_PID_ALL
"dword", 0)
If @error Or $aCall[0] Then
Return SetError(3, 0, 0)
EndIf
Local $tMIB_TCPTABLE_OWNER_PID_DWORDS = DllStructCreate("dword[" & Ceiling($iSize / 4) & "]", DllStructGetPtr($tByteStructure))
Local $iTCPentries = DllStructGetData($tMIB_TCPTABLE_OWNER_PID_DWORDS, 1)
Local $aConnections[$iTCPentries][3] ; PID_Name | PID_Number | Connection_state
Local $aState[12] = ["CLOSED", "LISTENING", "SYN_SENT", "SYN_RCVD", "ESTABLISHED", "FIN_WAIT1", "FIN_WAIT2", "CLOSE_WAIT", "CLOSING", "LAST_ACK", "TIME_WAIT", "DELETE_TCB"]
Local $aProcessList = ProcessList()
;_ArrayDisplay($aProcesses)
Local $iOffset
Local $iIP
Local $sIP = ""
Local $iPort_LOCAL = 0
TCPStartup()
Local $iArrayElement = 0
For $i = 1 To $iTCPentries
$iOffset = ($i - 1) * 6 + 1 ; going thru array of dwords
If DllStructGetData($tMIB_TCPTABLE_OWNER_PID_DWORDS, 1, $iOffset + 1) < 3 Then
; ignore generic connections
ContinueLoop
Else
$iIP = DllStructGetData($tMIB_TCPTABLE_OWNER_PID_DWORDS, 1, $iOffset + 4)
$sIP = BitOR(BinaryMid($iIP, 1, 1), 0) & "." & BitOR(BinaryMid($iIP, 2, 1), 0) & "." & BitOR(BinaryMid($iIP, 3, 1), 0) & "." & BitOR(BinaryMid($iIP, 4, 1), 0)
If $sIP <> $sRemoteIP Then
ContinueLoop
Else ; this is the remote IP that we want to monitor
$iPort_LOCAL = Dec(Hex(BinaryMid(DllStructGetData($tMIB_TCPTABLE_OWNER_PID_DWORDS, 1, $iOffset + 5), 1, 2)))
If $iPort_LOCAL == $iRemotePort Then ; this is the intended port that we want to monitor
;ConsoleWrite("!!!!! found ip and port" & @CRLF)
$aConnections[$iArrayElement][2] = $aState[DllStructGetData($tMIB_TCPTABLE_OWNER_PID_DWORDS, 1, $iOffset + 1) - 1] ; Connection state
$aConnections[$iArrayElement][1] = DllStructGetData($tMIB_TCPTABLE_OWNER_PID_DWORDS, 1, $iOffset + 6) ; PID_Number
For $j = 1 To $aProcessList[0][0]
If $aProcessList[$j][1] == $aConnections[$iArrayElement][1] Then
$aConnections[$iArrayElement][0] = $aProcessList[$j][0]
ExitLoop
EndIf
Next
If $aConnections[$iArrayElement][0] <> $sPIDname Then
ContinueLoop ; ignore this connection because it's not from the intended process name.
Else
$iArrayElement += 1
EndIf
EndIf
EndIf
EndIf
Next
TCPShutdown()
_ArrayDelete($aConnections, $iArrayElement & "-" & UBound($aConnections)-1)
Return $aConnections
EndFunc ;==>_CV_GetExtendedTcpTable
Func __Send_Show()
__Log("Showing Media")
Local $hWinHandle = WinGetHandle($sWinTitle,$sWinText)
SendKeepActive($hWinHandle)
Send($sSendShow)
EndFunc
Func __Send_Hide()
__Log("Hiding Media")
Local $hWinHandle = WinGetHandle($sWinTitle,$sWinText)
SendKeepActive($hWinHandle)
Send($sSendHide)
EndFunc
Func __Restart_Media()
__Send_Hide()
__Log("Ping")
While Ping($sRemoteIP,1000) == 0
ConsoleWrite("!> " & __DATETIME()&@TAB& "Ping timeout" & @CRLF)
WEnd
__Log("Port test")
TCPStartup()
While TCPConnect($sRemoteIP, $iRemotePort) < 1
ConsoleWrite("!> " & __DATETIME()&@TAB& "Can't open ip camera port "&$iRemotePort & @CRLF)
Sleep(1000)
WEnd
TCPShutdown()
__Send_Show()
EndFunc
Func __DATETIME()
Return @YEAR&"-"&@MON&"-"&@MDAY&" "&@HOUR&":"&@MIN&":"&@SEC&"."&@MSEC
EndFunc