mirror of
https://github.com/lkmio/gb-cms.git
synced 2025-09-26 19:51:22 +08:00
243 lines
5.5 KiB
Go
243 lines
5.5 KiB
Go
package stack
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"gb-cms/common"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
TransStreamRtmp = iota + 1
|
|
TransStreamFlv = 2
|
|
TransStreamRtsp = 3
|
|
TransStreamHls = 4
|
|
TransStreamRtc = 5
|
|
TransStreamGBCascaded = 6 // 国标级联转发
|
|
TransStreamGBTalk = 7 // 国标广播/对讲转发
|
|
TransStreamGBGateway = 8 // 国标网关
|
|
)
|
|
|
|
const (
|
|
SourceTypeRtmp = iota + 1
|
|
SourceType28181
|
|
SourceType1078
|
|
SourceTypeGBTalk
|
|
)
|
|
|
|
type SourceDetails struct {
|
|
ID string `json:"id"`
|
|
Protocol string `json:"protocol"` // 推流协议
|
|
Time time.Time `json:"time"` // 推流时间
|
|
SinkCount int `json:"sink_count"` // 播放端计数
|
|
Bitrate string `json:"bitrate"` // 码率统计
|
|
Tracks []string `json:"tracks"` // 每路流编码器ID
|
|
Urls []string `json:"urls"` // 拉流地址
|
|
}
|
|
|
|
type SinkDetails struct {
|
|
ID string `json:"id"`
|
|
Protocol string `json:"protocol"` // 拉流协议
|
|
Time time.Time `json:"time"` // 拉流时间
|
|
Bitrate string `json:"bitrate"` // 码率统计
|
|
Tracks []string `json:"tracks"` // 每路流编码器ID
|
|
}
|
|
|
|
type SDP struct {
|
|
SessionName string `json:"session_name,omitempty"` // play/download/playback/talk/broadcast
|
|
Addr string `json:"addr,omitempty"` // 连接地址
|
|
SSRC string `json:"ssrc,omitempty"`
|
|
Setup string `json:"setup,omitempty"` // active/passive
|
|
Transport string `json:"transport,omitempty"` // tcp/udp
|
|
}
|
|
|
|
type SourceSDP struct {
|
|
Source string `json:"source"` // GetSourceID
|
|
SDP
|
|
}
|
|
|
|
type GBOffer struct {
|
|
SourceSDP
|
|
AnswerSetup string `json:"answer_setup,omitempty"` // 希望应答的连接方式
|
|
TransStreamProtocol int `json:"trans_stream_protocol,omitempty"`
|
|
}
|
|
|
|
func Send(path string, body interface{}) (*http.Response, error) {
|
|
return SendWithUrlParams(path, body, nil)
|
|
}
|
|
|
|
func SendWithUrlParams(path string, body interface{}, values url.Values) (*http.Response, error) {
|
|
if values != nil {
|
|
params := values.Encode()
|
|
if len(params) > 0 {
|
|
path = fmt.Sprintf("%s?%s", path, params)
|
|
}
|
|
}
|
|
|
|
url := fmt.Sprintf("%s/%s", common.Config.MediaServer, path)
|
|
|
|
data, err := json.Marshal(body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
client := &http.Client{
|
|
Timeout: 10 * time.Second,
|
|
}
|
|
|
|
request, err := http.NewRequest("post", url, bytes.NewBuffer(data))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
request.Header.Set("Content-Type", "application/json")
|
|
return client.Do(request)
|
|
}
|
|
|
|
func MSCreateGBSource(id, setup string, ssrc string, sessionName string) (string, uint16, []string, string, error) {
|
|
v := &SourceSDP{
|
|
Source: id,
|
|
SDP: SDP{
|
|
Setup: setup,
|
|
SSRC: ssrc,
|
|
SessionName: sessionName,
|
|
},
|
|
}
|
|
|
|
response, err := Send("api/v1/gb28181/source/create", v)
|
|
if err != nil {
|
|
return "", 0, nil, "", err
|
|
}
|
|
|
|
data := &common.Response[struct {
|
|
SDP
|
|
Urls []string `json:"urls"`
|
|
}]{}
|
|
|
|
if err = common.DecodeJSONBody(response.Body, data); err != nil {
|
|
return "", 0, nil, "", err
|
|
} else if http.StatusOK != data.Code {
|
|
return "", 0, nil, "", fmt.Errorf(data.Msg)
|
|
}
|
|
|
|
host, p, err := net.SplitHostPort(data.Data.Addr)
|
|
if err != nil {
|
|
return "", 0, nil, "", err
|
|
}
|
|
|
|
port, err := strconv.Atoi(p)
|
|
return host, uint16(port), data.Data.Urls, data.Data.SSRC, err
|
|
}
|
|
|
|
func MSConnectGBSource(id, addr string) error {
|
|
v := &SourceSDP{
|
|
Source: id,
|
|
SDP: SDP{
|
|
Addr: addr,
|
|
},
|
|
}
|
|
|
|
_, err := Send("api/v1/gb28181/answer/set", v)
|
|
return err
|
|
}
|
|
|
|
func MSCloseSource(id string) error {
|
|
v := &struct {
|
|
Source string `json:"source"`
|
|
}{
|
|
Source: id,
|
|
}
|
|
|
|
_, err := Send("api/v1/source/close", v)
|
|
return err
|
|
}
|
|
|
|
func MSCloseSink(sourceId string, sinkId string) {
|
|
v := struct {
|
|
SourceID string `json:"source"`
|
|
SinkID string `json:"sink"` // sink id
|
|
}{
|
|
sourceId, sinkId,
|
|
}
|
|
|
|
_, _ = Send("api/v1/sink/close", v)
|
|
}
|
|
|
|
func MSQuerySourceList() ([]*SourceDetails, error) {
|
|
response, err := Send("api/v1/source/list", nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
data := &common.Response[[]*SourceDetails]{}
|
|
if err = common.DecodeJSONBody(response.Body, data); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return data.Data, err
|
|
}
|
|
|
|
func MSQuerySinkList(source string) ([]*SinkDetails, error) {
|
|
id := struct {
|
|
Source string `json:"source"`
|
|
}{source}
|
|
|
|
response, err := Send("api/v1/sink/list", id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
data := &common.Response[[]*SinkDetails]{}
|
|
if err = common.DecodeJSONBody(response.Body, data); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return data.Data, err
|
|
}
|
|
|
|
func MSAddForwardSink(protocol int, source, addr, offerSetup, answerSetup, ssrc, sessionName string, values url.Values) (string, uint16, string, string, error) {
|
|
offer := &GBOffer{
|
|
SourceSDP: SourceSDP{
|
|
Source: source,
|
|
SDP: SDP{
|
|
Addr: addr,
|
|
Setup: offerSetup,
|
|
SSRC: ssrc,
|
|
SessionName: sessionName,
|
|
},
|
|
},
|
|
AnswerSetup: answerSetup,
|
|
TransStreamProtocol: protocol,
|
|
}
|
|
|
|
var err error
|
|
response, err := SendWithUrlParams("api/v1/sink/add", offer, values)
|
|
if err != nil {
|
|
return "", 0, "", "", err
|
|
}
|
|
|
|
data := &common.Response[struct {
|
|
Sink string `json:"sink"`
|
|
SDP
|
|
}]{}
|
|
|
|
if err = common.DecodeJSONBody(response.Body, data); err != nil {
|
|
return "", 0, "", "", err
|
|
} else if http.StatusOK != data.Code {
|
|
return "", 0, "", "", fmt.Errorf(data.Msg)
|
|
}
|
|
|
|
host, p, err := net.SplitHostPort(data.Data.Addr)
|
|
if err != nil {
|
|
return "", 0, "", "", err
|
|
}
|
|
|
|
port, _ := strconv.Atoi(p)
|
|
return host, uint16(port), data.Data.Sink, data.Data.SSRC, nil
|
|
}
|