A signaling server for GB28181
This commit is contained in:
75
pkg/signaling/signaling.go
Normal file
75
pkg/signaling/signaling.go
Normal file
@ -0,0 +1,75 @@
|
||||
package signaling
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/ossrs/go-oryx-lib/errors"
|
||||
"github.com/ossrs/go-oryx-lib/logger"
|
||||
)
|
||||
|
||||
type ISignaling interface {
|
||||
Publish(id, ssrc string) (int, error)
|
||||
Unpublish(id string) error
|
||||
GetStreamStatus(id string) (bool, error)
|
||||
}
|
||||
|
||||
// The r is HTTP API to request, like "http://localhost:1985/gb/v1/publish".
|
||||
// The req is the HTTP request body, will be marshal to JSON object. nil is no body
|
||||
// The res is the HTTP response body, already unmarshal to JSON object.
|
||||
func apiRequest(ctx context.Context, r string, req interface{}, res interface{}) error {
|
||||
var buf bytes.Buffer
|
||||
if req != nil {
|
||||
if err := json.NewEncoder(&buf).Encode(req); err != nil {
|
||||
return errors.Wrapf(err, "Marshal body %v", req)
|
||||
}
|
||||
}
|
||||
logger.Tf(ctx, "Request url api=%v with %v bytes", r, buf.Len())
|
||||
|
||||
method := "POST"
|
||||
if req == nil {
|
||||
method = "GET"
|
||||
}
|
||||
reqObj, err := http.NewRequest(method, r, &buf)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "HTTP request %v", buf.String())
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
resObj, err := client.Do(reqObj.WithContext(ctx))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Do HTTP request %v", buf.String())
|
||||
}
|
||||
defer resObj.Body.Close()
|
||||
|
||||
if resObj.StatusCode != http.StatusOK {
|
||||
return errors.Errorf("Server returned status code=%v", resObj.StatusCode)
|
||||
}
|
||||
|
||||
b2, err := io.ReadAll(resObj.Body)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Read response for %v", buf.String())
|
||||
}
|
||||
logger.Tf(ctx, "Response from %v is %v bytes", r, len(b2))
|
||||
|
||||
errorCode := struct {
|
||||
Code int `json:"code"`
|
||||
}{}
|
||||
if err := json.Unmarshal(b2, &errorCode); err != nil {
|
||||
return errors.Wrapf(err, "Unmarshal %v", string(b2))
|
||||
}
|
||||
if errorCode.Code != 0 {
|
||||
return errors.Errorf("Server fail code=%v %v", errorCode.Code, string(b2))
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(b2, res); err != nil {
|
||||
return errors.Wrapf(err, "Unmarshal %v", string(b2))
|
||||
}
|
||||
logger.Tf(ctx, "Parse response to code=%v ok, %v", errorCode.Code, res)
|
||||
|
||||
return nil
|
||||
}
|
||||
95
pkg/signaling/srs.go
Normal file
95
pkg/signaling/srs.go
Normal file
@ -0,0 +1,95 @@
|
||||
package signaling
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ossrs/go-oryx-lib/errors"
|
||||
)
|
||||
|
||||
type Srs struct {
|
||||
Ctx context.Context
|
||||
Addr string // The address of SRS, eg: http://localhost:1985
|
||||
}
|
||||
|
||||
func (s *Srs) Publish(id, ssrc string) (int, error) {
|
||||
req := struct {
|
||||
Id string `json:"id"`
|
||||
SSRC string `json:"ssrc"`
|
||||
}{
|
||||
id, ssrc,
|
||||
}
|
||||
|
||||
res := struct {
|
||||
Code int `json:"code"`
|
||||
Port int `json:"port"`
|
||||
}{}
|
||||
|
||||
if err := apiRequest(s.Ctx, s.Addr+"/gb/v1/publish/", req, &res); err != nil {
|
||||
return 0, errors.Wrapf(err, "gb/v1/publish")
|
||||
}
|
||||
|
||||
return res.Port, nil
|
||||
}
|
||||
|
||||
func (s *Srs) Unpublish(id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// {
|
||||
// "code": 0,
|
||||
// "server": "vid-y19n6nm",
|
||||
// "service": "382k456r",
|
||||
// "pid": "9495",
|
||||
// "streams": [{
|
||||
// "id": "vid-9y0ozy0",
|
||||
// "name": "0551954854",
|
||||
// "vhost": "vid-v2ws53u",
|
||||
// "app": "live",
|
||||
// "tcUrl": "webrtc://127.0.0.1:1985/live",
|
||||
// "url": "/live/0551954854",
|
||||
// "live_ms": 1720428680003,
|
||||
// "clients": 1,
|
||||
// "frames": 8431,
|
||||
// "send_bytes": 66463941,
|
||||
// "recv_bytes": 89323998,
|
||||
// "kbps": {
|
||||
// "recv_30s": 0,
|
||||
// "send_30s": 0
|
||||
// },
|
||||
// "publish": {
|
||||
// "active": false,
|
||||
// "cid": "b3op069g"
|
||||
// },
|
||||
// "video": null,
|
||||
// "audio": null
|
||||
// }]
|
||||
// }
|
||||
func (s *Srs) GetStreamStatus(id string) (bool, error) {
|
||||
type Stream struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Publish struct {
|
||||
Active bool `json:"active"`
|
||||
Cid string `json:"cid"`
|
||||
} `json:"publish"`
|
||||
}
|
||||
res := struct {
|
||||
Code int `json:"code"`
|
||||
Streams []Stream `json:"streams"`
|
||||
}{}
|
||||
|
||||
if err := apiRequest(s.Ctx, s.Addr+"/api/v1/streams?count=99", nil, &res); err != nil {
|
||||
return false, errors.Wrapf(err, "api/v1/stream")
|
||||
}
|
||||
|
||||
if len(res.Streams) == 0 {
|
||||
return false, nil
|
||||
} else {
|
||||
for _, v := range res.Streams {
|
||||
if v.Name == id {
|
||||
return v.Publish.Active, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
Reference in New Issue
Block a user