mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
GB28181: Support GB28181-2016 protocol. v5.0.74 (#3201)
01. Support GB config as StreamCaster. 02. Support disable GB by --gb28181=off. 03. Add utests for SIP examples. 04. Wireshark plugin to decode TCP/9000 as rtp.rfc4571 05. Support MPEGPS program stream codec. 06. Add utest for PS stream codec. 07. Decode MPEGPS packet stream. 08. Carry RTP and PS packet as helper in PS message. 09. Support recover from error mode. 10. Support process by a pack of PS/TS messages. 11. Add statistic for recovered and msgs dropped. 12. Recover from err position fastly. 13. Define state machine for GB session. 14. Bind context to GB session. 15. Re-invite when media disconnected. 16. Update GitHub actions with GB28181. 17. Support parse CANDIDATE by env or pip. 18. Support mux GB28181 to RTMP. 19. Support regression test by srs-bench.
This commit is contained in:
parent
9c81a0e1bd
commit
5a420ece3b
298 changed files with 43343 additions and 763 deletions
147
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/util/elasticchan.go
generated
vendored
Normal file
147
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/util/elasticchan.go
generated
vendored
Normal file
|
@ -0,0 +1,147 @@
|
|||
// Forked from github.com/StefanKopieczek/gossip by @StefanKopieczek
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/ghettovoice/gosip/log"
|
||||
)
|
||||
|
||||
// The buffer size of the primitive input and output chans.
|
||||
const c_ELASTIC_CHANSIZE = 3
|
||||
|
||||
// A dynamic channel that does not block on send, but has an unlimited buffer capacity.
|
||||
// ElasticChan uses a dynamic slice to buffer signals received on the input channel until
|
||||
// the output channel is ready to process them.
|
||||
type ElasticChan struct {
|
||||
In chan interface{}
|
||||
Out chan interface{}
|
||||
buffer []interface{}
|
||||
stopped bool
|
||||
done chan struct{}
|
||||
|
||||
log log.Logger
|
||||
logMu sync.RWMutex
|
||||
}
|
||||
|
||||
// Initialise the Elastic channel, and start the management goroutine.
|
||||
func (c *ElasticChan) Init() {
|
||||
c.In = make(chan interface{}, c_ELASTIC_CHANSIZE)
|
||||
c.Out = make(chan interface{}, c_ELASTIC_CHANSIZE)
|
||||
c.buffer = make([]interface{}, 0)
|
||||
c.done = make(chan struct{})
|
||||
}
|
||||
|
||||
func (c *ElasticChan) Run() {
|
||||
go c.manage()
|
||||
}
|
||||
|
||||
func (c *ElasticChan) Stop() {
|
||||
select {
|
||||
case <-c.done:
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
logger := c.Log()
|
||||
|
||||
if logger != nil {
|
||||
logger.Trace("stopping elastic chan...")
|
||||
}
|
||||
|
||||
close(c.In)
|
||||
<-c.done
|
||||
|
||||
if logger != nil {
|
||||
logger.Trace("elastic chan stopped")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ElasticChan) Log() log.Logger {
|
||||
c.logMu.RLock()
|
||||
defer c.logMu.RUnlock()
|
||||
|
||||
return c.log
|
||||
|
||||
}
|
||||
|
||||
func (c *ElasticChan) SetLog(logger log.Logger) {
|
||||
c.logMu.Lock()
|
||||
|
||||
c.log = logger.
|
||||
WithPrefix("util.ElasticChan").
|
||||
WithFields(log.Fields{
|
||||
"elastic_chan_ptr": fmt.Sprintf("%p", c),
|
||||
})
|
||||
|
||||
c.logMu.Unlock()
|
||||
}
|
||||
|
||||
// Poll for input from one end of the channel and add it to the buffer.
|
||||
// Also poll sending buffered signals out over the output chan.
|
||||
// TODO: add cancel chan
|
||||
func (c *ElasticChan) manage() {
|
||||
defer close(c.done)
|
||||
|
||||
loop:
|
||||
for {
|
||||
logger := c.Log()
|
||||
|
||||
if len(c.buffer) > 0 {
|
||||
// The buffer has something in it, so try to send as well as
|
||||
// receive.
|
||||
// (Receive first in order to minimize blocked Send() calls).
|
||||
select {
|
||||
case in, ok := <-c.In:
|
||||
if !ok {
|
||||
if logger != nil {
|
||||
logger.Trace("elastic chan will dispose")
|
||||
}
|
||||
|
||||
break loop
|
||||
}
|
||||
c.Log().Tracef("ElasticChan %p gets '%v'", c, in)
|
||||
c.buffer = append(c.buffer, in)
|
||||
case c.Out <- c.buffer[0]:
|
||||
c.Log().Tracef("ElasticChan %p sends '%v'", c, c.buffer[0])
|
||||
c.buffer = c.buffer[1:]
|
||||
}
|
||||
} else {
|
||||
// The buffer is empty, so there's nothing to send.
|
||||
// Just wait to receive.
|
||||
in, ok := <-c.In
|
||||
if !ok {
|
||||
if logger != nil {
|
||||
logger.Trace("elastic chan will dispose")
|
||||
}
|
||||
|
||||
break loop
|
||||
}
|
||||
c.Log().Tracef("ElasticChan %p gets '%v'", c, in)
|
||||
c.buffer = append(c.buffer, in)
|
||||
}
|
||||
}
|
||||
|
||||
c.dispose()
|
||||
}
|
||||
|
||||
func (c *ElasticChan) dispose() {
|
||||
logger := c.Log()
|
||||
|
||||
if logger != nil {
|
||||
logger.Trace("elastic chan disposing...")
|
||||
}
|
||||
|
||||
for len(c.buffer) > 0 {
|
||||
select {
|
||||
case c.Out <- c.buffer[0]:
|
||||
c.buffer = c.buffer[1:]
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
if logger != nil {
|
||||
logger.Trace("elastic chan disposed")
|
||||
}
|
||||
}
|
104
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/util/helpers.go
generated
vendored
Normal file
104
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/util/helpers.go
generated
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
// Forked from github.com/StefanKopieczek/gossip by @StefanKopieczek
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Check two string pointers for equality as follows:
|
||||
// - If neither pointer is nil, check equality of the underlying strings.
|
||||
// - If either pointer is nil, return true if and only if they both are.
|
||||
func StrPtrEq(a *string, b *string) bool {
|
||||
if a == nil || b == nil {
|
||||
return a == b
|
||||
}
|
||||
|
||||
return *a == *b
|
||||
}
|
||||
|
||||
// Check two uint16 pointers for equality as follows:
|
||||
// - If neither pointer is nil, check equality of the underlying uint16s.
|
||||
// - If either pointer is nil, return true if and only if they both are.
|
||||
func Uint16PtrEq(a *uint16, b *uint16) bool {
|
||||
if a == nil || b == nil {
|
||||
return a == b
|
||||
}
|
||||
|
||||
return *a == *b
|
||||
}
|
||||
|
||||
func Coalesce(arg1 interface{}, arg2 interface{}, args ...interface{}) interface{} {
|
||||
all := append([]interface{}{arg1, arg2}, args...)
|
||||
for _, arg := range all {
|
||||
if arg != nil {
|
||||
return arg
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Noop() {}
|
||||
|
||||
func MergeErrs(chs ...<-chan error) <-chan error {
|
||||
wg := new(sync.WaitGroup)
|
||||
out := make(chan error)
|
||||
|
||||
pipe := func(ch <-chan error) {
|
||||
defer wg.Done()
|
||||
for err := range ch {
|
||||
out <- err
|
||||
}
|
||||
}
|
||||
|
||||
wg.Add(len(chs))
|
||||
for _, ch := range chs {
|
||||
go pipe(ch)
|
||||
}
|
||||
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(out)
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func ResolveSelfIP() (net.IP, error) {
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, iface := range ifaces {
|
||||
if iface.Flags&net.FlagUp == 0 {
|
||||
continue // interface down
|
||||
}
|
||||
if iface.Flags&net.FlagLoopback != 0 {
|
||||
continue // loopback interface
|
||||
}
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
ip = v.IP
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
if ip == nil || ip.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
ip = ip.To4()
|
||||
if ip == nil {
|
||||
continue // not an ipv4 address
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("server not connected to any network")
|
||||
}
|
38
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/util/rand.go
generated
vendored
Normal file
38
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/util/rand.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// https://github.com/kpbird/golang_random_string
|
||||
func RandString(n int) string {
|
||||
output := make([]byte, n)
|
||||
// We will take n bytes, one byte for each character of output.
|
||||
randomness := make([]byte, n)
|
||||
// read all random
|
||||
_, err := rand.Read(randomness)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
l := len(letterBytes)
|
||||
// fill output
|
||||
for pos := range output {
|
||||
// get random item
|
||||
random := randomness[pos]
|
||||
// random % 64
|
||||
randomPos := random % uint8(l)
|
||||
// put into output
|
||||
output[pos] = letterBytes[randomPos]
|
||||
}
|
||||
|
||||
return string(output)
|
||||
}
|
75
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/util/semaphore.go
generated
vendored
Normal file
75
trunk/3rdparty/srs-bench/vendor/github.com/ghettovoice/gosip/util/semaphore.go
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
// Forked from github.com/StefanKopieczek/gossip by @StefanKopieczek
|
||||
package util
|
||||
|
||||
import "sync"
|
||||
|
||||
// Simple semaphore implementation.
|
||||
// Any number of calls to Acquire() can be made; these will not block.
|
||||
// If the semaphore has been acquired more times than it has been released, it is called 'blocked'.
|
||||
// Otherwise, it is called 'free'.
|
||||
type Semaphore interface {
|
||||
// Take a semaphore lock.
|
||||
Acquire()
|
||||
|
||||
// Release an acquired semaphore lock.
|
||||
// This should only be called when the semaphore is blocked, otherwise behaviour is undefined
|
||||
Release()
|
||||
|
||||
// Block execution until the semaphore is free.
|
||||
Wait()
|
||||
|
||||
// Clean up the semaphore object.
|
||||
Dispose()
|
||||
}
|
||||
|
||||
func NewSemaphore() Semaphore {
|
||||
sem := new(semaphore)
|
||||
sem.cond = sync.NewCond(&sync.Mutex{})
|
||||
go func(s *semaphore) {
|
||||
select {
|
||||
case <-s.stop:
|
||||
return
|
||||
case <-s.acquired:
|
||||
s.locks += 1
|
||||
case <-s.released:
|
||||
s.locks -= 1
|
||||
if s.locks == 0 {
|
||||
s.cond.Broadcast()
|
||||
}
|
||||
}
|
||||
}(sem)
|
||||
return sem
|
||||
}
|
||||
|
||||
// Concrete implementation of Semaphore.
|
||||
type semaphore struct {
|
||||
held bool
|
||||
locks int
|
||||
acquired chan bool
|
||||
released chan bool
|
||||
stop chan bool
|
||||
cond *sync.Cond
|
||||
}
|
||||
|
||||
// Implements Semaphore.Acquire()
|
||||
func (sem *semaphore) Acquire() {
|
||||
sem.acquired <- true
|
||||
}
|
||||
|
||||
// Implements Semaphore.Release()
|
||||
func (sem *semaphore) Release() {
|
||||
sem.released <- true
|
||||
}
|
||||
|
||||
// Implements Semaphore.Wait()
|
||||
func (sem *semaphore) Wait() {
|
||||
sem.cond.L.Lock()
|
||||
for sem.locks != 0 {
|
||||
sem.cond.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
// Implements Semaphore.Dispose()
|
||||
func (sem *semaphore) Dispose() {
|
||||
sem.stop <- true
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue