Browse Source

add comment

pull/138/head
gcoder 5 years ago
parent
commit
073a332f8f
  1. 5
      av/av.go
  2. 17
      main.go
  3. 10
      protocol/api/api.go
  4. 10
      protocol/httpflv/server.go
  5. 138
      protocol/rtmp/stream.go
  6. 40
      protocol/rtsp/rtsp.go

5
av/av.go

@ -107,11 +107,13 @@ type GetWriter interface {
GetWriter(Info) WriteCloser GetWriter(Info) WriteCloser
} }
// 流读写接口
type Handler interface { type Handler interface {
HandleReader(ReadCloser) HandleReader(ReadCloser)
HandleWriter(WriteCloser) HandleWriter(WriteCloser)
} }
// 流状态
type Alive interface { type Alive interface {
Alive() bool Alive() bool
} }
@ -125,6 +127,7 @@ type CalcTime interface {
CalcBaseTimestamp() CalcBaseTimestamp()
} }
// 流信息
type Info struct { type Info struct {
Key string Key string
URL string URL string
@ -141,12 +144,14 @@ func (info Info) String() string {
info.Key, info.URL, info.UID, info.Inter) info.Key, info.URL, info.UID, info.Inter)
} }
// 读源流数据接口
type ReadCloser interface { type ReadCloser interface {
Closer Closer
Alive Alive
Read(*Packet) error Read(*Packet) error
} }
// 写目标流数据接口
type WriteCloser interface { type WriteCloser interface {
Closer Closer
Alive Alive

17
main.go

@ -2,15 +2,16 @@ package main
import ( import (
"fmt" "fmt"
"net"
"path"
"runtime"
"time"
"github.com/gwuhaolin/livego/configure" "github.com/gwuhaolin/livego/configure"
"github.com/gwuhaolin/livego/protocol/api" "github.com/gwuhaolin/livego/protocol/api"
"github.com/gwuhaolin/livego/protocol/hls" "github.com/gwuhaolin/livego/protocol/hls"
"github.com/gwuhaolin/livego/protocol/httpflv" "github.com/gwuhaolin/livego/protocol/httpflv"
"github.com/gwuhaolin/livego/protocol/rtmp" "github.com/gwuhaolin/livego/protocol/rtmp"
"net"
"path"
"runtime"
"time"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -39,7 +40,7 @@ func startHls() *hls.Server {
var rtmpAddr string var rtmpAddr string
func startRtmp(stream *rtmp.RtmpStream, hlsServer *hls.Server) { func startRtmp(stream *rtmp.StreamServer, hlsServer *hls.Server) {
rtmpAddr = configure.Config.GetString("rtmp_addr") rtmpAddr = configure.Config.GetString("rtmp_addr")
rtmpListen, err := net.Listen("tcp", rtmpAddr) rtmpListen, err := net.Listen("tcp", rtmpAddr)
@ -66,7 +67,7 @@ func startRtmp(stream *rtmp.RtmpStream, hlsServer *hls.Server) {
rtmpServer.Serve(rtmpListen) rtmpServer.Serve(rtmpListen)
} }
func startHTTPFlv(stream *rtmp.RtmpStream) { func startHTTPFlv(stream *rtmp.StreamServer) {
httpflvAddr := configure.Config.GetString("httpflv_addr") httpflvAddr := configure.Config.GetString("httpflv_addr")
flvListen, err := net.Listen("tcp", httpflvAddr) flvListen, err := net.Listen("tcp", httpflvAddr)
@ -86,7 +87,7 @@ func startHTTPFlv(stream *rtmp.RtmpStream) {
}() }()
} }
func startAPI(stream *rtmp.RtmpStream) { func startAPI(stream *rtmp.StreamServer) {
apiAddr := configure.Config.GetString("api_addr") apiAddr := configure.Config.GetString("api_addr")
if apiAddr != "" { if apiAddr != "" {
@ -134,7 +135,7 @@ func main() {
version: %s version: %s
`, VERSION) `, VERSION)
stream := rtmp.NewRtmpStream() stream := rtmp.NewStreamServers()
hlsServer := startHls() hlsServer := startHls()
startHTTPFlv(stream) startHTTPFlv(stream)
startAPI(stream) startAPI(stream)

10
protocol/api/api.go

@ -152,7 +152,7 @@ func (server *Server) GetLiveStatics(w http.ResponseWriter, req *http.Request) {
defer res.SendJson() defer res.SendJson()
rtmpStream := server.handler.(*rtmp.RtmpStream) rtmpStream := server.handler.(*rtmp.StreamServer)
if rtmpStream == nil { if rtmpStream == nil {
res.Status = 500 res.Status = 500
res.Data = "Get rtmp stream information error" res.Data = "Get rtmp stream information error"
@ -161,8 +161,8 @@ func (server *Server) GetLiveStatics(w http.ResponseWriter, req *http.Request) {
msgs := new(streams) msgs := new(streams)
rtmpStream.GetStreams().Range(func(key, val interface{}) bool { rtmpStream.GetServices().Range(func(key, val interface{}) bool {
if s, ok := val.(*rtmp.Stream); ok { if s, ok := val.(*rtmp.StreamService); ok {
if s.GetReader() != nil { if s.GetReader() != nil {
switch s.GetReader().(type) { switch s.GetReader().(type) {
case *rtmp.VirReader: case *rtmp.VirReader:
@ -176,8 +176,8 @@ func (server *Server) GetLiveStatics(w http.ResponseWriter, req *http.Request) {
return true return true
}) })
rtmpStream.GetStreams().Range(func(key, val interface{}) bool { rtmpStream.GetServices().Range(func(key, val interface{}) bool {
ws := val.(*rtmp.Stream).GetWs() ws := val.(*rtmp.StreamService).GetWs()
ws.Range(func(k, v interface{}) bool { ws.Range(func(k, v interface{}) bool {
if pw, ok := v.(*rtmp.PackWriterCloser); ok { if pw, ok := v.(*rtmp.PackWriterCloser); ok {
if pw.GetWriter() != nil { if pw.GetWriter() != nil {

10
protocol/httpflv/server.go

@ -46,14 +46,14 @@ func (server *Server) Serve(l net.Listener) error {
// 获取发布和播放器的信息 // 获取发布和播放器的信息
func (server *Server) getStreams(w http.ResponseWriter, r *http.Request) *streams { func (server *Server) getStreams(w http.ResponseWriter, r *http.Request) *streams {
rtmpStream := server.handler.(*rtmp.RtmpStream) rtmpStream := server.handler.(*rtmp.StreamServer)
if rtmpStream == nil { if rtmpStream == nil {
return nil return nil
} }
msgs := new(streams) msgs := new(streams)
rtmpStream.GetStreams().Range(func(key, val interface{}) bool { rtmpStream.GetServices().Range(func(key, val interface{}) bool {
if s, ok := val.(*rtmp.Stream); ok { if s, ok := val.(*rtmp.StreamService); ok {
if s.GetReader() != nil { if s.GetReader() != nil {
msg := stream{key.(string), s.GetReader().Info().UID} msg := stream{key.(string), s.GetReader().Info().UID}
msgs.Publishers = append(msgs.Publishers, msg) msgs.Publishers = append(msgs.Publishers, msg)
@ -62,8 +62,8 @@ func (server *Server) getStreams(w http.ResponseWriter, r *http.Request) *stream
return true return true
}) })
rtmpStream.GetStreams().Range(func(key, val interface{}) bool { rtmpStream.GetServices().Range(func(key, val interface{}) bool {
ws := val.(*rtmp.Stream).GetWs() ws := val.(*rtmp.StreamService).GetWs()
ws.Range(func(k, v interface{}) bool { ws.Range(func(k, v interface{}) bool {
if pw, ok := v.(*rtmp.PackWriterCloser); ok { if pw, ok := v.(*rtmp.PackWriterCloser); ok {

138
protocol/rtmp/stream.go

@ -17,116 +17,134 @@ var (
EmptyID = "" EmptyID = ""
) )
type RtmpStream struct { // 流媒体服务器。包含N个流媒体服务。
streams *sync.Map //key // 每个单独的流媒体服务都可以有多种输入流,多个输出流。
type StreamServer struct {
services *sync.Map //key
} }
func NewRtmpStream() *RtmpStream { // 创建流媒体服务器。并启动状态监测协程。
ret := &RtmpStream{ func NewStreamServers() *StreamServer {
streams: &sync.Map{}, ss := &StreamServer{
services: &sync.Map{},
} }
go ret.CheckAlive() go ss.CheckAlive(5)
return ret return ss
} }
func (rs *RtmpStream) HandleReader(r av.ReadCloser) { // 注册源流处理逻辑。并启动源流读取。
// 若已有源流,则重新启动;否则创建流媒体服务。
func (ss *StreamServer) HandleReader(r av.ReadCloser) {
info := r.Info() info := r.Info()
log.Debugf("HandleReader: info[%v]", info) log.Debugf("HandleReader: info[%v]", info)
var stream *Stream var service *StreamService
i, ok := rs.streams.Load(info.Key) i, ok := ss.services.Load(info.Key)
if stream, ok = i.(*Stream); ok { if service, ok = i.(*StreamService); ok {
stream.TransStop() service.TransStop()
id := stream.ID() id := service.ID()
if id != EmptyID && id != info.UID { if id != EmptyID && id != info.UID {
ns := NewStream() ns := NewStreamService()
stream.Copy(ns) service.Copy(ns)
stream = ns service = ns
rs.streams.Store(info.Key, ns) ss.services.Store(info.Key, ns)
} }
} else { } else {
stream = NewStream() service = NewStreamService()
rs.streams.Store(info.Key, stream) ss.services.Store(info.Key, service)
stream.info = info service.info = info
} }
stream.AddReader(r) service.AddReader(r)
} }
func (rs *RtmpStream) HandleWriter(w av.WriteCloser) { // 注册目标流处理逻辑。
// 若没有则新创建流媒体服务;若有则新增流媒体服务writer。
func (ss *StreamServer) HandleWriter(w av.WriteCloser) {
info := w.Info() info := w.Info()
log.Debugf("HandleWriter: info[%v]", info) log.Debugf("HandleWriter: info[%v]", info)
var s *Stream var service *StreamService
item, ok := rs.streams.Load(info.Key) item, ok := ss.services.Load(info.Key)
if !ok { if !ok {
log.Debugf("HandleWriter: not found create new info[%v]", info) log.Debugf("HandleWriter: not found create new info[%v]", info)
s = NewStream() service = NewStreamService()
rs.streams.Store(info.Key, s) ss.services.Store(info.Key, service)
s.info = info service.info = info
} else { } else {
s = item.(*Stream) service = item.(*StreamService)
s.AddWriter(w) service.AddWriter(w)
} }
} }
func (rs *RtmpStream) GetStreams() *sync.Map { // 获取所有流媒体服务
return rs.streams func (ss *StreamServer) GetServices() *sync.Map {
return ss.services
}
// 定时遍历检测所有媒体服务器
func (ss *StreamServer) CheckAlive(ttl uint) {
if ttl <= 1 {
ttl = 1
} }
func (rs *RtmpStream) CheckAlive() {
for { for {
<-time.After(5 * time.Second) <-time.After(time.Duration(ttl) * time.Second)
rs.streams.Range(func(key, val interface{}) bool { ss.services.Range(func(key, val interface{}) bool {
v := val.(*Stream) v := val.(*StreamService)
if v.CheckAlive() == 0 { if v.CheckAlive() == 0 {
rs.streams.Delete(key) ss.services.Delete(key)
} }
return true return true
}) })
} }
} }
type Stream struct { // 流媒体服务结构信息
type StreamService struct {
isStart bool isStart bool
cache *cache.Cache info av.Info // 源流信息
r av.ReadCloser cache *cache.Cache // 源流视频数据
ws *sync.Map r av.ReadCloser // 读源流handler
info av.Info ws *sync.Map // 推流目标地址集合
} }
// 写流数据
type PackWriterCloser struct { type PackWriterCloser struct {
init bool init bool
w av.WriteCloser w av.WriteCloser // 写目标流handler
} }
func (p *PackWriterCloser) GetWriter() av.WriteCloser { func (p *PackWriterCloser) GetWriter() av.WriteCloser {
return p.w return p.w
} }
func NewStream() *Stream { // 实例化创建媒体服务。
return &Stream{ func NewStreamService() *StreamService {
return &StreamService{
cache: cache.NewCache(), cache: cache.NewCache(),
ws: &sync.Map{}, ws: &sync.Map{},
} }
} }
func (s *Stream) ID() string { func (s *StreamService) ID() string {
if s.r != nil { if s.r != nil {
return s.r.Info().UID return s.r.Info().UID
} }
return EmptyID return EmptyID
} }
func (s *Stream) GetReader() av.ReadCloser { func (s *StreamService) GetReader() av.ReadCloser {
return s.r return s.r
} }
func (s *Stream) GetWs() *sync.Map { func (s *StreamService) GetWs() *sync.Map {
return s.ws return s.ws
} }
func (s *Stream) Copy(dst *Stream) { // 复制流媒体服务。
func (s *StreamService) Copy(dst *StreamService) {
dst.info = s.info dst.info = s.info
s.ws.Range(func(key, val interface{}) bool { s.ws.Range(func(key, val interface{}) bool {
v := val.(*PackWriterCloser) v := val.(*PackWriterCloser)
@ -137,12 +155,13 @@ func (s *Stream) Copy(dst *Stream) {
}) })
} }
func (s *Stream) AddReader(r av.ReadCloser) { // 新增源流处理。并启动读取流数据协程。
func (s *StreamService) AddReader(r av.ReadCloser) {
s.r = r s.r = r
go s.TransStart() go s.TransStart()
} }
func (s *Stream) AddWriter(w av.WriteCloser) { func (s *StreamService) AddWriter(w av.WriteCloser) {
info := w.Info() info := w.Info()
pw := &PackWriterCloser{w: w} pw := &PackWriterCloser{w: w}
s.ws.Store(info.UID, pw) s.ws.Store(info.UID, pw)
@ -150,7 +169,7 @@ func (s *Stream) AddWriter(w av.WriteCloser) {
/*检测本application下是否配置static_push, /*检测本application下是否配置static_push,
如果配置, 启动push远端的连接*/ 如果配置, 启动push远端的连接*/
func (s *Stream) StartStaticPush() { func (s *StreamService) StartStaticPush() {
key := s.info.Key key := s.info.Key
dscr := strings.Split(key, "/") dscr := strings.Split(key, "/")
@ -190,7 +209,7 @@ func (s *Stream) StartStaticPush() {
} }
} }
func (s *Stream) StopStaticPush() { func (s *StreamService) StopStaticPush() {
key := s.info.Key key := s.info.Key
log.Debugf("StopStaticPush......%s", key) log.Debugf("StopStaticPush......%s", key)
@ -229,7 +248,7 @@ func (s *Stream) StopStaticPush() {
} }
} }
func (s *Stream) IsSendStaticPush() bool { func (s *StreamService) IsSendStaticPush() bool {
key := s.info.Key key := s.info.Key
dscr := strings.Split(key, "/") dscr := strings.Split(key, "/")
@ -269,7 +288,7 @@ func (s *Stream) IsSendStaticPush() bool {
return false return false
} }
func (s *Stream) SendStaticPush(packet av.Packet) { func (s *StreamService) SendStaticPush(packet av.Packet) {
key := s.info.Key key := s.info.Key
dscr := strings.Split(key, "/") dscr := strings.Split(key, "/")
@ -306,7 +325,8 @@ func (s *Stream) SendStaticPush(packet av.Packet) {
} }
} }
func (s *Stream) TransStart() { // 流媒体服务读取源流数据协程
func (s *StreamService) TransStart() {
s.isStart = true s.isStart = true
var p av.Packet var p av.Packet
@ -356,7 +376,8 @@ func (s *Stream) TransStart() {
} }
} }
func (s *Stream) TransStop() { // 停止读取源流,并重置状态。
func (s *StreamService) TransStop() {
log.Debugf("TransStop: %s", s.info.Key) log.Debugf("TransStop: %s", s.info.Key)
if s.isStart && s.r != nil { if s.isStart && s.r != nil {
@ -366,7 +387,8 @@ func (s *Stream) TransStop() {
s.isStart = false s.isStart = false
} }
func (s *Stream) CheckAlive() (n int) { // 检测某个媒体服务器状态
func (s *StreamService) CheckAlive() (n int) {
if s.r != nil && s.isStart { if s.r != nil && s.isStart {
if s.r.Alive() { if s.r.Alive() {
n++ n++
@ -393,7 +415,7 @@ func (s *Stream) CheckAlive() (n int) {
return return
} }
func (s *Stream) closeInter() { func (s *StreamService) closeInter() {
if s.r != nil { if s.r != nil {
s.StopStaticPush() s.StopStaticPush()
log.Debugf("[%v] publisher closed", s.r.Info()) log.Debugf("[%v] publisher closed", s.r.Info())

40
protocol/rtsp/rtsp.go

@ -0,0 +1,40 @@
package rtsp
import (
"net"
"net/http"
"github.com/gwuhaolin/livego/av"
)
type Server struct {
handler av.Handler
}
type stream struct {
Key string `json:"key"`
Id string `json:"id"`
}
type streams struct {
Publishers []stream `json:"publishers"`
Players []stream `json:"players"`
}
func NewServer(h av.Handler) *Server {
return &Server{
handler: h,
}
}
func (server *Server) Serve(l net.Listener) error {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
server.handleConn(w, r)
})
mux.HandleFunc("/streams", func(w http.ResponseWriter, r *http.Request) {
server.getStream(w, r)
})
http.Serve(l, mux)
return nil
}
Loading…
Cancel
Save