P2P实现远程控制

     webrtc是实时音视频传输的利器,除了audio /video track的传输外还有datachannel可用于数据和信息的实时交互,在设备和浏览器间建立一个p2p通道,利用mqtt作为信令,通过对设备端rtsp服务器推流进行转换实现视频的采集,另外利用datachannel 发送浏览的监听的鼠标键盘数据给设备实现控制受控机的鼠标键盘,从而实现远程桌面控制。没事的时候自己diy一个远程控制设备,增加自己学习webrtc 和go语言的兴趣,两全其美。废话少说,直接上代码,大佬多指正

package kvm

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"
	"strconv"
	"strings"
	"sync/atomic"
	"time"

	"github.com/deepch/vdk/av"
	"github.com/deepch/vdk/codec/h264parser"
	"github.com/deepch/vdk/format/rtsp"
	webrtcdeep "github.com/deepch/vdk/format/webrtcv3"
	"github.com/pion/rtsp-bench/server/config"
	enc "github.com/pion/rtsp-bench/server/signal"
	"github.com/pion/webrtc/v3"
	"github.com/pion/webrtc/v3/pkg/media"
	"github.com/shirou/gopsutil/cpu"
)

var (
	//vers                *bool
	//help                *bool
	//conf                *string
	outboundVideoTrack  *webrtc.TrackLocalStaticSample
	peerConnectionCount int64
	CurrentKVMRTSP      RTSPInfo
	rtspsrcch           chan RTSPInfo
	rtspsrcmap          map[string]*VIDEO_SRC
	hidkeymap           map[byte]HidKeyCode
	//Version             = "v0.1.0"
	//outboundVideoTrack  *webrtc.TrackLocalStaticSample
	//peerConnectionCount int64
)

const (
	DEVICE_IP     = 100
	DEVICE_ONVIF  = 200
	DEVICE_SNMP   = 300
	DEVICE_MODBUS = 400
	DEVICE_BACNET = 500
	DEVICE_CAN    = 600
	DEVICE_UPCA   = 700
	CMDMSG_OFFER  = "offer"
	CMDMSG_DISC   = "discovery"
	CMDMSG_WAKE   = "wake"
	CMDMSG_UPDATE = "update"
	CMDMSG_MR2    = "mr2"
	//CMDMSG_OFF    = "off"

)

//https://github.com/txthinking/mr2/blob/master/README_ZH.md
//利用mr2内网映射软件做网络NAT 代理
//暴露本地局域网192.168.0.25的 ssh访问地址
//$ mr2 client -s 1.2.3.4:9999 -p password -P 8888 -c 192.168.0.25:22
//ssh -oPort=8888 yourlocaluser@1.2.3.4 按此进行内网192.168.0.25的ssh服务进行连接访问
//$ mr2 client -s 1.2.3.4:9999 -p password -P 8888 --clientDirectory /path/to/www --clientPort 8080
//现在访问 1.2.3.4:8888 就等于 127.0.0.1:8080, web root 是 /path/to/www
type Mr2Msg struct {
	ServerAddr string //运行mr2服务器的地址  1.2.3.4:9000
	Password   string //连接的密码
	ExposePort int    //映射的端口 8888
	ExposeAddr string //需要映射的局域网内的地址和端口 192.168.0.25:8888
}
type MAC struct {
	Host string
	Mac  string
}
type ResponseMsg struct {
	Cmdstr string
	Status int
	Err    string
	Sid    string
}
type versionUpdate struct {
	ForceUpdate int    `json:"forceupdate"` // 是否需要强制更新 0是否 1是需要
	Version     string `json:"version"`     // 版本号字符串
	DownLoadUrl string `json:"downloadurl"` // 下载地址
	VersionDesc string `json:"versiondesc"` // 更新描述
}
type DiscoveryCmd struct {
	DevType int `json:"DevType"`
}
type Session struct {
	Type     string `json:"type"`
	Msg      string `json:"msg"`
	Data     string `json:"data"`
	DeviceId string `json:"device_id"`
}
type PublishMsg struct {
	Topic string
	Msg   interface{}
}

// Message
type Message struct {
	SeqID               uint64                    `json:"seqid"`
	Video               bool                      `json:"video"`
	Serial              bool                      `json:"serial"`
	SSH                 bool                      `json:"ssh"`
	IceServer           []string                  `json:"iceserver"`
	RtcSession          webrtc.SessionDescription `json:"offer" mapstructure:"offer"`
	VideoRtspServerAddr string                    `json:"rtspaddr"`
	Suuid               string                    `json:"suuid"` //视频流编号,浏览器可以通过预先获取,然后在使用时带过来,主要是提供一个选择分辨率和地址的作用,kvm的话内置4路分辨率,其余的如果是Onvif IPC类则通过Onvif协议在本地获取后通过mqtt传给浏览器,也可以考虑用探测软件实现探测后直接注册到夜莺平台,需要时前端到夜莺平台取
}

type VIDEO_SRC struct {
	Name           string
	RtspServerAddr string
	Resolution     string
	Track          *webrtc.TrackLocalStaticSample
	BInUse         bool
}
type RTSPInfo struct {
	Suuid string
	URL   string
}
type MouseData struct {
	IsLeft   int `json:"isLeft"`
	IsMiddle int `json:"isMiddle"`
	IsRight  int `json:"isRight"`
	IsDown   int `json:"isDown"`
	X        int `json:"x"`
	Y        int `json:"y"`
	Width    int `json:"width"`
	Height   int `json:"height"`
}
type KeyData struct {
	FuncKey byte `json:"funcKey"`
	KeyCode byte `json:"keyCode"`
}
type HIDData struct {
	Type string      `json:"type"`
	Data interface{} `json:"data"`
}
type HidKeyCode struct {
	KeyCode byte
	Shift   bool
}

// Encode encodes the input in base64
// It can optionally zip the input before encoding
const (
	EVENT_MOUSE     = "MOUSE"
	EVENT_MOUSEUP   = "MOUSEUP"
	EVENT_MOUSEDOWN = "MOUSEDOWN"
	EVENT_KEYDOWN   = "KEYDOWN"
	EVENT_MOUSEMOVE = "MOUSEMOVE"
)

