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