实现移动位置订阅

This commit is contained in:
yangjiechina
2024-06-28 20:57:19 +08:00
parent 0cfb2c14df
commit 2372237017
5 changed files with 160 additions and 14 deletions

48
api.go
View File

@@ -26,26 +26,25 @@ func init() {
}
}
type eventInfo struct {
Stream string `json:"stream"` //Stream id
Protocol string `json:"protocol"` //推拉流协议
RemoteAddr string `json:"remote_addr"` //peer地址
}
func withCheckParams(f func(streamId, protocol string, w http.ResponseWriter, req *http.Request)) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, req *http.Request) {
if "" != req.URL.RawQuery {
logger.Infof("on request %s?%s", req.URL.Path, req.URL.RawQuery)
}
info := eventInfo{}
err := HttpDecodeJSONBody(w, req, &info)
v := struct {
Stream string `json:"stream"` //Stream id
Protocol string `json:"protocol"` //推拉流协议
RemoteAddr string `json:"remote_addr"` //peer地址
}{}
err := HttpDecodeJSONBody(w, req, &v)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
f(info.Stream, info.Protocol, w, req)
f(v.Stream, v.Protocol, w, req)
}
}
@@ -102,7 +101,6 @@ func (api *ApiServer) OnPlay(streamId, protocol string, w http.ResponseWriter, r
return
}
//发送invite
split := strings.Split(streamId, "/")
if len(split) != 2 {
w.WriteHeader(http.StatusOK)
@@ -376,8 +374,26 @@ func (api *ApiServer) OnRecordList(w http.ResponseWriter, r *http.Request) {
}
func (api *ApiServer) OnSubscribePosition(w http.ResponseWriter, r *http.Request) {
devices := DeviceManager.AllDevices()
httpResponse2(w, devices)
v := struct {
DeviceID string `json:"device_id"`
ChannelID string `json:"channel_id"`
}{}
if err := HttpDecodeJSONBody(w, r, &v); err != nil {
httpResponse2(w, err)
return
}
device := DeviceManager.Find(v.DeviceID)
if device == nil {
return
}
if err := device.DoSubscribePosition(v.ChannelID); err != nil {
}
w.WriteHeader(http.StatusOK)
}
func (api *ApiServer) OnSeekPlayback(w http.ResponseWriter, r *http.Request) {
@@ -391,8 +407,12 @@ func (api *ApiServer) OnPTZControl(w http.ResponseWriter, r *http.Request) {
}
func (api *ApiServer) OnBroadcast(w http.ResponseWriter, r *http.Request) {
devices := DeviceManager.AllDevices()
httpResponse2(w, devices)
//v := struct {
// DeviceID string `json:"device_id"`
// ChannelID string `json:"channel_id"`
// RoomID string `json:"room_id"` //如果要实现群呼功能, 除第一次广播外, 后续请求都携带该参数
//}{}
}
func (api *ApiServer) OnTalk(w http.ResponseWriter, r *http.Request) {

View File

@@ -15,6 +15,7 @@ type Config_ struct {
Password string `json:"password"`
AliveExpires int `json:"alive_expires"`
MobilePositionInterval int `json:"mobile_position_interval"`
MobilePositionExpires int `json:"mobile_position_expires"`
MediaServer string `json:"media_server"`
SipPort sip.Port

38
event.go Normal file
View File

@@ -0,0 +1,38 @@
package main
import (
"fmt"
"github.com/ghettovoice/gosip/sip"
)
type Event string
func (ev *Event) String() string { return fmt.Sprintf("%s: %s", ev.Name(), ev.Value()) }
func (ev *Event) Name() string { return "Event" }
func (ev Event) Value() string { return string(ev) }
func (ev *Event) Clone() sip.Header { return ev }
func (ev *Event) Equals(other interface{}) bool {
if h, ok := other.(Event); ok {
if ev == nil {
return false
}
return *ev == h
}
if h, ok := other.(*Event); ok {
if ev == h {
return true
}
if ev == nil && h != nil || ev != nil && h == nil {
return false
}
return *ev == *h
}
return false
}

64
position.go Normal file
View File

@@ -0,0 +1,64 @@
package main
import (
"fmt"
"github.com/ghettovoice/gosip/sip"
)
const MobilePositionMessageFormat = "<?xml version=\"1.0\"?>\r\n" +
"<Query>\r\n" +
"<CmdType>MobilePosition</CmdType>\r\n" +
"<SN>%s</SN>\r\n" +
"<DeviceID>%s</DeviceID>\r\n" +
"<Interval>%d</Interval>\r\n" +
"</Query>\r\n"
type MobilePositionNotify struct {
DeviceID string `xml:"DeviceID"`
CmdType string `xml:"CmdType"`
SN int `xml:"SN"`
Time string `xml:"Time"`
Longitude string `xml:"Longitude"`
Latitude string `xml:"Latitude"`
Speed string `xml:"Speed"`
Direction string `xml:"Direction"`
Altitude string `xml:"Altitude"`
}
func (d *DBDevice) DoSubscribePosition(channelId string) error {
if channelId == "" {
channelId = d.Id
}
//暂时不考虑级联
builder := d.NewRequestBuilder(sip.SUBSCRIBE, Config.SipId, Config.SipRealm, channelId)
body := fmt.Sprintf(MobilePositionMessageFormat, "1", channelId, Config.MobilePositionInterval)
expiresHeader := sip.Expires(Config.MobilePositionExpires)
builder.SetExpires(&expiresHeader)
builder.SetContentType(&XmlMessageType)
builder.SetContact(globalContactAddress)
builder.SetBody(body)
request, err := builder.Build()
if err != nil {
return err
}
event := Event("Catalog;id=2")
request.AppendHeader(&event)
response, err := SipUA.SendRequestWithTimeout(5, request)
if err != nil {
return err
}
if response.StatusCode() != 200 {
return fmt.Errorf("err code %d", response.StatusCode())
}
return nil
}
func (d *DBDevice) OnMobilePositionNotify(notify *MobilePositionNotify) {
Sugar.Infof("收到位置信息 device:%s data:%v", d.Id, notify)
}

View File

@@ -2,12 +2,14 @@ package main
import (
"context"
"encoding/xml"
"github.com/ghettovoice/gosip"
"github.com/ghettovoice/gosip/log"
"github.com/ghettovoice/gosip/sip"
"net"
"strconv"
"strings"
"time"
)
var (
@@ -41,6 +43,8 @@ type SipServer interface {
SendRequest(request sip.Request)
SendRequestWithTimeout(seconds int, request sip.Request, options ...gosip.RequestWithContextOption) (sip.Response, error)
Send(msg sip.Message) error
}
@@ -99,6 +103,19 @@ func (s *sipServer) OnBye(req sip.Request, tx sip.ServerTransaction) {
}
func (s *sipServer) OnNotify(req sip.Request, tx sip.ServerTransaction) {
response := sip.NewResponseFromRequest("", req, 200, "OK", "")
sendResponse(tx, response)
body := strings.Replace(req.Body(), "GB2312", "UTF-8", 1)
mobilePosition := MobilePositionNotify{}
if err := xml.Unmarshal([]byte(body), &mobilePosition); err != nil {
Sugar.Errorf("解析位置通知失败 err:%s body:%s", err.Error(), body)
return
}
if device := DeviceManager.Find(mobilePosition.DeviceID); device != nil {
device.OnMobilePositionNotify(&mobilePosition)
}
}
func sendResponse(tx sip.ServerTransaction, response sip.Response) bool {
@@ -116,6 +133,12 @@ func (s *sipServer) SendRequestWithContext(ctx context.Context, request sip.Requ
s.sip.RequestWithContext(ctx, request, options...)
}
func (s *sipServer) SendRequestWithTimeout(seconds int, request sip.Request, options ...gosip.RequestWithContextOption) (sip.Response, error) {
Sugar.Infof("send reqeust:%s", request.String())
reqCtx, _ := context.WithTimeout(context.Background(), time.Duration(seconds)*time.Second)
return s.sip.RequestWithContext(reqCtx, request, options...)
}
func (s *sipServer) SendRequest(request sip.Request) {
Sugar.Infof("send reqeust:%s", request.String())