package main import ( "context" "crypto/rand" "encoding/json" "flag" "fmt" "io" "io/ioutil" "log" "net/http" "sync" "time" "github.com/deepch/vdk/av" "github.com/deepch/vdk/codec/h264parser" "gopkg.in/yaml.v2" ) //Config global var Config = loadConfig() //ConfigST struct type ConfigST struct { mutex sync.RWMutex Server ServerST `json:"server"` Streams map[string]StreamST `json:"streams"` LastError error } //ServerST struct type ServerST struct { HTTPPort string `json:"http_port"` ICEServers []string `json:"ice_servers"` ICEUsername string `json:"ice_username"` ICECredential string `json:"ice_credential"` WebRTCPortMin uint16 `json:"webrtc_port_min"` WebRTCPortMax uint16 `json:"webrtc_port_max"` } //StreamST struct type StreamST struct { URL string `json:"url"` Status bool `json:"status"` OnDemand bool `json:"on_demand"` DisableAudio bool `json:"disable_audio"` Debug bool `json:"debug"` RunLock bool `json:"-"` Codecs []av.CodecData Cl map[string]viewer } type HttpST struct { JavaServer string `yaml:"java_server"` LocalIp string `yaml:"local_ip"` } type HttpResST struct { Code int `json:"code"` Message string `json:"message"` Data string `json:"data"` } type viewer struct { c chan av.Packet } func (element *ConfigST) RunIFNotRun(uuid string) { element.mutex.Lock() defer element.mutex.Unlock() if tmp, ok := element.Streams[uuid]; ok { if tmp.OnDemand && !tmp.RunLock { tmp.RunLock = true element.Streams[uuid] = tmp go RTSPWorkerLoop(uuid, tmp.URL, tmp.OnDemand, tmp.DisableAudio, tmp.Debug) } } } func (element *ConfigST) RunUnlock(uuid string) { element.mutex.Lock() defer element.mutex.Unlock() if tmp, ok := element.Streams[uuid]; ok { if tmp.OnDemand && tmp.RunLock { tmp.RunLock = false element.Streams[uuid] = tmp } } } func (element *ConfigST) HasViewer(uuid string) bool { element.mutex.Lock() defer element.mutex.Unlock() if tmp, ok := element.Streams[uuid]; ok && len(tmp.Cl) > 0 { return true } return false } func (element *ConfigST) GetICEServers() []string { element.mutex.Lock() defer element.mutex.Unlock() return element.Server.ICEServers } func (element *ConfigST) GetICEUsername() string { element.mutex.Lock() defer element.mutex.Unlock() return element.Server.ICEUsername } func (element *ConfigST) GetICECredential() string { element.mutex.Lock() defer element.mutex.Unlock() return element.Server.ICECredential } func (element *ConfigST) GetWebRTCPortMin() uint16 { element.mutex.Lock() defer element.mutex.Unlock() return element.Server.WebRTCPortMin } func (element *ConfigST) GetWebRTCPortMax() uint16 { element.mutex.Lock() defer element.mutex.Unlock() return element.Server.WebRTCPortMax } func loadConfig() *ConfigST { var tmp ConfigST var httpInfo HttpST yamlFile, err := ioutil.ReadFile("application.yml") if err != nil { fmt.Println(err.Error()) } //将配置文件读取到结构体中 err = yaml.Unmarshal([]byte(yamlFile), &httpInfo) if err != nil { fmt.Println(err.Error()) } fmt.Println(httpInfo) //data, err := ioutil.ReadFile("config.json") client := http.Client{} request, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "http://"+httpInfo.JavaServer+"/api/camera/rtcConfig?rtcServer="+httpInfo.LocalIp, nil) if err != nil { fmt.Println(err.Error()) } resp, err := client.Do(request) if err != nil { fmt.Println(err) } bytes, err := io.ReadAll(resp.Body) if err != nil { fmt.Println(err.Error()) } defer resp.Body.Close() fmt.Println(string(bytes)) var httpRes HttpResST err = json.Unmarshal(bytes, &httpRes) var data = httpRes.Data if err == nil { err = json.Unmarshal([]byte(data), &tmp) if err != nil { log.Fatalln(err) } for i, v := range tmp.Streams { v.Cl = make(map[string]viewer) tmp.Streams[i] = v } } else { addr := flag.String("listen", "8083", "HTTP host:port") udpMin := flag.Int("udp_min", 0, "WebRTC UDP port min") udpMax := flag.Int("udp_max", 0, "WebRTC UDP port max") iceServer := flag.String("ice_server", "", "ICE Server") flag.Parse() tmp.Server.HTTPPort = *addr tmp.Server.WebRTCPortMin = uint16(*udpMin) tmp.Server.WebRTCPortMax = uint16(*udpMax) if len(*iceServer) > 0 { tmp.Server.ICEServers = []string{*iceServer} } tmp.Streams = make(map[string]StreamST) } return &tmp } func (element *ConfigST) cast(uuid string, pck av.Packet) { element.mutex.Lock() defer element.mutex.Unlock() for _, v := range element.Streams[uuid].Cl { if len(v.c) < cap(v.c) { v.c <- pck } } } func (element *ConfigST) ext(suuid string) bool { element.mutex.Lock() defer element.mutex.Unlock() _, ok := element.Streams[suuid] return ok } func (element *ConfigST) coAd(suuid string, codecs []av.CodecData) { element.mutex.Lock() defer element.mutex.Unlock() t := element.Streams[suuid] t.Codecs = codecs element.Streams[suuid] = t } func (element *ConfigST) coGe(suuid string) []av.CodecData { for i := 0; i < 100; i++ { element.mutex.RLock() tmp, ok := element.Streams[suuid] element.mutex.RUnlock() if !ok { return nil } if tmp.Codecs != nil { //TODO Delete test for _, codec := range tmp.Codecs { if codec.Type() == av.H264 { codecVideo := codec.(h264parser.CodecData) if codecVideo.SPS() != nil && codecVideo.PPS() != nil && len(codecVideo.SPS()) > 0 && len(codecVideo.PPS()) > 0 { //ok //log.Println("Ok Video Ready to play") } else { //video codec not ok log.Println("Bad Video Codec SPS or PPS Wait") time.Sleep(50 * time.Millisecond) continue } } } return tmp.Codecs } time.Sleep(50 * time.Millisecond) } return nil } func (element *ConfigST) clAd(suuid string) (string, chan av.Packet) { element.mutex.Lock() defer element.mutex.Unlock() cuuid := pseudoUUID() ch := make(chan av.Packet, 100) element.Streams[suuid].Cl[cuuid] = viewer{c: ch} return cuuid, ch } func (element *ConfigST) list() (string, []string) { element.mutex.Lock() defer element.mutex.Unlock() var res []string var fist string for k := range element.Streams { if fist == "" { fist = k } res = append(res, k) } return fist, res } func (element *ConfigST) clDe(suuid, cuuid string) { element.mutex.Lock() defer element.mutex.Unlock() delete(element.Streams[suuid].Cl, cuuid) } func pseudoUUID() (uuid string) { b := make([]byte, 16) _, err := rand.Read(b) if err != nil { fmt.Println("Error: ", err) return } uuid = fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) return }