//https://blog.csdn.net/weixin_33905756/article/details/94002203
//https://blog.csdn.net/weixin_33905756/article/details/94002203
func init() {
	/*
		#define Keyboard_a                4   // Keyboard a and A
		#define Keyboard_b                5   // Keyboard b and B
		#define Keyboard_c                6   // Keyboard c and C
		#define Keyboard_d                7   // Keyboard d and D
		#define Keyboard_e                8   // Keyboard e and E
		#define Keyboard_f                9   // Keyboard f and F
		#define Keyboard_g                10  // Keyboard g and G
		#define Keyboard_h                11  // Keyboard h and H
		#define Keyboard_i                12  // Keyboard i and I
		#define Keyboard_j                13  // Keyboard j and J
		#define Keyboard_k                14  // Keyboard k and K
		#define Keyboard_l                15  // Keyboard l and L
		#define Keyboard_m                16  // Keyboard m and M
		#define Keyboard_n                17  // Keyboard n and N
		#define Keyboard_o                18  // Keyboard o and O
		#define Keyboard_p                19  // Keyboard p and P
		#define Keyboard_q                20  // Keyboard q and Q
		#define Keyboard_r                21  // Keyboard r and R
		#define Keyboard_s                22  // Keyboard s and S
		#define Keyboard_t                23  // Keyboard t and T
		#define Keyboard_u                24  // Keyboard u and U
		#define Keyboard_v                25  // Keyboard v and V
		#define Keyboard_w                26  // Keyboard w and W
		#define Keyboard_x                27  // Keyboard x and X
		#define Keyboard_y                28  // Keyboard y and Y
		#define Keyboard_z                29  // Keyboard z and Z
		#define Keyboard_1                30  // Keyboard 1 and !
		#define Keyboard_2                31  // Keyboard 2 and @
		#define Keyboard_3                32  // Keyboard 3 and #
		#define Keyboard_4                33  // Keyboard 4 and $
		#define Keyboard_5                34  // Keyboard 5 and %
		#define Keyboard_6                35  // Keyboard 6 and ^
		#define Keyboard_7                36  // Keyboard 7 and &
		#define Keyboard_8                37  // Keyboard 8 and *
		#define Keyboard_9                38  // Keyboard 9 and (
		#define Keyboard_0                39  // Keyboard 0 and )
		#define Keyboard_ENTER            40  // Keyboard ENTER
		#define Keyboard_ESCAPE           41  // Keyboard ESCAPE
		#define Keyboard_Backspace        42  // Keyboard Backspace
		#define Keyboard_Tab              43  // Keyboard Tab
		#define Keyboard_KongGe           44  // Keyboard Spacebar
		#define Keyboard_JianHao          45  // Keyboard - and _(underscore)
		#define Keyboard_DengHao          46  // Keyboard = and +
		#define Keyboard_ZuoZhongKuoHao   47  // Keyboard [ and {
		#define Keyboard_YouZhongKuoHao   48  // Keyboard ] and }
		#define Keyboard_FanXieGang       49  // Keyboard \ and |
		#define Keyboard_FenHao           51  // Keyboard ; and :
		#define Keyboard_DanYinHao        52  // Keyboard ‘ and “
		#define Keyboard_BoLangXian       53  // Keyboard `(Grave Accent) and ~(Tilde)
		#define Keyboard_Douhao           54  // Keyboard, and <
		#define Keyboard_JuHao            55  // Keyboard . and >
		#define Keyboard_XieGang_WenHao   56  // Keyboard / and ?
		#define Keyboard_CapsLock         57  // Keyboard Caps Lock
		#define Keyboard_F1               58  // Keyboard F1
		#define Keyboard_F2               59  // Keyboard F2
		#define Keyboard_F3               60  // Keyboard F3
		#define Keyboard_F4               61  // Keyboard F4
		#define Keyboard_F5               62  // Keyboard F5
		#define Keyboard_F6               63  // Keyboard F6
		#define Keyboard_F7               64  // Keyboard F7
		#define Keyboard_F8               65  // Keyboard F8
		#define Keyboard_F9               66  // Keyboard F9
		#define Keyboard_F10              67  // Keyboard F10
		#define Keyboard_F11              68  // Keyboard F11
		#define Keyboard_F12              69  // Keyboard F12
		#define Keyboard_PrintScreen      70  // Keyboard PrintScreen
		#define Keyboard_ScrollLock       71  // Keyboard Scroll Lock
		#define Keyboard_Pause            72  // Keyboard Pause
		#define Keyboard_Insert           73  // Keyboard Insert
		#define Keyboard_Home             74  // Keyboard Home
		#define Keyboard_PageUp           75  // Keyboard PageUp
		#define Keyboard_Delete           76  // Keyboard Delete
		#define Keyboard_End              77  // Keyboard End
		#define Keyboard_PageDown         78  // Keyboard PageDown
		#define Keyboard_RightArrow       79  // Keyboard RightArrow
		#define Keyboard_LeftArrow        80  // Keyboard LeftArrow
		#define Keyboard_DownArrow        81  // Keyboard DownArrow
		#define Keyboard_UpArrow          82  // Keyboard UpArrow
		#define Keypad_NumLock            83  // Keypad Num Lock and Clear
		#define Keypad_ChuHao             84  // Keypad /
		#define Keypad_ChengHao           85  // Keypad *
		#define Keypad_JianHao            86  // Keypad -
		#define Keypad_JiaHao             87  // Keypad +
		#define Keypad_ENTER              88  // Keypad ENTER
		#define Keypad_1_and_End          89  // Keypad 1 and End
		#define Keypad_2_and_DownArrow    90  // Keypad 2 and Down Arrow
		#define Keypad_3_and_PageDn       91  // Keypad 3 and PageDn
		#define Keypad_4_and_LeftArrow    92  // Keypad 4 and Left Arrow
		#define Keypad_5                  93  // Keypad 5
		#define Keypad_6_and_RightArrow   94  // Keypad 6 and Right Arrow
		#define Keypad_7_and_Home         95  // Keypad 7 and Home
		#define Keypad_8_and_UpArrow      96  // Keypad 8 and Up Arrow
		#define Keypad_9_and_PageUp       97  // Keypad 9 and PageUp
		#define Keypad_0_and_Insert       98  // Keypad 0 and Insert
		#define Keypad_Dian_and_Delete    99  // Keypad . and Delete
		#define Keyboard_Application      101 // Keyboard Application
		#define Keyboard_LeftControl      224
		#define Keyboard_LeftShift        225
		#define Keyboard_LeftAlt          226
		#define Keyboard_LeftWindows      227
		#define Keyboard_RightControl     228
		#define Keyboard_RightShift       229
		#define Keyboard_RightAlt         230
		#define Keyboard_RightWindows     231
	*/
	hidkeymap = make(map[byte]HidKeyCode)
	//hidkeymap['POSTFail'] = 0x02
	//hidkeymap['ErrorUndefined'] = 0x03
	hidkeymap[65] = HidKeyCode{0x04, false} //a
	//hidkeymap['A'] = HidKeyCode{0x04, true} //b
	hidkeymap[66] = HidKeyCode{0x05, false}
	//hidkeymap['B'] = HidKeyCode{0x05, true}
	hidkeymap[67] = HidKeyCode{0x06, false}
	//hidkeymap['C'] = HidKeyCode{0x06, true}
	hidkeymap[68] = HidKeyCode{0x07, false}
	//hidkeymap['D'] = HidKeyCode{0x07, true}
	hidkeymap[69] = HidKeyCode{0x08, false}
	//hidkeymap['E'] = HidKeyCode{0x08, true}
	hidkeymap[70] = HidKeyCode{0x09, false}
	//hidkeymap['F'] = HidKeyCode{0x09, true}
	hidkeymap[71] = HidKeyCode{0x0A, false}
	//hidkeymap['G'] = HidKeyCode{0x0A, true}
	hidkeymap[72] = HidKeyCode{0x0B, false}
	//hidkeymap['H'] = HidKeyCode{0x0B, true}
	hidkeymap[73] = HidKeyCode{0x0C, false}
	//hidkeymap['I'] = HidKeyCode{0x0C, true}
	hidkeymap[74] = HidKeyCode{0x0D, false}
	//hidkeymap['J'] = HidKeyCode{0x0D, true}
	hidkeymap[75] = HidKeyCode{0x0E, false}
	//hidkeymap['K'] = HidKeyCode{0x0E, true}
	hidkeymap[76] = HidKeyCode{0x0F, false}
	//hidkeymap['L'] = HidKeyCode{0x0F, true}
	hidkeymap[77] = HidKeyCode{0x10, false}
	//hidkeymap['M'] = HidKeyCode{0x10, true}
	hidkeymap[78] = HidKeyCode{0x11, false}
	//hidkeymap['N'] = HidKeyCode{0x11, true}
	hidkeymap[79] = HidKeyCode{0x12, false}
	//hidkeymap['O'] = HidKeyCode{0x12, true}
	hidkeymap[80] = HidKeyCode{0x13, false}
	//hidkeymap['P'] = HidKeyCode{0x13, true}
	hidkeymap[81] = HidKeyCode{0x14, false}
	//hidkeymap['Q'] = HidKeyCode{0x14, true}
	hidkeymap[82] = HidKeyCode{0x15, false}
	//hidkeymap['R'] = HidKeyCode{0x15, true}
	hidkeymap[83] = HidKeyCode{0x16, false}
	//hidkeymap['S'] = HidKeyCode{0x16, true}
	hidkeymap[84] = HidKeyCode{0x17, false}
	//hidkeymap['T'] = HidKeyCode{0x17, true}
	hidkeymap[85] = HidKeyCode{0x18, false}
	//hidkeymap['U'] = HidKeyCode{0x18, true}
	hidkeymap[86] = HidKeyCode{0x19, false}
	//hidkeymap['V'] = HidKeyCode{0x19, true}
	hidkeymap[87] = HidKeyCode{0x1A, false}
	//hidkeymap['W'] = HidKeyCode{0x1A, true}
	hidkeymap[88] = HidKeyCode{0x1B, false}
	//hidkeymap['X'] = HidKeyCode{0x1B, true}
	hidkeymap[89] = HidKeyCode{0x1C, false}
	//hidkeymap['Y'] = HidKeyCode{0x1C, true}
	hidkeymap[90] = HidKeyCode{0x1D, false}
	//hidkeymap['Z'] = HidKeyCode{0x1D, true}
	hidkeymap['1'] = HidKeyCode{0x1E, false}
	//hidkeymap['!'] = HidKeyCode{0x1E, true}
	hidkeymap['2'] = HidKeyCode{0x1F, false}
	//hidkeymap['@'] = HidKeyCode{0x1F, true}
	hidkeymap['3'] = HidKeyCode{0x20, false}
	//hidkeymap['#'] = HidKeyCode{0x20, true}
	hidkeymap['4'] = HidKeyCode{0x21, false}
	//hidkeymap['#'] = HidKeyCode{0x21, true}
	hidkeymap['5'] = HidKeyCode{0x22, false}
	//hidkeymap['%'] = HidKeyCode{0x22, true}
	hidkeymap['6'] = HidKeyCode{0x23, false}
	//hidkeymap['^'] = HidKeyCode{0x23, true}
	hidkeymap['7'] = HidKeyCode{0x24, false}
	//hidkeymap['&'] = HidKeyCode{0x24, true}
	hidkeymap['8'] = HidKeyCode{0x25, false}
	//hidkeymap['*'] = HidKeyCode{0x25, true}
	hidkeymap['9'] = HidKeyCode{0x26, false}
	//hidkeymap['('] = HidKeyCode{0x26, true}
	hidkeymap['0'] = HidKeyCode{0x27, false}
	//hidkeymap[')'] = HidKeyCode{0x27, true}

	hidkeymap['\r'] = HidKeyCode{0x28, false}
	hidkeymap[27] = HidKeyCode{0x29, false} //"ESC"
	hidkeymap[8] = HidKeyCode{0x2A, false}  //'DELETE (Backspace)'
	hidkeymap[9] = HidKeyCode{0x2B, false}  //'Tab'
	hidkeymap[' '] = HidKeyCode{0x2C, false}
	hidkeymap[189] = HidKeyCode{0x2D, false}
	//	hidkeymap['(underscore)'] = HidKeyCode{0x2D,false}
	hidkeymap[187] = HidKeyCode{0x2E, false}
	//hidkeymap['+'] = HidKeyCode{0x2E, true}
	hidkeymap[219] = HidKeyCode{0x2F, false}
	//hidkeymap['{'] = HidKeyCode{0x2F, true}
	hidkeymap[221] = HidKeyCode{0x30, false}
	//hidkeymap['}'] = HidKeyCode{0x30, true}
	hidkeymap[220] = HidKeyCode{0x31, false} //'\'
	//hidkeymap['|'] = HidKeyCode{0x31, true}
	//hidkeymap['Non-US #'] = HidKeyCode{0x32,false}
	hidkeymap[192] = HidKeyCode{0x32, false}
	hidkeymap[186] = HidKeyCode{0x33, false}
	//hidkeymap[':'] = HidKeyCode{0x33, true}
	hidkeymap[222] = HidKeyCode{0x34, false}
	//hidkeymap[222] = HidKeyCode{0x34, true} //"\""
	//	hidkeymap['Grave Accent'] = HidKeyCode{0x35,false}
	//	hidkeymap['Tilde'] = HidKeyCode{0x35,false}
	//	hidkeymap['Keyboard,'] = HidKeyCode{0x36,false}
	hidkeymap[188] = HidKeyCode{0x36, false}
	//hidkeymap['<'] = HidKeyCode{0x36, true}
	hidkeymap[190] = HidKeyCode{0x37, false}
	//hidkeymap['>'] = HidKeyCode{0x37, true}
	hidkeymap[191] = HidKeyCode{0x38, false}
	//hidkeymap['?'] = HidKeyCode{0x38, true}
	hidkeymap[20] = HidKeyCode{0x39, false}  //backspace
	hidkeymap[39] = HidKeyCode{0x4F, false}  //right arrow
	hidkeymap[37] = HidKeyCode{0x50, false}  //left arrow
	hidkeymap[40] = HidKeyCode{0x51, false}  //down arrow
	hidkeymap[38] = HidKeyCode{0x52, false}  //up arrow
	hidkeymap[112] = HidKeyCode{0x3A, false} //f1
	hidkeymap[113] = HidKeyCode{0x3B, false} //f2
	hidkeymap[114] = HidKeyCode{0x3C, false}
	hidkeymap[115] = HidKeyCode{0x3D, false}
	hidkeymap[116] = HidKeyCode{0x3E, false}
	hidkeymap[117] = HidKeyCode{0x3F, false}
	hidkeymap[118] = HidKeyCode{0x40, false}
	hidkeymap[119] = HidKeyCode{0x41, false}
	hidkeymap[120] = HidKeyCode{0x42, false}
	hidkeymap[121] = HidKeyCode{0x43, false}
	hidkeymap[122] = HidKeyCode{0x44, false}
	hidkeymap[123] = HidKeyCode{0x45, false} //f12
	hidkeymap[19] = HidKeyCode{0x48, false}  //pause
	hidkeymap[46] = HidKeyCode{0x49, false}  //Insert
	/*
		hidkeymap['F1'] = HidKeyCode{0x3A
		hidkeymap['F2'] = HidKeyCode{0x3B
		hidkeymap['F3'] = HidKeyCode{0x3C
		hidkeymap['F4'] = HidKeyCode{0x3D
		hidkeymap['F5'] = HidKeyCode{0x3E
		hidkeymap['F6'] = HidKeyCode{0x3F
		hidkeymap['F7'] = HidKeyCode{0x40
		hidkeymap['F8'] = HidKeyCode{0x41
		hidkeymap['F9'] = HidKeyCode{0x42
		hidkeymap['F10'] = HidKeyCode{0x43
		hidkeymap['F11'] = HidKeyCode{0x44
		hidkeymap['F12'] = HidKeyCode{0x45
		hidkeymap['PrintScreen'] = HidKeyCode{0x46
		hidkeymap['Scroll Lock'] = HidKeyCode{0x47
		hidkeymap['Pause'] = HidKeyCode{0x48
		hidkeymap['Insert'] = HidKeyCode{0x49
		hidkeymap['Home'] = HidKeyCode{0x4A
		hidkeymap['PageUp'] = HidKeyCode{0x4B
		hidkeymap['Delete Forward'] = HidKeyCode{0x4C
		hidkeymap['End'] = HidKeyCode{0x4D
		hidkeymap['PageDown'] = HidKeyCode{0x4E
		hidkeymap['RightArrow'] = HidKeyCode{x4F
		hidkeymap['LeftArrow'] = HidKeyCode{0x50
		hidkeymap['DownArrow'] = HidKeyCode{0x51
		hidkeymap['UpArrow'] = HidKeyCode{0x52
		hidkeymap['Num Lock'] = HidKeyCode{0x53
		hidkeymap['Clear'] = HidKeyCode{0x53
		hidkeymap['/'] = HidKeyCode{0x54
		hidkeymap['*'] = HidKeyCode{0x55
		hidkeymap['-'] = HidKeyCode{0x56
		hidkeymap['+'] = HidKeyCode{0x57
		hidkeymap['ENTER'] = HidKeyCode{0x58
		hidkeymap['1'] = HidKeyCode{0x59
		hidkeymap['Down Arrow'] = HidKeyCode{0x5A
		hidkeymap['2'] = HidKeyCode{0x5A
		hidkeymap['PageDn'] = HidKeyCode{0x5B
		hidkeymap['3'] = HidKeyCode{0x5B
		hidkeymap['Left Arrow'] = HidKeyCode{0x5C
		hidkeymap['4'] = HidKeyCode{0x5C
		hidkeymap['5'] = HidKeyCode{0x5D
		hidkeymap['Right Arrow'] = HidKeyCode{0x5E
		hidkeymap['6'] = HidKeyCode{0x5E
		hidkeymap['Home'] = HidKeyCode{0x5F
		hidkeymap['7'] = HidKeyCode{0x5F
		hidkeymap['Up Arrow'] = HidKeyCode{0x60
		hidkeymap['8'] = HidKeyCode{0x60
		hidkeymap['PageUp'] = HidKeyCode{0x61
		hidkeymap['9'] = HidKeyCode{0x61
		hidkeymap['Insert'] = HidKeyCode{0x62
		hidkeymap['0'] = HidKeyCode{0x62
		hidkeymap['.'] = HidKeyCode{0x63
		hidkeymap['Delete'] = HidKeyCode{0x63
		hidkeymap['Non-US \\'] = HidKeyCode{0x64
		hidkeymap['|'] = HidKeyCode{0x64
		hidkeymap['Application'] = HidKeyCode{0x65
		hidkeymap['Power'] = HidKeyCode{0x66
		hidkeymap['='] = HidKeyCode{0x67
		hidkeymap['F13'] = HidKeyCode{0x68
		hidkeymap['F14'] = HidKeyCode{0x69
		hidkeymap['F15'] = HidKeyCode{0x6A
		hidkeymap['F16'] = HidKeyCode{0x6B
		hidkeymap['F17'] = HidKeyCode{0x6C
		hidkeymap['F18'] = HidKeyCode{0x6D
		hidkeymap['F19'] = HidKeyCode{0x6E
		hidkeymap['F21'] = HidKeyCode{0x6F
		hidkeymap['F22'] = HidKeyCode{0x70
		hidkeymap['F23'] = HidKeyCode{0x71
		hidkeymap['F24'] = HidKeyCode{0x72
		hidkeymap['F18'] = HidKeyCode{0x73
		hidkeymap['Execute'] = HidKeyCode{0x74
		hidkeymap['Help'] = HidKeyCode{0x75
		hidkeymap['Menu'] = HidKeyCode{0x76
		hidkeymap['Select'] = HidKeyCode{0x77
		hidkeymap['Stop'] = HidKeyCode{0x78
		hidkeymap['Again'] = HidKeyCode{0x79
		hidkeymap['Undo'] = HidKeyCode{0x7A
		hidkeymap['Cut'] = HidKeyCode{0x7B
		hidkeymap['Copy'] = HidKeyCode{0x7C
		hidkeymap['Paste'] = HidKeyCode{0x7D
		hidkeymap['Find'] = HidKeyCode{0x7E
		hidkeymap['Mute'] = HidKeyCode{0x7F
		hidkeymap['Volume Up'] = HidKeyCode{0x80
		hidkeymap['Volume Down'] = HidKeyCode{0x81
		hidkeymap['Locking Caps Lock'] = HidKeyCode{0x82
		hidkeymap['Locking Num Lock'] = HidKeyCode{0x83
		hidkeymap['Locking Scroll Lock'] = HidKeyCode{0x84
		hidkeymap['Comma'] = HidKeyCode{0x85
		hidkeymap['Equal Sign'] = HidKeyCode{0x86
		hidkeymap['International1'] = HidKeyCode{0x87
		hidkeymap['International2'] = HidKeyCode{0x88
		hidkeymap['International3'] = HidKeyCode{0x89
		hidkeymap['International4'] = HidKeyCode{0x8A
		hidkeymap['International5'] = HidKeyCode{0x8B
		hidkeymap['International6'] = HidKeyCode{0x8C
		hidkeymap['International7'] = HidKeyCode{0x8D
		hidkeymap['International8'] = HidKeyCode{0x8E
		hidkeymap['International9'] = HidKeyCode{0x8F
		hidkeymap['LANG1'] = HidKeyCode{0x90
		hidkeymap['LANG2'] = HidKeyCode{0x91
		hidkeymap['LANG3'] = HidKeyCode{0x92
		hidkeymap['LANG4'] = HidKeyCode{0x93
		hidkeymap['LANG5'] = HidKeyCode{0x94
		hidkeymap['LANG6'] = HidKeyCode{0x95
		hidkeymap['LANG7'] = HidKeyCode{0x96
		hidkeymap['LANG8'] = HidKeyCode{0x97
		hidkeymap['LANG9'] = HidKeyCode{0x98
		hidkeymap['Alternate Erase'] = HidKeyCode{0x99
		hidkeymap['SysReq/Attention'] = HidKeyCode{0x9A
		hidkeymap['Cancel'] = HidKeyCode{0x9B
		hidkeymap['Clear'] = HidKeyCode{0x9C
		hidkeymap['Prior'] = HidKeyCode{0x9D
		hidkeymap['Return'] = HidKeyCode{0x9E
		hidkeymap['Separator'] = HidKeyCode{0x9F
		hidkeymap['Out'] = HidKeyCode{0xA0
		hidkeymap['Oper'] = HidKeyCode{0xA1
		hidkeymap['Clear/Again'] = HidKeyCode{0xA2
		hidkeymap['CrSel/Props'] = HidKeyCode{0xA3
		hidkeymap['ExSel'] = HidKeyCode{0xA4
		hidkeymap['LeftControl'] = HidKeyCode{0xE0
		hidkeymap['LeftShift'] = HidKeyCode{0xE1
		hidkeymap['LeftAlt'] = HidKeyCode{0xE2
		hidkeymap['Left GUI'] = HidKeyCode{0xE3
		hidkeymap['RightControl'] = HidKeyCode{0xE4
		hidkeymap['RightShift'] = HidKeyCode{0xE5
		hidkeymap['RightAlt'] = HidKeyCode{0xE6
		hidkeymap['Right GUI'] = HidKeyCode{0xE7
	*/
}

