@@ -2,7 +2,6 @@ package engine
import (
"encoding/json"
"sort"
"strings"
"sync"
"time"
@@ -88,30 +87,6 @@ var StreamFSM = [len(StateNames)]map[StreamAction]StreamState{
// Streams 所有的流集合
var Streams util . Map [ string , * Stream ]
type StreamList [ ] * Stream
func ( l StreamList ) Len ( ) int {
return len ( l )
}
func ( l StreamList ) Less ( i , j int ) bool {
return l [ i ] . Path < l [ j ] . Path
}
func ( l StreamList ) Swap ( i , j int ) {
l [ i ] , l [ j ] = l [ j ] , l [ i ]
}
func ( l StreamList ) Sort ( ) {
sort . Sort ( l )
}
func GetSortedStreamList ( ) StreamList {
result := StreamList ( Streams . ToList ( ) )
result . Sort ( )
return result
}
func FilterStreams [ T IPublisher ] ( ) ( ss [ ] * Stream ) {
Streams . Range ( func ( _ string , s * Stream ) {
if _ , ok := s . Publisher . ( T ) ; ok {
@@ -350,14 +325,18 @@ func (r *Stream) action(action StreamAction) (ok bool) {
r . timeout . Reset ( r . DelayCloseTimeout )
}
case STATE_CLOSED :
Streams . Delete ( r . Path )
r . timeout . Stop ( )
r . Subscribers . Dispose ( )
for ! r . actionChan . Close ( ) {
// 等待channel发送完毕, 伪自旋锁
time . Sleep ( time . Millisecond * 100 )
}
stateEvent = SEclose { event }
r . Subscribers . Broadcast ( stateEvent )
Streams . Delete ( r . Path )
r . timeout . Stop ( )
r . Tracks . Range ( func ( _ string , t Track ) {
t . Dispose ( )
} )
}
EventBus <- stateEvent
if r . Publisher != nil {
@@ -494,140 +473,135 @@ func (s *Stream) run() {
s . action ( ACTION_TIMEOUT )
}
case action , ok := <- s . actionChan . C :
if ! ok {
return
}
timeStart = time . Now ( )
if ok {
switch v := action . ( type ) {
case SubPulse :
timeOutInfo = zap . String ( "action" , "SubPulse" )
pulseSuber [ v ] = struct { } { }
case * util . Promise [ I Publisher ] :
timeOutInfo = zap . String ( "action" , "Publish" )
if s . IsClosed( ) {
v . Reject ( ErrStreamIsClosed )
}
republish := s . Publisher = = v . Value // 重复发布
kicked := ! republish && s . Publisher != nil && s . Publisher . IsClosed ( ) // 被踢下线
if ! rep ublish {
s . Publisher = v . Value
}
if s . action ( ACTION_PUBLISH ) || republish || kicked {
v . Resolve ( )
if s . Publisher . GetPublisher ( ) . Config . InsertSEI {
if s . Tracks . SEI = = nil {
s . Tracks . SEI = track . NewDataTrack [ [ ] by te ] ( "sei" )
s . Tracks . SEI . Locker = & sync . Mutex { }
s . Tracks . SEI . SetStuff ( s )
if s . Tracks . Add ( "sei" , s . Tracks . SEI ) {
s . Info ( "sei track added" )
}
switch v := action . ( type ) {
case SubPulse :
timeOutInfo = zap . String ( "action" , " SubPulse" )
pulseSuber [ v ] = struct { } { }
case * util . Promise [ IPublisher ] :
timeOutInfo = zap . String ( "action" , " Publish" )
if s . IsClosed ( ) {
v . Reject ( ErrStream IsClosed)
}
republish := s . Publisher == v . Value // 重复发布
kicked := ! republish && s . Publisher ! = nil && s . Publisher . IsClosed ( ) // 被踢下线
if ! republish {
s . P ublisher = v . Value
}
if s . action ( ACTION_PUBLISH ) || republish || kicked {
v . Resolve ( )
if s . Publisher . GetPublisher ( ) . Config . InsertSEI {
if s . Tracks . SEI == nil {
s . Tracks . SEI = track . NewDataTrack [ [ ] byte ] ( "sei" )
s . Tracks . SEI . Locker = & sync . Mu tex { }
s . Tracks . SEI . SetStuff ( s )
if s . Tracks . Add ( "sei" , s . Tracks . SEI ) {
s . Info ( "sei track added" )
}
}
} else {
v . Reject ( ErrDuplicatePublish )
}
case * util . Promise [ ISubscriber ] :
timeOutInfo = zap . String ( "action" , "Subscribe" )
if s . IsClosed ( ) {
v . Reject ( ErrStreamIsClosed )
}
suber := v . Value
io := suber . GetSubscriber ( )
sbConfig := io . Config
waits := & waitTracks {
Promise : v ,
}
if ats := io . Args . Get ( sbConfig . SubAudioArgName ) ; ats != "" {
waits . audio . Wait ( strings . Split ( ats , "," ) ... )
} else if len ( sbConfig . SubAudioTracks ) > 0 {
waits . audio . Wait ( sbConfig . SubAudioTracks ... )
} else if sbConfig . SubAudio {
waits . audio . Wait ( )
}
if vts := io . Args . Get ( sbConfig . SubVideoArgName ) ; vts != "" {
waits . video . Wait ( strings . Split ( vts , "," ) ... )
} else if len ( sbConfig . SubVideoTracks ) > 0 {
waits . video . Wait ( sbConfig . SubVideoTracks ... )
} else if sbConfig . SubVideo {
waits . video . Wait ( )
}
if dts := io . Args . Get ( sbConfig . SubDataArgName ) ; dts != "" {
waits . data . Wait ( strings . Split ( dts , "," ) ... )
} else {
// waits.data.Wait()
}
if s . Publisher != nil {
s . Publisher . OnEvent ( v ) // 通知Publisher有新的订阅者加入, 在回调中可以去获取订阅者数量
pubConfig := s . Publisher . GetPublisher ( ) . Config
s . Tracks . Range ( func ( name string , t Track ) {
waits . Accept ( t )
} )
if ! pubConfig . PubAudio || s . Subscribers . waitAborted {
waits . audio . StopWait ( )
}
if ! pubConfig . PubVideo || s . Subscribers . waitAborted {
waits . video . StopWait ( )
}
}
s . Subscribers . Add ( suber , waits )
if s . Subscribers . Len ( ) == 1 && s . State == STATE_WAITCLOSE {
s . action ( ACTION_FIRSTENTER )
}
case Unsubscribe :
timeOutInfo = zap . String ( "action" , "Unsubscribe" )
delete ( pulseSuber , v )
s . onSuberClose ( v )
case TrackRemoved :
timeOutInfo = zap . String ( "action" , "TrackRemoved" )
name := v . GetName ( )
if t , ok := s . Tracks . LoadAndDelete ( name ) ; ok {
s . Info ( "track -1" , zap . String ( "name" , name ) )
s . Subscribers . Broadcast ( t )
t . ( common . Track ) . Dispose ( )
}
case * util . Promise [ Track ] :
timeOutInfo = zap . String ( "action" , "Track" )
if s . State == STATE_WAITPUBLISH {
s . action ( ACTION_PUBLISH )
}
pubConfig := s . GetPublisherConfig ( )
name := v . Value . GetName ( )
if _ , ok := v . Value . ( * track . Video ) ; ok && ! pubConfig . PubVideo {
v . Reject ( ErrTrackMute )
continue
}
if _ , ok := v . Value . ( * track . Audio ) ; ok && ! pubConfig . PubAudio {
v . Reject ( ErrTrackMute )
continue
}
if s . Tracks . Add ( name , v . Value ) {
v . Resolve ( )
s . Subscribers . OnTrack ( v . Value )
if _ , ok := v . Value . ( * track . Video ) ; ok && ! pubConfig . PubAudio {
s . Subscribers . AbortWait ( )
}
if _ , ok := v . Value . ( * track . Audio ) ; ok && ! pubConfig . PubVideo {
s . Subscribers . AbortWait ( )
}
// 这里重置的目的是当PublishTimeout设置很大的情况下, 需要及时取消订阅者的等待
s . timeout . Reset ( time . Second * 5 )
} else {
v . Reject ( ErrBadTrackName )
}
case NoMoreTrack :
s . Subscribers . AbortWait ( )
case StreamAction :
timeOutInfo = zap . String ( "action" , "StreamAction" + v . String ( ) )
s . action ( v )
default :
timeOutInfo = zap . String ( "action" , "unknown" )
s . Error ( "unknown action" , timeOutInfo )
} else {
v . Reject ( ErrDuplicatePublish )
}
} else {
s . Subscribers . Dispose ( )
s . Tracks . Range ( func ( _ string , t Track ) {
t . Dispose ( )
} )
return
case * util . Promise [ ISubscriber ] :
timeOutInfo = zap . String ( "action" , "Subscribe" )
if s . IsClosed ( ) {
v . Reject ( ErrStreamIsClosed )
}
suber := v . Value
io := suber . GetSubscriber ( )
sbConfig := io . Config
waits := & waitTracks {
Promise : v ,
}
if ats := io . Args . Get ( sbConfig . SubAudioArgName ) ; ats != "" {
waits . audio . Wait ( strings . Split ( ats , "," ) ... )
} else if len ( sbConfig . SubAudioTracks ) > 0 {
waits . audio . Wait ( sbConfig . SubAudioTracks ... )
} else if sbConfig . SubAudio {
waits . audio . Wait ( )
}
if vts := io . Args . Get ( sbConfig . SubVideoArgName ) ; vts != "" {
waits . video . Wait ( strings . Split ( vts , "," ) ... )
} else if len ( sbConfig . SubVideoTracks ) > 0 {
waits . video . Wait ( sbConfig . SubVideoTracks ... )
} else if sbConfig . SubVideo {
waits . video . Wait ( )
}
if dts := io . Args . Get ( sbConfig . SubDataArgName ) ; dts != "" {
waits . data . Wait ( strings . Split ( dts , "," ) ... )
} else {
// waits.data.Wait()
}
if s . Publisher != nil {
s . Publisher . OnEvent ( v ) // 通知Publisher有新的订阅者加入, 在回调中可以去获取订阅者数量
pubConfig := s . Publisher . GetPublisher ( ) . Config
s . Tracks . Range ( func ( name string , t Track ) {
waits . Accept ( t )
} )
if ! pubConfig . PubAudio || s . Subscribers . waitAborted {
waits . audio . StopWait ( )
}
if ! pubConfig . PubVideo || s . Subscribers . waitAborted {
waits . video . StopWait ( )
}
}
s . Subscribers . Add ( suber , waits )
if s . Subscribers . Len ( ) == 1 && s . State == STATE_WAITCLOSE {
s . action ( ACTION_FIRSTENTER )
}
case Unsubscribe :
timeOutInfo = zap . String ( "action" , "Unsubscribe" )
delete ( pulseSuber , v )
s . onSuberClose ( v )
case TrackRemoved :
timeOutInfo = zap . String ( "action" , "TrackRemoved" )
name := v . GetName ( )
if t , ok := s . Tracks . LoadAndDelete ( name ) ; ok {
s . Info ( "track -1" , zap . String ( "name" , name ) )
s . Subscribers . Broadcast ( t )
t . ( common . Track ) . Dispose ( )
}
case * util . Promise [ Track ] :
timeOutInfo = zap . String ( "action" , "Track" )
if s . State == STATE_WAITPUBLISH {
s . action ( ACTION_PUBLISH )
}
pubConfig := s . GetPublisherConfig ( )
name := v . Value . GetName ( )
if _ , ok := v . Value . ( * track . Video ) ; ok && ! pubConfig . PubVideo {
v . Reject ( ErrTrackMute )
continue
}
if _ , ok := v . Value . ( * track . Audio ) ; ok && ! pubConfig . PubAudio {
v . Reject ( ErrTrackMute )
continue
}
if s . Tracks . Add ( name , v . Value ) {
v . Resolve ( )
s . Subscribers . OnTrack ( v . Value )
if _ , ok := v . Value . ( * track . Video ) ; ok && ! pubConfig . PubAudio {
s . Subscribers . AbortWait ( )
}
if _ , ok := v . Value . ( * track . Audio ) ; ok && ! pubConfig . PubVideo {
s . Subscribers . AbortWait ( )
}
// 这里重置的目的是当PublishTimeout设置很大的情况下, 需要及时取消订阅者的等待
s . timeout . Reset ( time . Second * 5 )
} else {
v . Reject ( ErrBadTrackName )
}
case NoMoreTrack :
s . Subscribers . AbortWait ( )
case StreamAction :
timeOutInfo = zap . String ( "action" , "StreamAction" + v . String ( ) )
s . action ( v )
default :
timeOutInfo = zap . String ( "action" , "unknown" )
s . Error ( "unknown action" , timeOutInfo )
}
}
}