channel.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. package gb28181
  2. import (
  3. "fmt"
  4. "net/http"
  5. "strconv"
  6. "strings"
  7. "time"
  8. "sync/atomic"
  9. "github.com/ghettovoice/gosip/sip"
  10. "github.com/goccy/go-json"
  11. "go.uber.org/zap"
  12. . "m7s.live/engine/v4"
  13. "m7s.live/engine/v4/log"
  14. "m7s.live/plugin/gb28181/v4/utils"
  15. "m7s.live/plugin/ps/v4"
  16. )
  17. var QUERY_RECORD_TIMEOUT = time.Second * 5
  18. type PullStream struct {
  19. opt *InviteOptions
  20. channel *Channel
  21. inviteRes sip.Response
  22. }
  23. func (p *PullStream) CreateRequest(method sip.RequestMethod) (req sip.Request) {
  24. res := p.inviteRes
  25. req = p.channel.CreateRequst(method)
  26. from, _ := res.From()
  27. to, _ := res.To()
  28. callId, _ := res.CallID()
  29. req.ReplaceHeaders(from.Name(), []sip.Header{from})
  30. req.ReplaceHeaders(to.Name(), []sip.Header{to})
  31. req.ReplaceHeaders(callId.Name(), []sip.Header{callId})
  32. return
  33. }
  34. func (p *PullStream) Bye() int {
  35. req := p.CreateRequest(sip.BYE)
  36. resp, err := p.channel.Device.SipRequestForResponse(req)
  37. if p.opt.IsLive() {
  38. p.channel.State.Store(0)
  39. }
  40. if p.opt.recyclePort != nil {
  41. p.opt.recyclePort(p.opt.MediaPort)
  42. }
  43. if err != nil {
  44. return http.StatusInternalServerError
  45. }
  46. return int(resp.StatusCode())
  47. }
  48. func (p *PullStream) info(body string) int {
  49. d := p.channel.Device
  50. req := p.CreateRequest(sip.INFO)
  51. contentType := sip.ContentType("Application/MANSRTSP")
  52. req.AppendHeader(&contentType)
  53. req.SetBody(body, true)
  54. resp, err := d.SipRequestForResponse(req)
  55. if err != nil {
  56. log.Warnf("Send info to stream error: %v, stream=%s, body=%s", err, p.opt.StreamPath, body)
  57. return getSipRespErrorCode(err)
  58. }
  59. return int(resp.StatusCode())
  60. }
  61. // 暂停播放
  62. func (p *PullStream) Pause() int {
  63. body := fmt.Sprintf(`PAUSE RTSP/1.0
  64. CSeq: %d
  65. PauseTime: now
  66. `, p.channel.Device.SN)
  67. return p.info(body)
  68. }
  69. // 恢复播放
  70. func (p *PullStream) Resume() int {
  71. d := p.channel.Device
  72. body := fmt.Sprintf(`PLAY RTSP/1.0
  73. CSeq: %d
  74. Range: npt=now-
  75. `, d.SN)
  76. return p.info(body)
  77. }
  78. // 跳转到播放时间
  79. // second: 相对于起始点调整到第 sec 秒播放
  80. func (p *PullStream) PlayAt(second uint) int {
  81. d := p.channel.Device
  82. body := fmt.Sprintf(`PLAY RTSP/1.0
  83. CSeq: %d
  84. Range: npt=%d-
  85. `, d.SN, second)
  86. return p.info(body)
  87. }
  88. // 快进/快退播放
  89. // speed 取值: 0.25 0.5 1 2 4 或者其对应的负数表示倒放
  90. func (p *PullStream) PlayForward(speed float32) int {
  91. d := p.channel.Device
  92. body := fmt.Sprintf(`PLAY RTSP/1.0
  93. CSeq: %d
  94. Scale: %0.6f
  95. `, d.SN, speed)
  96. return p.info(body)
  97. }
  98. type Channel struct {
  99. Device *Device `json:"-" yaml:"-"` // 所属设备
  100. State atomic.Int32 `json:"-" yaml:"-"` // 通道状态,0:空闲,1:正在invite,2:正在播放/对讲
  101. LiveSubSP string // 实时子码流,通过rtsp
  102. GpsTime time.Time // gps时间
  103. Longitude string // 经度
  104. Latitude string // 纬度
  105. *log.Logger `json:"-" yaml:"-"`
  106. ChannelInfo
  107. }
  108. func (c *Channel) MarshalJSON() ([]byte, error) {
  109. m := map[string]any{
  110. "DeviceID": c.DeviceID,
  111. "ParentID": c.ParentID,
  112. "Name": c.Name,
  113. "Manufacturer": c.Manufacturer,
  114. "Model": c.Model,
  115. "Owner": c.Owner,
  116. "CivilCode": c.CivilCode,
  117. "Address": c.Address,
  118. "Port": c.Port,
  119. "Parental": c.Parental,
  120. "SafetyWay": c.SafetyWay,
  121. "RegisterWay": c.RegisterWay,
  122. "Secrecy": c.Secrecy,
  123. "Status": c.Status,
  124. "Longitude": c.Longitude,
  125. "Latitude": c.Latitude,
  126. "GpsTime": c.GpsTime,
  127. "LiveSubSP": c.LiveSubSP,
  128. "LiveStatus": c.State.Load(),
  129. }
  130. return json.Marshal(m)
  131. }
  132. // Channel 通道
  133. type ChannelInfo struct {
  134. DeviceID string // 通道ID
  135. ParentID string
  136. Name string
  137. Manufacturer string
  138. Model string
  139. Owner string
  140. CivilCode string
  141. Address string
  142. Port int
  143. Parental int
  144. SafetyWay int
  145. RegisterWay int
  146. Secrecy int
  147. Status ChannelStatus
  148. }
  149. type ChannelStatus string
  150. const (
  151. ChannelOnStatus = "ON"
  152. ChannelOffStatus = "OFF"
  153. )
  154. func (channel *Channel) CreateRequst(Method sip.RequestMethod) (req sip.Request) {
  155. d := channel.Device
  156. d.SN++
  157. callId := sip.CallID(utils.RandNumString(10))
  158. userAgent := sip.UserAgentHeader("Monibuca")
  159. maxForwards := sip.MaxForwards(70) //增加max-forwards为默认值 70
  160. cseq := sip.CSeq{
  161. SeqNo: uint32(d.SN),
  162. MethodName: Method,
  163. }
  164. port := sip.Port(conf.SipPort)
  165. serverAddr := sip.Address{
  166. //DisplayName: sip.String{Str: d.serverConfig.Serial},
  167. Uri: &sip.SipUri{
  168. FUser: sip.String{Str: conf.Serial},
  169. FHost: d.SipIP,
  170. FPort: &port,
  171. },
  172. Params: sip.NewParams().Add("tag", sip.String{Str: utils.RandNumString(9)}),
  173. }
  174. //非同一域的目标地址需要使用@host
  175. host := conf.Realm
  176. if channel.DeviceID[0:9] != host {
  177. if channel.Port != 0 {
  178. deviceIp := d.NetAddr
  179. deviceIp = deviceIp[0:strings.LastIndex(deviceIp, ":")]
  180. host = fmt.Sprintf("%s:%d", deviceIp, channel.Port)
  181. } else {
  182. host = d.NetAddr
  183. }
  184. }
  185. channelAddr := sip.Address{
  186. //DisplayName: sip.String{Str: d.serverConfig.Serial},
  187. Uri: &sip.SipUri{FUser: sip.String{Str: channel.DeviceID}, FHost: host},
  188. }
  189. req = sip.NewRequest(
  190. "",
  191. Method,
  192. channelAddr.Uri,
  193. "SIP/2.0",
  194. []sip.Header{
  195. serverAddr.AsFromHeader(),
  196. channelAddr.AsToHeader(),
  197. &callId,
  198. &userAgent,
  199. &cseq,
  200. &maxForwards,
  201. serverAddr.AsContactHeader(),
  202. },
  203. "",
  204. nil,
  205. )
  206. req.SetTransport(conf.SipNetwork)
  207. req.SetDestination(d.NetAddr)
  208. return req
  209. }
  210. func (channel *Channel) QueryRecord(startTime, endTime string) ([]*Record, error) {
  211. d := channel.Device
  212. request := d.CreateRequest(sip.MESSAGE)
  213. contentType := sip.ContentType("Application/MANSCDP+xml")
  214. request.AppendHeader(&contentType)
  215. // body := fmt.Sprintf(`<?xml version="1.0"?>
  216. // <Query>
  217. // <CmdType>RecordInfo</CmdType>
  218. // <SN>%d</SN>
  219. // <DeviceID>%s</DeviceID>
  220. // <StartTime>%s</StartTime>
  221. // <EndTime>%s</EndTime>
  222. // <Secrecy>0</Secrecy>
  223. // <Type>all</Type>
  224. // </Query>`, d.sn, channel.DeviceID, startTime, endTime)
  225. start, _ := strconv.ParseInt(startTime, 10, 0)
  226. end, _ := strconv.ParseInt(endTime, 10, 0)
  227. body := BuildRecordInfoXML(d.SN, channel.DeviceID, start, end)
  228. request.SetBody(body, true)
  229. resultCh := RecordQueryLink.WaitResult(d.ID, channel.DeviceID, d.SN, QUERY_RECORD_TIMEOUT)
  230. resp, err := d.SipRequestForResponse(request)
  231. if err != nil {
  232. return nil, fmt.Errorf("query error: %s", err)
  233. }
  234. if resp.StatusCode() != http.StatusOK {
  235. return nil, fmt.Errorf("query error, status=%d", resp.StatusCode())
  236. }
  237. // RecordQueryLink 中加了超时机制,该结果一定会返回
  238. // 所以此处不用再增加超时等保护机制
  239. r := <-resultCh
  240. return r.list, r.err
  241. }
  242. func (channel *Channel) Control(PTZCmd string) int {
  243. d := channel.Device
  244. request := d.CreateRequest(sip.MESSAGE)
  245. contentType := sip.ContentType("Application/MANSCDP+xml")
  246. request.AppendHeader(&contentType)
  247. body := fmt.Sprintf(`<?xml version="1.0"?>
  248. <Control>
  249. <CmdType>DeviceControl</CmdType>
  250. <SN>%d</SN>
  251. <DeviceID>%s</DeviceID>
  252. <PTZCmd>%s</PTZCmd>
  253. </Control>`, d.SN, channel.DeviceID, PTZCmd)
  254. request.SetBody(body, true)
  255. resp, err := d.SipRequestForResponse(request)
  256. if err != nil {
  257. return http.StatusRequestTimeout
  258. }
  259. return int(resp.StatusCode())
  260. }
  261. // Invite 发送Invite报文 invites a channel to play
  262. // 注意里面的锁保证不同时发送invite报文,该锁由channel持有
  263. /***
  264. f字段: f = v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
  265. 各项具体含义:
  266. v:后续参数为视频的参数;各参数间以 “/”分割;
  267. 编码格式:十进制整数字符串表示
  268. 1 –MPEG-4 2 –H.264 3 – SVAC 4 –3GP
  269. 分辨率:十进制整数字符串表示
  270. 1 – QCIF 2 – CIF 3 – 4CIF 4 – D1 5 –720P 6 –1080P/I
  271. 帧率:十进制整数字符串表示 0~99
  272. 码率类型:十进制整数字符串表示
  273. 1 – 固定码率(CBR) 2 – 可变码率(VBR)
  274. 码率大小:十进制整数字符串表示 0~100000(如 1表示1kbps)
  275. a:后续参数为音频的参数;各参数间以 “/”分割;
  276. 编码格式:十进制整数字符串表示
  277. 1 – G.711 2 – G.723.1 3 – G.729 4 – G.722.1
  278. 码率大小:十进制整数字符串
  279. 音频编码码率: 1 — 5.3 kbps (注:G.723.1中使用)
  280. 2 — 6.3 kbps (注:G.723.1中使用)
  281. 3 — 8 kbps (注:G.729中使用)
  282. 4 — 16 kbps (注:G.722.1中使用)
  283. 5 — 24 kbps (注:G.722.1中使用)
  284. 6 — 32 kbps (注:G.722.1中使用)
  285. 7 — 48 kbps (注:G.722.1中使用)
  286. 8 — 64 kbps(注:G.711中使用)
  287. 采样率:十进制整数字符串表示
  288. 1 — 8 kHz(注:G.711/ G.723.1/ G.729中使用)
  289. 2—14 kHz(注:G.722.1中使用)
  290. 3—16 kHz(注:G.722.1中使用)
  291. 4—32 kHz(注:G.722.1中使用)
  292. 注1:字符串说明
  293. 本节中使用的“十进制整数字符串”的含义为“0”~“4294967296” 之间的十进制数字字符串。
  294. 注2:参数分割标识
  295. 各参数间以“/”分割,参数间的分割符“/”不能省略;
  296. 若两个分割符 “/”间的某参数为空时(即两个分割符 “/”直接将相连时)表示无该参数值;
  297. 注3:f字段说明
  298. 使用f字段时,应保证视频和音频参数的结构完整性,即在任何时候,f字段的结构都应是完整的结构:
  299. f = v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
  300. 若只有视频时,音频中的各参数项可以不填写,但应保持 “a///”的结构:
  301. f = v/编码格式/分辨率/帧率/码率类型/码率大小a///
  302. 若只有音频时也类似处理,视频中的各参数项可以不填写,但应保持 “v/”的结构:
  303. f = v/a/编码格式/码率大小/采样率
  304. f字段中视、音频参数段之间不需空格分割。
  305. 可使用f字段中的分辨率参数标识同一设备不同分辨率的码流。
  306. */
  307. func (channel *Channel) Invite(opt *InviteOptions) (code int, err error) {
  308. if opt.IsLive() {
  309. if !channel.State.CompareAndSwap(0, 1) {
  310. return 304, nil
  311. }
  312. defer func() {
  313. if err != nil {
  314. GB28181Plugin.Error("Invite", zap.Error(err))
  315. channel.State.Store(0)
  316. if conf.InviteMode == 1 {
  317. // 5秒后重试
  318. time.AfterFunc(time.Second*5, func() {
  319. channel.Invite(opt)
  320. })
  321. }
  322. } else {
  323. channel.State.Store(2)
  324. }
  325. }()
  326. }
  327. d := channel.Device
  328. streamPath := fmt.Sprintf("%s/%s", d.ID, channel.DeviceID)
  329. s := "Play"
  330. opt.CreateSSRC()
  331. if opt.Record() {
  332. s = "Playback"
  333. streamPath = fmt.Sprintf("%s/%s/%d-%d", d.ID, channel.DeviceID, opt.Start, opt.End)
  334. }
  335. if opt.StreamPath != "" {
  336. streamPath = opt.StreamPath
  337. } else if channel.DeviceID == "" {
  338. streamPath = "gb28181/" + d.ID
  339. } else {
  340. opt.StreamPath = streamPath
  341. }
  342. if opt.dump == "" {
  343. opt.dump = conf.DumpPath
  344. }
  345. protocol := ""
  346. networkType := "udp"
  347. reusePort := true
  348. if conf.IsMediaNetworkTCP() {
  349. networkType = "tcp"
  350. protocol = "TCP/"
  351. if conf.tcpPorts.Valid {
  352. opt.MediaPort, err = conf.tcpPorts.GetPort()
  353. opt.recyclePort = conf.tcpPorts.Recycle
  354. reusePort = false
  355. }
  356. } else {
  357. if conf.udpPorts.Valid {
  358. opt.MediaPort, err = conf.udpPorts.GetPort()
  359. opt.recyclePort = conf.udpPorts.Recycle
  360. reusePort = false
  361. }
  362. }
  363. if err != nil {
  364. return http.StatusInternalServerError, err
  365. }
  366. if opt.MediaPort == 0 {
  367. opt.MediaPort = conf.MediaPort
  368. }
  369. sdpInfo := []string{
  370. "v=0",
  371. fmt.Sprintf("o=%s 0 0 IN IP4 %s", channel.DeviceID, d.MediaIP),
  372. "s=" + s,
  373. "u=" + channel.DeviceID + ":0",
  374. "c=IN IP4 " + d.MediaIP,
  375. opt.String(),
  376. fmt.Sprintf("m=video %d %sRTP/AVP 96", opt.MediaPort, protocol),
  377. "a=recvonly",
  378. "a=rtpmap:96 PS/90000",
  379. "y=" + opt.ssrc,
  380. }
  381. if conf.IsMediaNetworkTCP() {
  382. sdpInfo = append(sdpInfo, "a=setup:passive", "a=connection:new")
  383. }
  384. invite := channel.CreateRequst(sip.INVITE)
  385. contentType := sip.ContentType("application/sdp")
  386. invite.AppendHeader(&contentType)
  387. invite.SetBody(strings.Join(sdpInfo, "\r\n")+"\r\n", true)
  388. subject := sip.GenericHeader{
  389. HeaderName: "Subject", Contents: fmt.Sprintf("%s:%s,%s:0", channel.DeviceID, opt.ssrc, conf.Serial),
  390. }
  391. invite.AppendHeader(&subject)
  392. inviteRes, err := d.SipRequestForResponse(invite)
  393. if err != nil {
  394. channel.Error("invite", zap.Error(err), zap.String("msg", invite.String()))
  395. return http.StatusInternalServerError, err
  396. }
  397. code = int(inviteRes.StatusCode())
  398. channel.Info("invite response", zap.Int("status code", code))
  399. if code == http.StatusOK {
  400. ds := strings.Split(inviteRes.Body(), "\r\n")
  401. for _, l := range ds {
  402. if ls := strings.Split(l, "="); len(ls) > 1 {
  403. if ls[0] == "y" && len(ls[1]) > 0 {
  404. if _ssrc, err := strconv.ParseInt(ls[1], 10, 0); err == nil {
  405. opt.SSRC = uint32(_ssrc)
  406. } else {
  407. channel.Error("read invite response y ", zap.Error(err))
  408. }
  409. // break
  410. }
  411. if ls[0] == "m" && len(ls[1]) > 0 {
  412. netinfo := strings.Split(ls[1], " ")
  413. if strings.ToUpper(netinfo[2]) == "TCP/RTP/AVP" {
  414. channel.Debug("Device support tcp")
  415. } else {
  416. channel.Debug("Device not support tcp")
  417. networkType = "udp"
  418. }
  419. }
  420. }
  421. }
  422. var psPuber ps.PSPublisher
  423. err = psPuber.Receive(streamPath, opt.dump, fmt.Sprintf("%s:%d", networkType, opt.MediaPort), opt.SSRC, reusePort)
  424. if err == nil {
  425. if !opt.IsLive() {
  426. // 10秒无数据关闭
  427. if psPuber.Stream.DelayCloseTimeout == 0 {
  428. psPuber.Stream.DelayCloseTimeout = time.Second * 10
  429. }
  430. if psPuber.Stream.IdleTimeout == 0 {
  431. psPuber.Stream.IdleTimeout = time.Second * 10
  432. }
  433. }
  434. PullStreams.Store(streamPath, &PullStream{
  435. opt: opt,
  436. channel: channel,
  437. inviteRes: inviteRes,
  438. })
  439. err = srv.Send(sip.NewAckRequest("", invite, inviteRes, "", nil))
  440. }
  441. }
  442. return
  443. }
  444. func (channel *Channel) Bye(streamPath string) int {
  445. d := channel.Device
  446. if streamPath == "" {
  447. streamPath = fmt.Sprintf("%s/%s", d.ID, channel.DeviceID)
  448. }
  449. if s, loaded := PullStreams.LoadAndDelete(streamPath); loaded {
  450. s.(*PullStream).Bye()
  451. if s := Streams.Get(streamPath); s != nil {
  452. s.Close()
  453. }
  454. return http.StatusOK
  455. }
  456. return http.StatusNotFound
  457. }
  458. func (channel *Channel) Pause(streamPath string) int {
  459. if s, loaded := PullStreams.Load(streamPath); loaded {
  460. r := s.(*PullStream).Pause()
  461. if s := Streams.Get(streamPath); s != nil {
  462. s.Pause()
  463. }
  464. return r
  465. }
  466. return http.StatusNotFound
  467. }
  468. func (channel *Channel) Resume(streamPath string) int {
  469. if s, loaded := PullStreams.Load(streamPath); loaded {
  470. r := s.(*PullStream).Resume()
  471. if s := Streams.Get(streamPath); s != nil {
  472. s.Resume()
  473. }
  474. return r
  475. }
  476. return http.StatusNotFound
  477. }
  478. func (channel *Channel) PlayAt(streamPath string, second uint) int {
  479. if s, loaded := PullStreams.Load(streamPath); loaded {
  480. r := s.(*PullStream).PlayAt(second)
  481. if s := Streams.Get(streamPath); s != nil {
  482. s.Resume()
  483. }
  484. return r
  485. }
  486. return http.StatusNotFound
  487. }
  488. func (channel *Channel) PlayForward(streamPath string, speed float32) int {
  489. if s, loaded := PullStreams.Load(streamPath); loaded {
  490. return s.(*PullStream).PlayForward(speed)
  491. }
  492. if s := Streams.Get(streamPath); s != nil {
  493. s.Resume()
  494. }
  495. return http.StatusNotFound
  496. }
  497. func (channel *Channel) TryAutoInvite(opt *InviteOptions) {
  498. condition := !opt.IsLive() || channel.CanInvite()
  499. channel.Debug("TryAutoInvite", zap.Any("opt", opt), zap.Bool("condition", condition))
  500. if condition {
  501. go channel.Invite(opt)
  502. }
  503. }
  504. func (channel *Channel) CanInvite() bool {
  505. if channel.State.Load() != 0 || len(channel.DeviceID) != 20 || channel.Status == ChannelOffStatus {
  506. return false
  507. }
  508. if conf.InviteIDs == "" {
  509. return true
  510. }
  511. // 11~13位是设备类型编码
  512. typeID := channel.DeviceID[10:13]
  513. // format: start-end,type1,type2
  514. tokens := strings.Split(conf.InviteIDs, ",")
  515. for _, tok := range tokens {
  516. if first, second, ok := strings.Cut(tok, "-"); ok {
  517. if typeID >= first && typeID <= second {
  518. return true
  519. }
  520. } else {
  521. if typeID == first {
  522. return true
  523. }
  524. }
  525. }
  526. return false
  527. }
  528. func getSipRespErrorCode(err error) int {
  529. if re, ok := err.(*sip.RequestError); ok {
  530. return int(re.Code)
  531. } else {
  532. return http.StatusInternalServerError
  533. }
  534. }