// Generate CSV with columns of timestamp, peerConnectionCount, and cpuUsage
func reportBuilder() {
	file, err := os.OpenFile("report.csv", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
	if err != nil {
		panic(err)
	}

	if _, err := file.WriteString("timestamp, peerConnectionCount, cpuUsage\n"); err != nil {
		panic(err)
	}

	for range time.NewTicker(3 * time.Second).C {
		usage, err := cpu.Percent(0, false)
		if err != nil {
			panic(err)
		} else if len(usage) != 1 {
			panic(fmt.Sprintf("CPU Usage results should have 1 sample, have %d", len(usage)))
		}
		if _, err = file.WriteString(fmt.Sprintf("%s, %d, %f\n", time.Now().Format(time.RFC3339), atomic.LoadInt64(&peerConnectionCount), usage[0])); err != nil {
			panic(err)
		}
	}
}

/*
// HTTP Handler that accepts an Offer and returns an Answer
// adds outboundVideoTrack to PeerConnection
func doSignaling(w http.ResponseWriter, r *http.Request) {
	peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{})
	if err != nil {
		panic(err)
	}
	peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
		if connectionState == webrtc.ICEConnectionStateDisconnected {
			atomic.AddInt64(&peerConnectionCount, -1)
			if err := peerConnection.Close(); err != nil {
				panic(err)
			}
		} else if connectionState == webrtc.ICEConnectionStateConnected {
			atomic.AddInt64(&peerConnectionCount, 1)
		}
	})
	if _, err = peerConnection.AddTrack(outboundVideoTrack); err != nil {
		panic(err)
	}
	var offer webrtc.SessionDescription
	if err = json.NewDecoder(r.Body).Decode(&offer); err != nil {
		panic(err)
	}
	if err = peerConnection.SetRemoteDescription(offer); err != nil {
		panic(err)
	}
	gatherCompletePromise := webrtc.GatheringCompletePromise(peerConnection)
	answer, err := peerConnection.CreateAnswer(nil)
	if err != nil {
		panic(err)
	} else if err = peerConnection.SetLocalDescription(answer); err != nil {
		panic(err)
	}
	<-gatherCompletePromise
	response, err := json.Marshal(*peerConnection.LocalDescription())
	if err != nil {
		panic(err)
	}
	w.Header().Set("Content-Type", "application/json")
	if _, err := w.Write(response); err != nil {
		panic(err)
	}
}
*/
/*
func init() {
	vers = flag.Bool("v", false, "display the version.")
	help = flag.Bool("h", false, "print this help.")
	conf = flag.String("f", "", "specify configuration file.")
	flag.Parse()
	if *vers {
		fmt.Println("version:", Version)
		os.Exit(0)
	}
	if *help {
		flag.Usage()
		os.Exit(0)
	}
}
// auto detect configuration file
func aconf() {
	if *conf != "" && file.IsExist(*conf) {
		return
	}
	*conf = "etc/kvmagent.local.yml"
	if file.IsExist(*conf) {
		return
	}
	*conf = "etc/kvmagent.yml"
	if file.IsExist(*conf) {
		return
	}
	fmt.Println("no configuration file for collector")
	os.Exit(1)
}
// parse configuration file
func pconf() {
	if err := Parse(*conf); err != nil {
		fmt.Println("cannot parse configuration file:", err)
		os.Exit(1)
	}
}
*/
func startKVMClient() {
	//uiTest()
	go StartMqtt()
	//go screen.StartScreentShot()
}

func StartKvmAgent() {
	var err error
	//aconf()
	//pconf()
	rtspsrcmap = make(map[string]*VIDEO_SRC)
	rtspsrcch = make(chan RTSPInfo)
	outboundVideoTrack, err = webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{
		MimeType: "video/h264",
	}, "pion-rtsp", "pion-rtsp")
	if err != nil {
		panic(err)
	}
	kvm1 := VIDEO_SRC{
		Name:           "KVMStream1",
		RtspServerAddr: config.Config.KVM.RTSP1ServerAddr,
		Resolution:     "1920*1080@30",
		Track:          outboundVideoTrack,
	}
	rtspsrcmap["KVMStream1"] = &kvm1
	kvm2 := VIDEO_SRC{
		Name:           "KVMStream2",
		RtspServerAddr: config.Config.KVM.RTSP2ServerAddr,
		Resolution:     "1280*720@30",
		Track:          outboundVideoTrack,
	}
	rtspsrcmap["KVMStream2"] = &kvm2
	kvm3 := VIDEO_SRC{
		Name:           "KVMStream3",
		RtspServerAddr: config.Config.KVM.RTSP3ServerAddr,
		Resolution:     "640*360@30",
		Track:          outboundVideoTrack,
	}
	rtspsrcmap["KVMStream3"] = &kvm3
	kvm4 := VIDEO_SRC{
		Name:           "KVMStream4",
		RtspServerAddr: config.Config.KVM.RTSP4ServerAddr,
		Resolution:     "640*360@30",
		Track:          outboundVideoTrack,
	}
	rtspsrcmap["KVMStream4"] = &kvm4
	go rtspConsumer()
	go HIDSerailTask()
	//HIDserialOpen()
	//go reportBuilder()
	startKVMClient()
	/*
		http.Handle("/", http.FileServer(http.Dir("./static")))
		http.HandleFunc("/doSignaling", doSignaling)
		fmt.Println("Open http://localhost:8080 to access this demo")
		panic(http.ListenAndServe(":8080", nil))
	*/
}
func SwitchSrcIndex(srcindex RTSPInfo) {
	for _, v := range rtspsrcmap {
		v.BInUse = false
	}
	//time.Sleep(time.Millisecond * 5)
	index := rtspsrcmap[srcindex.Suuid]
	if index != nil {
		//index.BInUse = true
		rtspsrcch <- srcindex
		fmt.Println("Switch to:", srcindex.Suuid, srcindex.URL)
	} else {
		scrindex := VIDEO_SRC{
			Name:           srcindex.Suuid,
			RtspServerAddr: srcindex.URL,
			Resolution:     "1920*1080@30",
			Track:          outboundVideoTrack,
			BInUse:         true,
		}
		rtspsrcmap[srcindex.Suuid] = &scrindex
		rtspsrcch <- srcindex
		fmt.Println("Add New Src&Switch to:", srcindex.Suuid, srcindex.URL)
	}
}

