package main import ( "errors" "github.com/aler9/gortsplib" "github.com/gofiber/fiber/v2" "image" "log" "net/url" "time" ) type SceneCommand struct { Scene string `json:"scene"` PushUrl string `json:"pushUrl"` CameraUrls []string `json:"cameraURls"` proc func(int64) error areaConfigs []AreaConfig `json:"-"` } type SceneData struct { State string `json:"state"` LiveUrl []string `json:"liveUrl"` } type Pointer struct { Id string `json:"id"` PercentX float32 `json:"percentX"` PercentY float32 `json:"percentY"` } type AreaConfig struct { AreaId string `json:"areaId"` PointersNum int `json:"pointersNum"` Pointers []Pointer `json:"pointers"` } type SceneReadyResponse struct { Scene string `json:"scene"` Timestamp int64 `json:"timestamp"` SceneData SceneData `json:"sceneData"` } var currentScene *SceneCommand var sceneStopChannel chan bool func validateSceneCmd(cmd SceneCommand) error { switch cmd.Scene { case "pullUp", "standJump", "sitUps": if len(cmd.CameraUrls) < 1 { return errors.New("cameraUrls can not less than 1") } case "race": if len(cmd.CameraUrls) < 2 { return errors.New("cameraUrls can not less than 2") } default: return errors.New("unknown scene type:" + cmd.Scene) } if u, e := url.Parse(cmd.PushUrl); nil != e { return errors.New("invalid pushUrl:" + e.Error()) } else if u.Scheme != "http" && u.Scheme != "https" { return errors.New("can not support pushUrl with " + u.Scheme) } return nil } func setScene(c *fiber.Ctx) error { var sceneCmd SceneCommand if err := c.BodyParser(&sceneCmd); nil != err { log.Println("ERROR:", c.Body()) return failureResponse(c, "-1", err.Error(), 200) } else if nil != currentScene { return failureResponse(c, "1", "A working scene is started", 200) } else if err = validateSceneCmd(sceneCmd); nil != err { return failureResponse(c, "2", err.Error(), 200) } else { // currentScene = &sceneCmd log.Println("Starting scene ...") log.Println(sceneCmd) if e := sceneTaskProc(&sceneCmd); nil != e { return failureResponse(c, "3", err.Error(), 200) } else { return successResponse(c, "Updated successfully.") } } } func setAreaConfig(c *fiber.Ctx) error { var cfg []AreaConfig if e := c.BodyParser(&cfg); nil != e { log.Println("ERROR:", c.Body()) return failureResponse(c, "-1", e.Error(), 200) } else if nil == currentScene { return failureResponse(c, "1", "No working scene is started", 200) } currentScene.areaConfigs = cfg return successResponse(c, "Updated successfully.") } func getAreaConfig(c *fiber.Ctx) error { if nil == currentScene { return failureResponse(c, "1", "No working scene is started", 200) } else { return successResponseData(c, "success", currentScene.areaConfigs) } } func stopScene(c *fiber.Ctx) error { if nil != testStopChannel { testStopChannel <- true } if nil != sceneStopChannel { sceneStopChannel <- true } return successResponse(c, "Updated successfully.") } func getStatus(c *fiber.Ctx) error { var scene = "" var seq int64 = 0 if nil != currentScene { scene = currentScene.Scene } if nil != currentTest { seq = currentTest.SequenceId } return successResponseEx(c, "success", scene, seq) } var capturedImage image.Image func sceneTaskProc(cmd *SceneCommand) error { var f func(int64) error = nil switch cmd.Scene { case "pullUp": f = pullUpTask case "standJump": f = standJumpTask case "sitUps": f = sitUpsTask case "race": f = raceTask default: return errors.New("unknown scene type:" + cmd.Scene) } if len(cmd.CameraUrls) < 1 { return errors.New("no camera specified") } var cc *gortsplib.Client if c, u, e := setupRtsp(cmd.CameraUrls[0]); nil != e { log.Println("setupRtsp failed:", e) } else { cc = c go func() { if e := playRtsp(c, u, func(img image.Image) { // log.Println("...capturedImage:>", img.Bounds()) capturedImage = img }); nil != e { // log.Println("playRtsp failed:>", e) } }() } sceneStopChannel = make(chan bool) var tk = time.NewTicker(time.Second * 3) go func() { defer func() { tk.Stop() close(sceneStopChannel) if nil != cc { _ = cc.Close() } sceneStopChannel = nil }() currentScene = cmd currentScene.proc = f time.Sleep(time.Second) var st = SceneReadyResponse{ Scene: cmd.Scene, Timestamp: time.Now().UnixMilli(), SceneData: SceneData{ State: "SCENE READY", LiveUrl: cmd.CameraUrls, }, } go httpPostEx(cmd.PushUrl, st, 3) for { select { case <-tk.C: // log.Println(" ...") case <-sceneStopChannel: log.Println("Scene Stopping...") go pushEvent(cmd.PushUrl, cmd.Scene, 0, "SCENE END", nil) currentScene = nil return } } }() return nil } func init() { currentScene = nil sceneStopChannel = nil }