// The RTSP URL that will be streamed
//const rtspURL = "rtsp://170.93.143.139:1935/rtplive/0b01b57900060075004d823633235daa"
//const KVMrtspURL = "rtsp://127.0.0.1/0"

// Connect to an RTSP URL and pull media.
// Convert H264 to Annex-B, then write to outboundVideoTrack which sends to all PeerConnections
func rtspConsumer() {
	annexbNALUStartCode := func() []byte { return []byte{0x00, 0x00, 0x00, 0x01} }

	for {
		current := <-rtspsrcch

		rtspsrcmap[current.Suuid].BInUse = true
		KVMrtsp := rtspsrcmap[current.Suuid]
		//psrcIndex:=
		//KVMrtsp := rtspsrcmap["KVMStream3"]
		//if
		if KVMrtsp == nil {
			time.Sleep(time.Second * 2)
			continue
		}

		session, err := rtsp.Dial(KVMrtsp.RtspServerAddr)
		if err != nil {
			panic(err)
		}
		session.RtpKeepAliveTimeout = 10 * time.Second

		codecs, err := session.Streams()
		if err != nil {
			panic(err)
		}
		for i, t := range codecs {
			log.Println("Stream", i, "is of type", t.Type().String())
		}
		if codecs[0].Type() != av.H264 {
			panic("RTSP feed must begin with a H264 codec")
		}
		if len(codecs) != 1 {
			log.Println("Ignoring all but the first stream.")
		}

		var previousTime time.Duration
		for {
			if KVMrtsp.BInUse != true {
				break
			}
			pkt, err := session.ReadPacket()
			if err != nil {
				break
			}

			if pkt.Idx != 0 {
				//audio or other stream, skip it
				continue
			}

			pkt.Data = pkt.Data[4:]

			// For every key-frame pre-pend the SPS and PPS
			if pkt.IsKeyFrame {
				pkt.Data = append(annexbNALUStartCode(), pkt.Data...)
				pkt.Data = append(codecs[0].(h264parser.CodecData).PPS(), pkt.Data...)
				pkt.Data = append(annexbNALUStartCode(), pkt.Data...)
				pkt.Data = append(codecs[0].(h264parser.CodecData).SPS(), pkt.Data...)
				pkt.Data = append(annexbNALUStartCode(), pkt.Data...)
			}

			bufferDuration := pkt.Time - previousTime
			previousTime = pkt.Time
			if err = KVMrtsp.Track.WriteSample(media.Sample{Data: pkt.Data, Duration: bufferDuration}); err != nil && err != io.ErrClosedPipe {
				panic(err)
			}
		}

		if err = session.Close(); err != nil {
			log.Println("session Close error", err)
		}

		time.Sleep(5 * time.Second)
	}
}

func Notice(msg Message) {
	go doSignalingMqtt(msg)
	//go RTSP2StreamWebRTC(msg)
}

//"stun:stun.l.google.com:19302"
// MQTT Message Handler that accepts an Offer and returns an Answer
// adds outboundVideoTrack to PeerConnection
func doSignalingMqtt(msg Message) {
	fmt.Println("msg", msg)

	CurrentKVMRTSP.Suuid = msg.Suuid
	CurrentKVMRTSP.URL = msg.VideoRtspServerAddr
	if rtspsrcmap[msg.Suuid] == nil {
		fmt.Println(msg.Suuid, "is not exist")
		return
	}
	peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{
		ICEServers: []webrtc.ICEServer{
			{
				//URLs: []string{"stun:192.168.0.25:3478"},
				URLs: msg.IceServer,
			},
			/*
				{
					URLs:           []string{"turn:192.168.0.25:3478"},
					Username:       "xxd",
					Credential:     "xxd",
					CredentialType: webrtc.ICECredentialTypePassword,
				},
			*/
		},

		SDPSemantics: webrtc.SDPSemanticsUnifiedPlanWithFallback,
	})
	if err != nil {
		fmt.Println(err)
		return
	}

	peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
		if connectionState == webrtc.ICEConnectionStateDisconnected {
			atomic.AddInt64(&peerConnectionCount, -1)
			if err := peerConnection.Close(); err != nil {
				panic(err)
			}
		} else if connectionState == webrtc.ICEConnectionStateConnected {
			atomic.AddInt64(&peerConnectionCount, 1)
		}
	})

	if msg.Video {
		//rtspsrcch <- CurrentKVMRTSP
		SwitchSrcIndex(CurrentKVMRTSP)
		if _, err = peerConnection.AddTrack(rtspsrcmap[CurrentKVMRTSP.Suuid].Track); err != nil {
			panic(err)
		}
	}
	//if msg.SSH
	peerConnection.OnDataChannel(func(dc *webrtc.DataChannel) {
		if dc.Label() == "SSH" {
			sshDataChannelHandler(dc)
		}
		if dc.Label() == "Control" {
			controlDataChannelHandler(dc)
		}
		if dc.Label() == "Serial" {
			serialDataChannelHandler(dc)
		}
		if dc.Label() == "HID" {
			HIDDataChannelHandler(dc)
		}
	})

	var offer webrtc.SessionDescription
	offer = msg.RtcSession
	fmt.Println("offer", offer)
	if err = peerConnection.SetRemoteDescription(offer); err != nil {
		panic(err)
	}

	gatherCompletePromise := webrtc.GatheringCompletePromise(peerConnection)

	answer, err := peerConnection.CreateAnswer(nil)
	if err != nil {
		panic(err)
	} else if err = peerConnection.SetLocalDescription(answer); err != nil {
		panic(err)
	}

	<-gatherCompletePromise
	/*
		response, err := json.Marshal(answer)
		if err != nil {
			panic(err)
		}
	*/
	req := &Session{}
	req.Type = "answer"
	req.DeviceId = "kvm1"
	req.Data = enc.Encode(*peerConnection.LocalDescription())
	//data := signal.Encode(*peerConnection.LocalDescription())
	answermsg := PublishMsg{
		Topic: "answer",
		Msg:   req,
	}
	fmt.Println("answer", answermsg)
	SendMsg(answermsg) //response)
}

//"stun:stun.l.google.com:19302"
// MQTT Message Handler that accepts an Offer and returns an Answer
// adds outboundVideoTrack to PeerConnection
func doSignalingMqtt_1(msg Message) {
	//peerConnection, err := webrtc.NewPeerConnection(msg.Rtcconfig)
	fmt.Println("msg", msg)
	CurrentKVMRTSP.Suuid = msg.Suuid
	CurrentKVMRTSP.URL = msg.VideoRtspServerAddr
	if rtspsrcmap[msg.Suuid] == nil {
		fmt.Println(msg.Suuid, "is not exist")
		return
		//AddRtsptoMap(VideoRtspServerAddr)
		/*
			respmsg := PublishMsg{
				Topic: "error",
				Msg:   req,
			}
			fmt.Println("answer", answermsg)
			SendMsg(answermsg) //response)
		*/
	}
	peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{
		ICEServers: []webrtc.ICEServer{
			{
				//URLs: []string{"stun:192.168.0.25:3478"},
				URLs: msg.IceServer,
			},
			/*
				{
					URLs:           []string{"turn:192.168.0.25:3478"},
					Username:       "xxd",
					Credential:     "xxd",
					CredentialType: webrtc.ICECredentialTypePassword,
				},
			*/
		},

		SDPSemantics: webrtc.SDPSemanticsUnifiedPlanWithFallback,
	})
	if err != nil {
		fmt.Println(err)
		return
	}

	peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
		if connectionState == webrtc.ICEConnectionStateDisconnected {
			atomic.AddInt64(&peerConnectionCount, -1)
			if err := peerConnection.Close(); err != nil {
				panic(err)
			}
		} else if connectionState == webrtc.ICEConnectionStateConnected {
			atomic.AddInt64(&peerConnectionCount, 1)
		}
	})
	if msg.Video {
		SwitchSrcIndex(CurrentKVMRTSP)
		if _, err = peerConnection.AddTrack(rtspsrcmap[CurrentKVMRTSP.Suuid].Track); err != nil {
			panic(err)
		}
	}

	//if msg.SSH
	peerConnection.OnDataChannel(func(dc *webrtc.DataChannel) {
		if dc.Label() == "SSH" {
			sshDataChannelHandler(dc)
		}
		if dc.Label() == "Control" {
			controlDataChannelHandler(dc)
		}
		if dc.Label() == "Serial" {
			serialDataChannelHandler(dc)
		}
		if dc.Label() == "HID" {
			HIDDataChannelHandler(dc)
		}
	})

	var offer webrtc.SessionDescription
	offer = msg.RtcSession
	fmt.Println("ofer", offer)
	if err = peerConnection.SetRemoteDescription(offer); err != nil {
		panic(err)
	}

	gatherCompletePromise := webrtc.GatheringCompletePromise(peerConnection)

	answer, err := peerConnection.CreateAnswer(nil)
	if err != nil {
		panic(err)
	} else if err = peerConnection.SetLocalDescription(answer); err != nil {
		panic(err)
	}

	<-gatherCompletePromise
	req := &Session{}
	req.Type = "answer"
	req.DeviceId = "kvm1"
	req.Data = enc.Encode(answer)
	//data := signal.Encode(*peerConnection.LocalDescription())
	answermsg := PublishMsg{
		Topic: "answer",
		Msg:   req,
	}
	fmt.Println("answer", answermsg)
	SendMsg(answermsg) //response)
	/*
		response, err := json.Marshal(answer)
		if err != nil {
			panic(err)
		}
	*/
	/*
		answermsg := PublishMsg{
			Topic: "answer",
			Msg:   *peerConnection.LocalDescription(),
		}
		SendMsg(answermsg) //response)
	*/
}
func controlDataChannelHandler(dc *webrtc.DataChannel) {
	dc.OnOpen(func() {
		err := dc.SendText("please input command")
		if err != nil {
			fmt.Println("write data error:", err)
			dc.Close()
		}
	})
	dc.OnMessage(func(msg webrtc.DataChannelMessage) {
		result := controlHandler(msg.Data)
		dc.SendText(result)
	})
	dc.OnClose(func() {
		fmt.Printf("Close Control socket")
	})
}
func serialDataChannelHandler(dc *webrtc.DataChannel) {
	dc.OnOpen(func() {
		err := dc.SendText("please input command")
		if err != nil {
			fmt.Println("write data error:", err)
			dc.Close()
		}
	})
	dc.OnMessage(func(msg webrtc.DataChannelMessage) {
		result := serialHandler(msg.Data)
		dc.SendText(result)
	})
	dc.OnClose(func() {
		fmt.Printf("Close Control socket")
	})
}
func sshDataChannelHandler(dc *webrtc.DataChannel) {
	dc.OnOpen(func() {
		for {
			var user string
			var password string
			var addr string
			rtcin := make(chan string)
			step := make(chan string)

			dc.OnMessage(func(msg webrtc.DataChannelMessage) {
				addr = string(msg.Data)
				fmt.Println(addr)
				dc.OnMessage(func(msg webrtc.DataChannelMessage) {
					user = string(msg.Data)
					fmt.Println(user)
					dc.OnMessage(func(msg webrtc.DataChannelMessage) {
						password = string(msg.Data)
						fmt.Println(password)
						step <- ""
					})
				})
			})

			<-step
			if strings.Contains(addr, ":") != true {
				addr = fmt.Sprintf("%s:%d", config.Config.KVM.SSHHost, config.Config.KVM.SSHPort)
			}
			sshSession, err := initSSH(user, password, addr, dc, rtcin)
			if err != nil {
				dc.SendText(err.Error())
				continue
			}
			dc.OnMessage(func(msg webrtc.DataChannelMessage) {
				msg_ := string(msg.Data)

				if len(msg_) >= 10 {
					ss := strings.Fields(msg_)
					if ss[0] == "resize" {
						cols, _ := strconv.Atoi(ss[1])
						rows, _ := strconv.Atoi(ss[2])
						sshSession.WindowChange(cols, rows)
						fmt.Println(msg_)
						return
					}
				}

				rtcin <- msg_
			})
			break
		}
	})
	dc.OnClose(func() {
		fmt.Printf("Close SSH socket")
	})
}

const (
	DEVWIDTH    = 1920
	DEVHEIGHT   = 1080
	SCREENPARAM = 4096
)

//kcom3 HID 模拟模块接口
//鼠标数据 绝对坐标
//字节: byte1 byet2 byte3 byte01 byte02 byte03  byte04 byte05   byte06
//head: 0x57  0xAB  0x04           低字节在前,高字节在后
//鼠标                    按键    X轴绝对位移值   Y轴绝对位移值     滚轮(0x01-0x07 表示向上滚齿数 0x81-0xFF表)
//0x01 左键按下 0x02 右键按下 0x04 中键按下
//普通键盘数据
//0x57 0xAB 0x01 8 字节标准键盘数据
//8 字节标准键盘数据:
//BYTE1 BYTE2 BYTE3 BYTE4 BYTE5 BYTE6 BYTE7 BYTE8
//定义分别是:
/*
BYTE1 --
|--bit0: Left Control 是否按下,按下为 1
|--bit1: Left Shift 是否按下,按下为 1
|--bit2: Left Alt 是否按下,按下为 1
|--bit3: Left GUI 是否按下,按下为 1
|--bit4: Right Control 是否按下,按下为 1
|--bit5: Right Shift 是否按下,按下为 1
|--bit6: Right Alt 是否按下,按下为 1
|--bit7: Right GUI 是否按下,按下为 1
BYTE2 -- 暂不清楚,有的地方说是保留位,设置为 00 即可
BYTE3--BYTE8 -- 这六个为普通按键
*/
func HIDDataChannelHandler(dc *webrtc.DataChannel) {
	dc.OnOpen(func() {

	})
	dc.OnMessage(func(msg webrtc.DataChannelMessage) {
		var hid HIDData
		err := json.Unmarshal(msg.Data, &hid)
		if err != nil {
			return
		}
		switch hid.Type {
		case EVENT_MOUSEMOVE:
			fmt.Println("mousemove", hid.Data)
			var mouse MouseData
			json.Unmarshal([]byte(hid.Data.(string)), &mouse)
			//mouse := hid.Data.(MouseData)
			var hiddata []byte
			hiddata = append(hiddata, 0x57)
			hiddata = append(hiddata, 0xAB)
			hiddata = append(hiddata, 0x04)
			if mouse.IsDown == 1 {
				if mouse.IsLeft == 1 {
					hiddata = append(hiddata, 0x01)
				} else if mouse.IsRight == 1 {
					hiddata = append(hiddata, 0x02)
				} else if mouse.IsMiddle == 1 {
					hiddata = append(hiddata, 0x04)
				}
			} else {
				hiddata = append(hiddata, 0x00)
			}
			xx := mouse.X * DEVWIDTH / mouse.Width
			yy := mouse.Y * DEVHEIGHT / mouse.Height
			xx = xx * SCREENPARAM / DEVWIDTH
			yy = yy * SCREENPARAM / DEVHEIGHT

			hiddata = append(hiddata, uint8(xx))
			hiddata = append(hiddata, uint8(xx>>8))

			hiddata = append(hiddata, uint8(yy))
			hiddata = append(hiddata, uint8(yy>>8))

			hiddata = append(hiddata, uint8(0x00))
			fmt.Println(hiddata)
			//hidd := ]byte{0x57, 0xAB, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
			//hidd := ]byte{0x57, 0xAB, 0x04, 0x00, 0x11, 0x08, 0x68, 0x07, 0x00}
			HIDserialHandler(hiddata)
			//HIDserialHandler(hiddata)
			//json.Marshal(hid.Data.(MouseData),&mouse)
		case EVENT_MOUSEDOWN:
			fmt.Println("mousedown", hid.Data)
			var mouse MouseData
			json.Unmarshal([]byte(hid.Data.(string)), &mouse)
			//mouse := hid.Data.(MouseData)
			var hiddata []byte
			hiddata = append(hiddata, 0x57)
			hiddata = append(hiddata, 0xAB)
			hiddata = append(hiddata, 0x04)
			if mouse.IsDown == 1 {
				if mouse.IsLeft == 1 {
					hiddata = append(hiddata, 0x01)
				} else if mouse.IsRight == 1 {
					hiddata = append(hiddata, 0x02)
				} else if mouse.IsMiddle == 1 {
					hiddata = append(hiddata, 0x04)
				}
			} else {
				hiddata = append(hiddata, 0x00)
			}

			xx := mouse.X * DEVWIDTH / mouse.Width
			yy := mouse.Y * DEVHEIGHT / mouse.Height
			xx = xx * SCREENPARAM / DEVWIDTH
			yy = yy * SCREENPARAM / DEVHEIGHT

			hiddata = append(hiddata, uint8(xx))
			hiddata = append(hiddata, uint8(xx>>8))

			hiddata = append(hiddata, uint8(yy))
			hiddata = append(hiddata, uint8(yy>>8))
			hiddata = append(hiddata, 0x00)

			fmt.Println(hiddata)
			//hidd := ]byte{0x57, 0xAB, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
			//hidd := ]byte{0x57, 0xAB, 0x04, 0x00, 0x11, 0x08, 0x68, 0x07, 0x00}
			HIDserialHandler(hiddata)
			//HIDserialHandler(hiddata)
			//json.Marshal(hid.Data.(MouseData),&mouse)
		case EVENT_MOUSEUP:
			fmt.Println("mousemove", hid.Data)
			var mouse MouseData
			json.Unmarshal([]byte(hid.Data.(string)), &mouse)
			//mouse := hid.Data.(MouseData)
			var hiddata []byte
			hiddata = append(hiddata, 0x57)
			hiddata = append(hiddata, 0xAB)
			hiddata = append(hiddata, 0x04)
			hiddata = append(hiddata, 0x00)
			xx := mouse.X * DEVWIDTH / mouse.Width
			yy := mouse.Y * DEVHEIGHT / mouse.Height
			xx = xx * SCREENPARAM / DEVWIDTH
			yy = yy * SCREENPARAM / DEVHEIGHT

			hiddata = append(hiddata, uint8(xx))
			hiddata = append(hiddata, uint8(xx>>8))

			hiddata = append(hiddata, uint8(yy))
			hiddata = append(hiddata, uint8(yy>>8))
			hiddata = append(hiddata, 0x00)
			fmt.Println(hiddata)
			//hidd := ]byte{0x57, 0xAB, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
			//hidd := ]byte{0x57, 0xAB, 0x04, 0x00, 0x11, 0x08, 0x68, 0x07, 0x00}
			HIDserialHandler(hiddata)
			//HIDserialHandler(hiddata)
			//json.Marshal(hid.Data.(MouseData),&mouse)
		case EVENT_KEYDOWN:
			fmt.Println("key", hid.Data)
			//key := hid.Data.(KeyData)
			var key KeyData
			json.Unmarshal([]byte(hid.Data.(string)), &key)
			var hiddata []byte
			hiddata = append(hiddata, 0x57)
			hiddata = append(hiddata, 0xAB)
			hiddata = append(hiddata, 0x01)
			/*
				keyfunc, err := strconv.Atoi(key.FuncKey)
				if err != nil {
					return
				}
			*/

			/*keycode, err := strconv.Atoi(key.KeyCode)
			if err != nil {
				return
			}
			*/
			var keycode HidKeyCode
			switch key.KeyCode {
			case 13:
				keycode = HidKeyCode{0x28, false}
			case 8:
				keycode = HidKeyCode{0x2A, false}
			case 182:
				keycode = HidKeyCode{0x2E, false}
			default:
				keycode = hidkeymap[key.KeyCode]
			}
			if keycode.Shift {
				funckey := key.FuncKey | (1 << 1)
				hiddata = append(hiddata, byte(funckey))
			} else {
				hiddata = append(hiddata, byte(key.FuncKey))

			}
			hiddata = append(hiddata, 0x00)

			hiddata = append(hiddata, byte(keycode.KeyCode))
			hiddata = append(hiddata, 0x00)
			hiddata = append(hiddata, 0x00)
			hiddata = append(hiddata, 0x00)
			hiddata = append(hiddata, 0x00)
			hiddata = append(hiddata, 0x00)
			fmt.Println(hiddata)
			HIDserialHandler(hiddata)
			hidd := []byte{0x57, 0xAB, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
			//time.Sleep(15)
			HIDserialHandler(hidd)
		}
		//fmt.Println("HID", hid)
	})
	dc.OnClose(func() {
		fmt.Printf("Close Control socket")
	})
}

//HTTPAPIServerStreamWebRTC stream video over WebRTC
func RTSP2StreamWebRTC(msg Message) {
	if !Config.ext(msg.Suuid) {
		log.Println("Stream Not Found")
		//没找到则添加
		//return
	}
	Config.RunIFNotRun(msg.Suuid)
	codecs := Config.coGe(msg.Suuid)
	if codecs == nil {
		log.Println("Stream Codec Not Found")
		return
	}
	var AudioOnly bool
	if len(codecs) == 1 && codecs[0].Type().IsAudio() {
		AudioOnly = true
	}
	muxerWebRTC := webrtcdeep.NewMuxer(webrtcdeep.Options{ICEServers: msg.IceServer, PortMin: Config.GetWebRTCPortMin(), PortMax: Config.GetWebRTCPortMax()})
	answer, err := muxerWebRTC.WriteHeader(codecs, enc.Encode(msg.RtcSession))
	if err != nil {
		log.Println("WriteHeader", err)
		return
	}
	/*
		muxerWebRTC.OnDataChannel(func(dc *webrtc.DataChannel) {
			if dc.Label() == "SSH" {
				sshDataChannelHandler(dc)
			}
			if dc.Label() == "Control" {
				controlDataChannelHandler(dc)
			}
			if dc.Label() == "Serial" {
				serialDataChannelHandler(dc)
			}
			if dc.Label() == "HID" {
				HIDDataChannelHandler(dc)
			}
		})
	*/
	req := &Session{}
	req.Type = "answer"
	req.DeviceId = "kvm1"
	req.Data = enc.Encode(answer)
	//data := signal.Encode(*peerConnection.LocalDescription())
	answermsg := PublishMsg{
		Topic: "answer",
		Msg:   req,
	}
	fmt.Println("answer", answermsg)
	SendMsg(answermsg) //response)
	go func() {
		cid, ch := Config.clAd(msg.Suuid)
		defer Config.clDe(msg.Suuid, cid)
		defer muxerWebRTC.Close()
		var videoStart bool
		noVideo := time.NewTimer(10 * time.Second)
		for {
			select {
			case <-noVideo.C:
				log.Println("noVideo")
				return
			case pck := <-ch:
				if pck.IsKeyFrame || AudioOnly {
					noVideo.Reset(10 * time.Second)
					videoStart = true
				}
				if !videoStart && !AudioOnly {
					continue
				}
				err = muxerWebRTC.WritePacket(pck)
				if err != nil {
					log.Println("WritePacket", err)
					return
				}
			}
		}
	}()
}

629f522a572240e9afa5a1cfdeba0698.png

                                                               ubuntu系统桌面控制

b93e4c86291141498804c4a7e15424c4.png

                                                     手机对Win10桌面控制

 1ca3804c97b84f19b39a07fa1aea232f.png

                                对嵌入式设备HDMI输出信息进行远程调试

05f03a404f784c7bae56eac8259e7aab.png                                                                android系统控制

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值