mirror of
				https://github.com/aler9/rtsp-simple-server
				synced 2025-11-01 03:22:50 +08:00 
			
		
		
		
	split readPublisher into reader and publisher
This commit is contained in:
		| @@ -165,17 +165,11 @@ func (r *hlsRemuxer) Close() { | |||||||
| 	r.ctxCancel() | 	r.ctxCancel() | ||||||
| } | } | ||||||
|  |  | ||||||
| // IsReadPublisher implements readPublisher. |  | ||||||
| func (r *hlsRemuxer) IsReadPublisher() {} |  | ||||||
|  |  | ||||||
| // IsSource implements source. |  | ||||||
| func (r *hlsRemuxer) IsSource() {} |  | ||||||
|  |  | ||||||
| func (r *hlsRemuxer) log(level logger.Level, format string, args ...interface{}) { | func (r *hlsRemuxer) log(level logger.Level, format string, args ...interface{}) { | ||||||
| 	r.parent.Log(level, "[remuxer %s] "+format, append([]interface{}{r.pathName}, args...)...) | 	r.parent.Log(level, "[remuxer %s] "+format, append([]interface{}{r.pathName}, args...)...) | ||||||
| } | } | ||||||
|  |  | ||||||
| // PathName returns the path name of the readPublisher | // PathName returns the path name. | ||||||
| func (r *hlsRemuxer) PathName() string { | func (r *hlsRemuxer) PathName() string { | ||||||
| 	return r.pathName | 	return r.pathName | ||||||
| } | } | ||||||
| @@ -203,15 +197,11 @@ func (r *hlsRemuxer) run() { | |||||||
|  |  | ||||||
| 	r.ctxCancel() | 	r.ctxCancel() | ||||||
|  |  | ||||||
| 	if r.path != nil { |  | ||||||
| 		r.path.OnReadPublisherRemove(readPublisherRemoveReq{Author: r}) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	r.parent.OnRemuxerClose(r) | 	r.parent.OnRemuxerClose(r) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (r *hlsRemuxer) runInner(innerCtx context.Context) error { | func (r *hlsRemuxer) runInner(innerCtx context.Context) error { | ||||||
| 	res := r.pathManager.OnReadPublisherSetupPlay(readPublisherSetupPlayReq{ | 	res := r.pathManager.OnReaderSetupPlay(pathReaderSetupPlayReq{ | ||||||
| 		Author:              r, | 		Author:              r, | ||||||
| 		PathName:            r.pathName, | 		PathName:            r.pathName, | ||||||
| 		IP:                  nil, | 		IP:                  nil, | ||||||
| @@ -223,6 +213,11 @@ func (r *hlsRemuxer) runInner(innerCtx context.Context) error { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	r.path = res.Path | 	r.path = res.Path | ||||||
|  |  | ||||||
|  | 	defer func() { | ||||||
|  | 		r.path.OnReaderRemove(pathReaderRemoveReq{Author: r}) | ||||||
|  | 	}() | ||||||
|  |  | ||||||
| 	var videoTrack *gortsplib.Track | 	var videoTrack *gortsplib.Track | ||||||
| 	videoTrackID := -1 | 	videoTrackID := -1 | ||||||
| 	var h264SPS []byte | 	var h264SPS []byte | ||||||
| @@ -300,7 +295,7 @@ func (r *hlsRemuxer) runInner(innerCtx context.Context) error { | |||||||
|  |  | ||||||
| 	r.ringBuffer = ringbuffer.New(uint64(r.readBufferCount)) | 	r.ringBuffer = ringbuffer.New(uint64(r.readBufferCount)) | ||||||
|  |  | ||||||
| 	r.path.OnReadPublisherPlay(readPublisherPlayReq{ | 	r.path.OnReaderPlay(pathReaderPlayReq{ | ||||||
| 		Author: r, | 		Author: r, | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| @@ -489,17 +484,13 @@ func (r *hlsRemuxer) OnRequest(req hlsRemuxerRequest) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // OnReaderAccepted implements readPublisher. | // OnReaderAccepted implements reader. | ||||||
| func (r *hlsRemuxer) OnReaderAccepted() { | func (r *hlsRemuxer) OnReaderAccepted() { | ||||||
| 	r.log(logger.Info, "is remuxing into HLS") | 	r.log(logger.Info, "is remuxing into HLS") | ||||||
| } | } | ||||||
|  |  | ||||||
| // OnPublisherAccepted implements readPublisher. | // OnReaderFrame implements reader. | ||||||
| func (r *hlsRemuxer) OnPublisherAccepted(tracksLen int) { | func (r *hlsRemuxer) OnReaderFrame(trackID int, streamType gortsplib.StreamType, payload []byte) { | ||||||
| } |  | ||||||
|  |  | ||||||
| // OnFrame implements readPublisher. |  | ||||||
| func (r *hlsRemuxer) OnFrame(trackID int, streamType gortsplib.StreamType, payload []byte) { |  | ||||||
| 	if streamType == gortsplib.StreamTypeRTP { | 	if streamType == gortsplib.StreamTypeRTP { | ||||||
| 		r.ringBuffer.Push(hlsRemuxerTrackIDPayloadPair{trackID, payload}) | 		r.ringBuffer.Push(hlsRemuxerTrackIDPayloadPair{trackID, payload}) | ||||||
| 	} | 	} | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -39,9 +39,9 @@ type pathManager struct { | |||||||
| 	confReload        chan map[string]*conf.PathConf | 	confReload        chan map[string]*conf.PathConf | ||||||
| 	pathClose         chan *path | 	pathClose         chan *path | ||||||
| 	pathSourceReady   chan *path | 	pathSourceReady   chan *path | ||||||
| 	rpDescribe      chan readPublisherDescribeReq | 	describe          chan pathDescribeReq | ||||||
| 	rpSetupPlay     chan readPublisherSetupPlayReq | 	readerSetupPlay   chan pathReaderSetupPlayReq | ||||||
| 	rpAnnounce      chan readPublisherAnnounceReq | 	publisherAnnounce chan pathPublisherAnnounceReq | ||||||
| 	hlsServerSet      chan *hlsServer | 	hlsServerSet      chan *hlsServer | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -74,9 +74,9 @@ func newPathManager( | |||||||
| 		confReload:        make(chan map[string]*conf.PathConf), | 		confReload:        make(chan map[string]*conf.PathConf), | ||||||
| 		pathClose:         make(chan *path), | 		pathClose:         make(chan *path), | ||||||
| 		pathSourceReady:   make(chan *path), | 		pathSourceReady:   make(chan *path), | ||||||
| 		rpDescribe:      make(chan readPublisherDescribeReq), | 		describe:          make(chan pathDescribeReq), | ||||||
| 		rpSetupPlay:     make(chan readPublisherSetupPlayReq), | 		readerSetupPlay:   make(chan pathReaderSetupPlayReq), | ||||||
| 		rpAnnounce:      make(chan readPublisherAnnounceReq), | 		publisherAnnounce: make(chan pathPublisherAnnounceReq), | ||||||
| 		hlsServerSet:      make(chan *hlsServer), | 		hlsServerSet:      make(chan *hlsServer), | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -150,10 +150,10 @@ outer: | |||||||
| 				pm.hlsServer.OnPathSourceReady(pa) | 				pm.hlsServer.OnPathSourceReady(pa) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 		case req := <-pm.rpDescribe: | 		case req := <-pm.describe: | ||||||
| 			pathName, pathConf, err := pm.findPathConf(req.PathName) | 			pathName, pathConf, err := pm.findPathConf(req.PathName) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				req.Res <- readPublisherDescribeRes{Err: err} | 				req.Res <- pathDescribeRes{Err: err} | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @@ -166,7 +166,7 @@ outer: | |||||||
| 				pathConf.ReadPass, | 				pathConf.ReadPass, | ||||||
| 			) | 			) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				req.Res <- readPublisherDescribeRes{Err: err} | 				req.Res <- pathDescribeRes{Err: err} | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @@ -175,12 +175,12 @@ outer: | |||||||
| 				pm.createPath(pathName, pathConf, req.PathName) | 				pm.createPath(pathName, pathConf, req.PathName) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			pm.paths[req.PathName].OnPathManDescribe(req) | 			pm.paths[req.PathName].OnDescribe(req) | ||||||
|  |  | ||||||
| 		case req := <-pm.rpSetupPlay: | 		case req := <-pm.readerSetupPlay: | ||||||
| 			pathName, pathConf, err := pm.findPathConf(req.PathName) | 			pathName, pathConf, err := pm.findPathConf(req.PathName) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				req.Res <- readPublisherSetupPlayRes{Err: err} | 				req.Res <- pathReaderSetupPlayRes{Err: err} | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @@ -193,7 +193,7 @@ outer: | |||||||
| 				pathConf.ReadPass, | 				pathConf.ReadPass, | ||||||
| 			) | 			) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				req.Res <- readPublisherSetupPlayRes{Err: err} | 				req.Res <- pathReaderSetupPlayRes{Err: err} | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @@ -202,12 +202,12 @@ outer: | |||||||
| 				pm.createPath(pathName, pathConf, req.PathName) | 				pm.createPath(pathName, pathConf, req.PathName) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			pm.paths[req.PathName].OnPathManSetupPlay(req) | 			pm.paths[req.PathName].OnReaderSetupPlay(req) | ||||||
|  |  | ||||||
| 		case req := <-pm.rpAnnounce: | 		case req := <-pm.publisherAnnounce: | ||||||
| 			pathName, pathConf, err := pm.findPathConf(req.PathName) | 			pathName, pathConf, err := pm.findPathConf(req.PathName) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				req.Res <- readPublisherAnnounceRes{Err: err} | 				req.Res <- pathPublisherAnnounceRes{Err: err} | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @@ -220,7 +220,7 @@ outer: | |||||||
| 				pathConf.PublishPass, | 				pathConf.PublishPass, | ||||||
| 			) | 			) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				req.Res <- readPublisherAnnounceRes{Err: err} | 				req.Res <- pathPublisherAnnounceRes{Err: err} | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @@ -229,7 +229,7 @@ outer: | |||||||
| 				pm.createPath(pathName, pathConf, req.PathName) | 				pm.createPath(pathName, pathConf, req.PathName) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			pm.paths[req.PathName].OnPathManAnnounce(req) | 			pm.paths[req.PathName].OnPublisherAnnounce(req) | ||||||
|  |  | ||||||
| 		case s := <-pm.hlsServerSet: | 		case s := <-pm.hlsServerSet: | ||||||
| 			pm.hlsServer = s | 			pm.hlsServer = s | ||||||
| @@ -298,7 +298,7 @@ func (pm *pathManager) authenticate( | |||||||
| 	// validate ip | 	// validate ip | ||||||
| 	if pathIPs != nil && ip != nil { | 	if pathIPs != nil && ip != nil { | ||||||
| 		if !ipEqualOrInRange(ip, pathIPs) { | 		if !ipEqualOrInRange(ip, pathIPs) { | ||||||
| 			return readPublisherErrAuthCritical{ | 			return pathErrAuthCritical{ | ||||||
| 				Message: fmt.Sprintf("IP '%s' not allowed", ip), | 				Message: fmt.Sprintf("IP '%s' not allowed", ip), | ||||||
| 				Response: &base.Response{ | 				Response: &base.Response{ | ||||||
| 					StatusCode: base.StatusUnauthorized, | 					StatusCode: base.StatusUnauthorized, | ||||||
| @@ -342,36 +342,36 @@ func (pm *pathManager) OnPathClose(pa *path) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // OnReadPublisherDescribe is called by a readPublisher. | // OnDescribe is called by a reader or publisher. | ||||||
| func (pm *pathManager) OnReadPublisherDescribe(req readPublisherDescribeReq) readPublisherDescribeRes { | func (pm *pathManager) OnDescribe(req pathDescribeReq) pathDescribeRes { | ||||||
| 	req.Res = make(chan readPublisherDescribeRes) | 	req.Res = make(chan pathDescribeRes) | ||||||
| 	select { | 	select { | ||||||
| 	case pm.rpDescribe <- req: | 	case pm.describe <- req: | ||||||
| 		return <-req.Res | 		return <-req.Res | ||||||
| 	case <-pm.ctx.Done(): | 	case <-pm.ctx.Done(): | ||||||
| 		return readPublisherDescribeRes{Err: fmt.Errorf("terminated")} | 		return pathDescribeRes{Err: fmt.Errorf("terminated")} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // OnReadPublisherAnnounce is called by a readPublisher. | // OnPublisherAnnounce is called by a publisher. | ||||||
| func (pm *pathManager) OnReadPublisherAnnounce(req readPublisherAnnounceReq) readPublisherAnnounceRes { | func (pm *pathManager) OnPublisherAnnounce(req pathPublisherAnnounceReq) pathPublisherAnnounceRes { | ||||||
| 	req.Res = make(chan readPublisherAnnounceRes) | 	req.Res = make(chan pathPublisherAnnounceRes) | ||||||
| 	select { | 	select { | ||||||
| 	case pm.rpAnnounce <- req: | 	case pm.publisherAnnounce <- req: | ||||||
| 		return <-req.Res | 		return <-req.Res | ||||||
| 	case <-pm.ctx.Done(): | 	case <-pm.ctx.Done(): | ||||||
| 		return readPublisherAnnounceRes{Err: fmt.Errorf("terminated")} | 		return pathPublisherAnnounceRes{Err: fmt.Errorf("terminated")} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // OnReadPublisherSetupPlay is called by a readPublisher. | // OnReaderSetupPlay is called by a reader. | ||||||
| func (pm *pathManager) OnReadPublisherSetupPlay(req readPublisherSetupPlayReq) readPublisherSetupPlayRes { | func (pm *pathManager) OnReaderSetupPlay(req pathReaderSetupPlayReq) pathReaderSetupPlayRes { | ||||||
| 	req.Res = make(chan readPublisherSetupPlayRes) | 	req.Res = make(chan pathReaderSetupPlayRes) | ||||||
| 	select { | 	select { | ||||||
| 	case pm.rpSetupPlay <- req: | 	case pm.readerSetupPlay <- req: | ||||||
| 		return <-req.Res | 		return <-req.Res | ||||||
| 	case <-pm.ctx.Done(): | 	case <-pm.ctx.Done(): | ||||||
| 		return readPublisherSetupPlayRes{Err: fmt.Errorf("terminated")} | 		return pathReaderSetupPlayRes{Err: fmt.Errorf("terminated")} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								internal/core/publisher.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								internal/core/publisher.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | package core | ||||||
|  |  | ||||||
|  | // publisher is an entity that can publish a stream dynamically. | ||||||
|  | type publisher interface { | ||||||
|  | 	source | ||||||
|  | 	Close() | ||||||
|  | 	OnPublisherAccepted(tracksLen int) | ||||||
|  | } | ||||||
| @@ -1,113 +0,0 @@ | |||||||
| package core |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"net" |  | ||||||
|  |  | ||||||
| 	"github.com/aler9/gortsplib" |  | ||||||
| 	"github.com/aler9/gortsplib/pkg/base" |  | ||||||
| 	"github.com/aler9/gortsplib/pkg/headers" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type readPublisherErrNoOnePublishing struct { |  | ||||||
| 	PathName string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Error implements the error interface. |  | ||||||
| func (e readPublisherErrNoOnePublishing) Error() string { |  | ||||||
| 	return fmt.Sprintf("no one is publishing to path '%s'", e.PathName) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisherErrAuthNotCritical struct { |  | ||||||
| 	*base.Response |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Error implements the error interface. |  | ||||||
| func (readPublisherErrAuthNotCritical) Error() string { |  | ||||||
| 	return "non-critical authentication error" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisherErrAuthCritical struct { |  | ||||||
| 	Message  string |  | ||||||
| 	Response *base.Response |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Error implements the error interface. |  | ||||||
| func (readPublisherErrAuthCritical) Error() string { |  | ||||||
| 	return "critical authentication error" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisher interface { |  | ||||||
| 	IsReadPublisher() |  | ||||||
| 	IsSource() |  | ||||||
| 	Close() |  | ||||||
| 	OnReaderAccepted() |  | ||||||
| 	OnPublisherAccepted(tracksLen int) |  | ||||||
| 	OnFrame(int, gortsplib.StreamType, []byte) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisherDescribeRes struct { |  | ||||||
| 	Stream   *gortsplib.ServerStream |  | ||||||
| 	Redirect string |  | ||||||
| 	Err      error |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisherDescribeReq struct { |  | ||||||
| 	PathName            string |  | ||||||
| 	URL                 *base.URL |  | ||||||
| 	IP                  net.IP |  | ||||||
| 	ValidateCredentials func(authMethods []headers.AuthMethod, pathUser string, pathPass string) error |  | ||||||
| 	Res                 chan readPublisherDescribeRes |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisherSetupPlayRes struct { |  | ||||||
| 	Path   *path |  | ||||||
| 	Stream *gortsplib.ServerStream |  | ||||||
| 	Err    error |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisherSetupPlayReq struct { |  | ||||||
| 	Author              readPublisher |  | ||||||
| 	PathName            string |  | ||||||
| 	IP                  net.IP |  | ||||||
| 	ValidateCredentials func(authMethods []headers.AuthMethod, pathUser string, pathPass string) error |  | ||||||
| 	Res                 chan readPublisherSetupPlayRes |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisherAnnounceRes struct { |  | ||||||
| 	Path *path |  | ||||||
| 	Err  error |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisherAnnounceReq struct { |  | ||||||
| 	Author              readPublisher |  | ||||||
| 	PathName            string |  | ||||||
| 	Tracks              gortsplib.Tracks |  | ||||||
| 	IP                  net.IP |  | ||||||
| 	ValidateCredentials func(authMethods []headers.AuthMethod, pathUser string, pathPass string) error |  | ||||||
| 	Res                 chan readPublisherAnnounceRes |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisherRemoveReq struct { |  | ||||||
| 	Author readPublisher |  | ||||||
| 	Res    chan struct{} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisherPlayReq struct { |  | ||||||
| 	Author readPublisher |  | ||||||
| 	Res    chan struct{} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisherRecordRes struct { |  | ||||||
| 	Err error |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisherRecordReq struct { |  | ||||||
| 	Author readPublisher |  | ||||||
| 	Res    chan readPublisherRecordRes |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type readPublisherPauseReq struct { |  | ||||||
| 	Author readPublisher |  | ||||||
| 	Res    chan struct{} |  | ||||||
| } |  | ||||||
							
								
								
									
										12
									
								
								internal/core/reader.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								internal/core/reader.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | package core | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"github.com/aler9/gortsplib" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // reader is an entity that can read a stream. | ||||||
|  | type reader interface { | ||||||
|  | 	Close() | ||||||
|  | 	OnReaderAccepted() | ||||||
|  | 	OnReaderFrame(int, gortsplib.StreamType, []byte) | ||||||
|  | } | ||||||
| @@ -121,9 +121,6 @@ func (c *rtmpConn) Close() { | |||||||
| 	c.ctxCancel() | 	c.ctxCancel() | ||||||
| } | } | ||||||
|  |  | ||||||
| // IsReadPublisher implements readPublisher. |  | ||||||
| func (c *rtmpConn) IsReadPublisher() {} |  | ||||||
|  |  | ||||||
| // IsSource implements source. | // IsSource implements source. | ||||||
| func (c *rtmpConn) IsSource() {} | func (c *rtmpConn) IsSource() {} | ||||||
|  |  | ||||||
| @@ -168,10 +165,6 @@ func (c *rtmpConn) run() { | |||||||
|  |  | ||||||
| 	c.ctxCancel() | 	c.ctxCancel() | ||||||
|  |  | ||||||
| 	if c.path != nil { |  | ||||||
| 		c.path.OnReadPublisherRemove(readPublisherRemoveReq{Author: c}) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	c.parent.OnConnClose(c) | 	c.parent.OnConnClose(c) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -197,7 +190,7 @@ func (c *rtmpConn) runInner(ctx context.Context) error { | |||||||
| func (c *rtmpConn) runRead(ctx context.Context) error { | func (c *rtmpConn) runRead(ctx context.Context) error { | ||||||
| 	pathName, query := pathNameAndQuery(c.conn.URL()) | 	pathName, query := pathNameAndQuery(c.conn.URL()) | ||||||
|  |  | ||||||
| 	res := c.pathManager.OnReadPublisherSetupPlay(readPublisherSetupPlayReq{ | 	res := c.pathManager.OnReaderSetupPlay(pathReaderSetupPlayReq{ | ||||||
| 		Author:   c, | 		Author:   c, | ||||||
| 		PathName: pathName, | 		PathName: pathName, | ||||||
| 		IP:       c.ip(), | 		IP:       c.ip(), | ||||||
| @@ -207,7 +200,7 @@ func (c *rtmpConn) runRead(ctx context.Context) error { | |||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	if res.Err != nil { | 	if res.Err != nil { | ||||||
| 		if terr, ok := res.Err.(readPublisherErrAuthCritical); ok { | 		if terr, ok := res.Err.(pathErrAuthCritical); ok { | ||||||
| 			// wait some seconds to stop brute force attacks | 			// wait some seconds to stop brute force attacks | ||||||
| 			<-time.After(rtmpConnPauseAfterAuthError) | 			<-time.After(rtmpConnPauseAfterAuthError) | ||||||
| 			return errors.New(terr.Message) | 			return errors.New(terr.Message) | ||||||
| @@ -217,6 +210,10 @@ func (c *rtmpConn) runRead(ctx context.Context) error { | |||||||
|  |  | ||||||
| 	c.path = res.Path | 	c.path = res.Path | ||||||
|  |  | ||||||
|  | 	defer func() { | ||||||
|  | 		c.path.OnReaderRemove(pathReaderRemoveReq{Author: c}) | ||||||
|  | 	}() | ||||||
|  |  | ||||||
| 	var videoTrack *gortsplib.Track | 	var videoTrack *gortsplib.Track | ||||||
| 	videoTrackID := -1 | 	videoTrackID := -1 | ||||||
| 	var h264Decoder *rtph264.Decoder | 	var h264Decoder *rtph264.Decoder | ||||||
| @@ -261,7 +258,7 @@ func (c *rtmpConn) runRead(ctx context.Context) error { | |||||||
| 		c.ringBuffer.Close() | 		c.ringBuffer.Close() | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| 	c.path.OnReadPublisherPlay(readPublisherPlayReq{ | 	c.path.OnReaderPlay(pathReaderPlayReq{ | ||||||
| 		Author: c, | 		Author: c, | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| @@ -389,7 +386,7 @@ func (c *rtmpConn) runPublish(ctx context.Context) error { | |||||||
|  |  | ||||||
| 	pathName, query := pathNameAndQuery(c.conn.URL()) | 	pathName, query := pathNameAndQuery(c.conn.URL()) | ||||||
|  |  | ||||||
| 	res := c.pathManager.OnReadPublisherAnnounce(readPublisherAnnounceReq{ | 	res := c.pathManager.OnPublisherAnnounce(pathPublisherAnnounceReq{ | ||||||
| 		Author:   c, | 		Author:   c, | ||||||
| 		PathName: pathName, | 		PathName: pathName, | ||||||
| 		Tracks:   tracks, | 		Tracks:   tracks, | ||||||
| @@ -400,7 +397,7 @@ func (c *rtmpConn) runPublish(ctx context.Context) error { | |||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	if res.Err != nil { | 	if res.Err != nil { | ||||||
| 		if terr, ok := res.Err.(readPublisherErrAuthCritical); ok { | 		if terr, ok := res.Err.(pathErrAuthCritical); ok { | ||||||
| 			// wait some seconds to stop brute force attacks | 			// wait some seconds to stop brute force attacks | ||||||
| 			<-time.After(rtmpConnPauseAfterAuthError) | 			<-time.After(rtmpConnPauseAfterAuthError) | ||||||
| 			return errors.New(terr.Message) | 			return errors.New(terr.Message) | ||||||
| @@ -410,10 +407,14 @@ func (c *rtmpConn) runPublish(ctx context.Context) error { | |||||||
|  |  | ||||||
| 	c.path = res.Path | 	c.path = res.Path | ||||||
|  |  | ||||||
|  | 	defer func() { | ||||||
|  | 		c.path.OnPublisherRemove(pathPublisherRemoveReq{Author: c}) | ||||||
|  | 	}() | ||||||
|  |  | ||||||
| 	// disable write deadline | 	// disable write deadline | ||||||
| 	c.conn.NetConn().SetWriteDeadline(time.Time{}) | 	c.conn.NetConn().SetWriteDeadline(time.Time{}) | ||||||
|  |  | ||||||
| 	rres := c.path.OnReadPublisherRecord(readPublisherRecordReq{Author: c}) | 	rres := c.path.OnPublisherRecord(pathPublisherRecordReq{Author: c}) | ||||||
| 	if rres.Err != nil { | 	if rres.Err != nil { | ||||||
| 		return rres.Err | 		return rres.Err | ||||||
| 	} | 	} | ||||||
| @@ -497,7 +498,7 @@ func (c *rtmpConn) validateCredentials( | |||||||
| ) error { | ) error { | ||||||
| 	if query.Get("user") != pathUser || | 	if query.Get("user") != pathUser || | ||||||
| 		query.Get("pass") != pathPass { | 		query.Get("pass") != pathPass { | ||||||
| 		return readPublisherErrAuthCritical{ | 		return pathErrAuthCritical{ | ||||||
| 			Message: "wrong username or password", | 			Message: "wrong username or password", | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -505,12 +506,19 @@ func (c *rtmpConn) validateCredentials( | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // OnReaderAccepted implements readPublisher. | // OnReaderAccepted implements reader. | ||||||
| func (c *rtmpConn) OnReaderAccepted() { | func (c *rtmpConn) OnReaderAccepted() { | ||||||
| 	c.log(logger.Info, "is reading from path '%s'", c.path.Name()) | 	c.log(logger.Info, "is reading from path '%s'", c.path.Name()) | ||||||
| } | } | ||||||
|  |  | ||||||
| // OnPublisherAccepted implements readPublisher. | // OnReaderFrame implements reader. | ||||||
|  | func (c *rtmpConn) OnReaderFrame(trackID int, streamType gortsplib.StreamType, payload []byte) { | ||||||
|  | 	if streamType == gortsplib.StreamTypeRTP { | ||||||
|  | 		c.ringBuffer.Push(rtmpConnTrackIDPayloadPair{trackID, payload}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // OnPublisherAccepted implements publisher. | ||||||
| func (c *rtmpConn) OnPublisherAccepted(tracksLen int) { | func (c *rtmpConn) OnPublisherAccepted(tracksLen int) { | ||||||
| 	c.log(logger.Info, "is publishing to path '%s', %d %s", | 	c.log(logger.Info, "is publishing to path '%s', %d %s", | ||||||
| 		c.path.Name(), | 		c.path.Name(), | ||||||
| @@ -522,10 +530,3 @@ func (c *rtmpConn) OnPublisherAccepted(tracksLen int) { | |||||||
| 			return "tracks" | 			return "tracks" | ||||||
| 		}()) | 		}()) | ||||||
| } | } | ||||||
|  |  | ||||||
| // OnFrame implements readPublisher. |  | ||||||
| func (c *rtmpConn) OnFrame(trackID int, streamType gortsplib.StreamType, payload []byte) { |  | ||||||
| 	if streamType == gortsplib.StreamTypeRTP { |  | ||||||
| 		c.ringBuffer.Push(rtmpConnTrackIDPayloadPair{trackID, payload}) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -24,8 +24,8 @@ const ( | |||||||
|  |  | ||||||
| type rtmpSourceParent interface { | type rtmpSourceParent interface { | ||||||
| 	Log(logger.Level, string, ...interface{}) | 	Log(logger.Level, string, ...interface{}) | ||||||
| 	OnSourceExternalSetReady(req sourceExtSetReadyReq) | 	OnSourceStaticSetReady(req pathSourceStaticSetReadyReq) | ||||||
| 	OnSourceExternalSetNotReady(req sourceExtSetNotReadyReq) | 	OnSourceStaticSetNotReady(req pathSourceStaticSetNotReadyReq) | ||||||
| 	OnSourceFrame(int, gortsplib.StreamType, []byte) | 	OnSourceFrame(int, gortsplib.StreamType, []byte) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -81,8 +81,8 @@ func (s *rtmpSource) Close() { | |||||||
| // IsSource implements source. | // IsSource implements source. | ||||||
| func (s *rtmpSource) IsSource() {} | func (s *rtmpSource) IsSource() {} | ||||||
|  |  | ||||||
| // IsSourceExternal implements sourceExternal. | // IsSourceStatic implements sourceStatic. | ||||||
| func (s *rtmpSource) IsSourceExternal() {} | func (s *rtmpSource) IsSourceStatic() {} | ||||||
|  |  | ||||||
| func (s *rtmpSource) log(level logger.Level, format string, args ...interface{}) { | func (s *rtmpSource) log(level logger.Level, format string, args ...interface{}) { | ||||||
| 	s.parent.Log(level, "[rtmp source] "+format, args...) | 	s.parent.Log(level, "[rtmp source] "+format, args...) | ||||||
| @@ -168,12 +168,12 @@ func (s *rtmpSource) runInner() bool { | |||||||
|  |  | ||||||
| 					s.log(logger.Info, "ready") | 					s.log(logger.Info, "ready") | ||||||
|  |  | ||||||
| 					s.parent.OnSourceExternalSetReady(sourceExtSetReadyReq{ | 					s.parent.OnSourceStaticSetReady(pathSourceStaticSetReadyReq{ | ||||||
| 						Tracks: tracks, | 						Tracks: tracks, | ||||||
| 					}) | 					}) | ||||||
|  |  | ||||||
| 					defer func() { | 					defer func() { | ||||||
| 						s.parent.OnSourceExternalSetNotReady(sourceExtSetNotReadyReq{}) | 						s.parent.OnSourceStaticSetNotReady(pathSourceStaticSetNotReadyReq{}) | ||||||
| 					}() | 					}() | ||||||
|  |  | ||||||
| 					rtcpSenders := rtcpsenderset.New(tracks, s.parent.OnSourceFrame) | 					rtcpSenders := rtcpsenderset.New(tracks, s.parent.OnSourceFrame) | ||||||
|   | |||||||
| @@ -148,7 +148,7 @@ func (c *rtspConn) validateCredentials( | |||||||
| 		// 4) with password and username | 		// 4) with password and username | ||||||
| 		// therefore we must allow up to 3 failures | 		// therefore we must allow up to 3 failures | ||||||
| 		if c.authFailures > 3 { | 		if c.authFailures > 3 { | ||||||
| 			return readPublisherErrAuthCritical{ | 			return pathErrAuthCritical{ | ||||||
| 				Message: "unauthorized: " + err.Error(), | 				Message: "unauthorized: " + err.Error(), | ||||||
| 				Response: &base.Response{ | 				Response: &base.Response{ | ||||||
| 					StatusCode: base.StatusUnauthorized, | 					StatusCode: base.StatusUnauthorized, | ||||||
| @@ -160,7 +160,7 @@ func (c *rtspConn) validateCredentials( | |||||||
| 			c.log(logger.Debug, "WARN: unauthorized: %s", err) | 			c.log(logger.Debug, "WARN: unauthorized: %s", err) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		return readPublisherErrAuthNotCritical{ | 		return pathErrAuthNotCritical{ | ||||||
| 			Response: &base.Response{ | 			Response: &base.Response{ | ||||||
| 				StatusCode: base.StatusUnauthorized, | 				StatusCode: base.StatusUnauthorized, | ||||||
| 				Header: base.Header{ | 				Header: base.Header{ | ||||||
| @@ -188,7 +188,7 @@ func (c *rtspConn) OnResponse(res *base.Response) { | |||||||
|  |  | ||||||
| // OnDescribe is called by rtspServer. | // OnDescribe is called by rtspServer. | ||||||
| func (c *rtspConn) OnDescribe(ctx *gortsplib.ServerHandlerOnDescribeCtx) (*base.Response, *gortsplib.ServerStream, error) { | func (c *rtspConn) OnDescribe(ctx *gortsplib.ServerHandlerOnDescribeCtx) (*base.Response, *gortsplib.ServerStream, error) { | ||||||
| 	res := c.pathManager.OnReadPublisherDescribe(readPublisherDescribeReq{ | 	res := c.pathManager.OnDescribe(pathDescribeReq{ | ||||||
| 		PathName: ctx.Path, | 		PathName: ctx.Path, | ||||||
| 		URL:      ctx.Req.URL, | 		URL:      ctx.Req.URL, | ||||||
| 		IP:       c.ip(), | 		IP:       c.ip(), | ||||||
| @@ -199,16 +199,16 @@ func (c *rtspConn) OnDescribe(ctx *gortsplib.ServerHandlerOnDescribeCtx) (*base. | |||||||
|  |  | ||||||
| 	if res.Err != nil { | 	if res.Err != nil { | ||||||
| 		switch terr := res.Err.(type) { | 		switch terr := res.Err.(type) { | ||||||
| 		case readPublisherErrAuthNotCritical: | 		case pathErrAuthNotCritical: | ||||||
| 			return terr.Response, nil, nil | 			return terr.Response, nil, nil | ||||||
|  |  | ||||||
| 		case readPublisherErrAuthCritical: | 		case pathErrAuthCritical: | ||||||
| 			// wait some seconds to stop brute force attacks | 			// wait some seconds to stop brute force attacks | ||||||
| 			<-time.After(rtspConnPauseAfterAuthError) | 			<-time.After(rtspConnPauseAfterAuthError) | ||||||
|  |  | ||||||
| 			return terr.Response, nil, errors.New(terr.Message) | 			return terr.Response, nil, errors.New(terr.Message) | ||||||
|  |  | ||||||
| 		case readPublisherErrNoOnePublishing: | 		case pathErrNoOnePublishing: | ||||||
| 			return &base.Response{ | 			return &base.Response{ | ||||||
| 				StatusCode: base.StatusNotFound, | 				StatusCode: base.StatusNotFound, | ||||||
| 			}, nil, res.Err | 			}, nil, res.Err | ||||||
|   | |||||||
| @@ -66,8 +66,13 @@ func (s *rtspSession) ParentClose() { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if s.path != nil { | 	switch s.ss.State() { | ||||||
| 		s.path.OnReadPublisherRemove(readPublisherRemoveReq{Author: s}) | 	case gortsplib.ServerSessionStatePrePlay, gortsplib.ServerSessionStatePlay: | ||||||
|  | 		s.path.OnReaderRemove(pathReaderRemoveReq{Author: s}) | ||||||
|  | 		s.path = nil | ||||||
|  |  | ||||||
|  | 	case gortsplib.ServerSessionStatePreRecord, gortsplib.ServerSessionStateRecord: | ||||||
|  | 		s.path.OnPublisherRemove(pathPublisherRemoveReq{Author: s}) | ||||||
| 		s.path = nil | 		s.path = nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -79,13 +84,10 @@ func (s *rtspSession) Close() { | |||||||
| 	s.ss.Close() | 	s.ss.Close() | ||||||
| } | } | ||||||
|  |  | ||||||
| // IsReadPublisher implements readPublisher. |  | ||||||
| func (s *rtspSession) IsReadPublisher() {} |  | ||||||
|  |  | ||||||
| // IsSource implements source. | // IsSource implements source. | ||||||
| func (s *rtspSession) IsSource() {} | func (s *rtspSession) IsSource() {} | ||||||
|  |  | ||||||
| // IsRTSPSession implements path.rtspSession. | // IsRTSPSession implements pathRTSPSession. | ||||||
| func (s *rtspSession) IsRTSPSession() {} | func (s *rtspSession) IsRTSPSession() {} | ||||||
|  |  | ||||||
| // VisualID returns the visual ID of the session. | // VisualID returns the visual ID of the session. | ||||||
| @@ -106,7 +108,7 @@ func (s *rtspSession) log(level logger.Level, format string, args ...interface{} | |||||||
|  |  | ||||||
| // OnAnnounce is called by rtspServer. | // OnAnnounce is called by rtspServer. | ||||||
| func (s *rtspSession) OnAnnounce(c *rtspConn, ctx *gortsplib.ServerHandlerOnAnnounceCtx) (*base.Response, error) { | func (s *rtspSession) OnAnnounce(c *rtspConn, ctx *gortsplib.ServerHandlerOnAnnounceCtx) (*base.Response, error) { | ||||||
| 	res := s.pathManager.OnReadPublisherAnnounce(readPublisherAnnounceReq{ | 	res := s.pathManager.OnPublisherAnnounce(pathPublisherAnnounceReq{ | ||||||
| 		Author:   s, | 		Author:   s, | ||||||
| 		PathName: ctx.Path, | 		PathName: ctx.Path, | ||||||
| 		Tracks:   ctx.Tracks, | 		Tracks:   ctx.Tracks, | ||||||
| @@ -118,10 +120,10 @@ func (s *rtspSession) OnAnnounce(c *rtspConn, ctx *gortsplib.ServerHandlerOnAnno | |||||||
|  |  | ||||||
| 	if res.Err != nil { | 	if res.Err != nil { | ||||||
| 		switch terr := res.Err.(type) { | 		switch terr := res.Err.(type) { | ||||||
| 		case readPublisherErrAuthNotCritical: | 		case pathErrAuthNotCritical: | ||||||
| 			return terr.Response, nil | 			return terr.Response, nil | ||||||
|  |  | ||||||
| 		case readPublisherErrAuthCritical: | 		case pathErrAuthCritical: | ||||||
| 			// wait some seconds to stop brute force attacks | 			// wait some seconds to stop brute force attacks | ||||||
| 			<-time.After(pauseAfterAuthError) | 			<-time.After(pauseAfterAuthError) | ||||||
|  |  | ||||||
| @@ -165,7 +167,7 @@ func (s *rtspSession) OnSetup(c *rtspConn, ctx *gortsplib.ServerHandlerOnSetupCt | |||||||
|  |  | ||||||
| 	switch s.ss.State() { | 	switch s.ss.State() { | ||||||
| 	case gortsplib.ServerSessionStateInitial, gortsplib.ServerSessionStatePrePlay: // play | 	case gortsplib.ServerSessionStateInitial, gortsplib.ServerSessionStatePrePlay: // play | ||||||
| 		res := s.pathManager.OnReadPublisherSetupPlay(readPublisherSetupPlayReq{ | 		res := s.pathManager.OnReaderSetupPlay(pathReaderSetupPlayReq{ | ||||||
| 			Author:   s, | 			Author:   s, | ||||||
| 			PathName: ctx.Path, | 			PathName: ctx.Path, | ||||||
| 			IP:       ctx.Conn.NetConn().RemoteAddr().(*net.TCPAddr).IP, | 			IP:       ctx.Conn.NetConn().RemoteAddr().(*net.TCPAddr).IP, | ||||||
| @@ -176,16 +178,16 @@ func (s *rtspSession) OnSetup(c *rtspConn, ctx *gortsplib.ServerHandlerOnSetupCt | |||||||
|  |  | ||||||
| 		if res.Err != nil { | 		if res.Err != nil { | ||||||
| 			switch terr := res.Err.(type) { | 			switch terr := res.Err.(type) { | ||||||
| 			case readPublisherErrAuthNotCritical: | 			case pathErrAuthNotCritical: | ||||||
| 				return terr.Response, nil, nil | 				return terr.Response, nil, nil | ||||||
|  |  | ||||||
| 			case readPublisherErrAuthCritical: | 			case pathErrAuthCritical: | ||||||
| 				// wait some seconds to stop brute force attacks | 				// wait some seconds to stop brute force attacks | ||||||
| 				<-time.After(pauseAfterAuthError) | 				<-time.After(pauseAfterAuthError) | ||||||
|  |  | ||||||
| 				return terr.Response, nil, errors.New(terr.Message) | 				return terr.Response, nil, errors.New(terr.Message) | ||||||
|  |  | ||||||
| 			case readPublisherErrNoOnePublishing: | 			case pathErrNoOnePublishing: | ||||||
| 				return &base.Response{ | 				return &base.Response{ | ||||||
| 					StatusCode: base.StatusNotFound, | 					StatusCode: base.StatusNotFound, | ||||||
| 				}, nil, res.Err | 				}, nil, res.Err | ||||||
| @@ -232,9 +234,7 @@ func (s *rtspSession) OnPlay(ctx *gortsplib.ServerHandlerOnPlayCtx) (*base.Respo | |||||||
| 			}, fmt.Errorf("path has changed, was '%s', now is '%s'", s.path.Name(), ctx.Path) | 			}, fmt.Errorf("path has changed, was '%s', now is '%s'", s.path.Name(), ctx.Path) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		s.path.OnReadPublisherPlay(readPublisherPlayReq{ | 		s.path.OnReaderPlay(pathReaderPlayReq{Author: s}) | ||||||
| 			Author: s, |  | ||||||
| 		}) |  | ||||||
|  |  | ||||||
| 		if s.path.Conf().RunOnRead != "" { | 		if s.path.Conf().RunOnRead != "" { | ||||||
| 			_, port, _ := net.SplitHostPort(s.rtspAddress) | 			_, port, _ := net.SplitHostPort(s.rtspAddress) | ||||||
| @@ -259,7 +259,7 @@ func (s *rtspSession) OnRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.R | |||||||
| 		}, fmt.Errorf("path has changed, was '%s', now is '%s'", s.path.Name(), ctx.Path) | 		}, fmt.Errorf("path has changed, was '%s', now is '%s'", s.path.Name(), ctx.Path) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	res := s.path.OnReadPublisherRecord(readPublisherRecordReq{Author: s}) | 	res := s.path.OnPublisherRecord(pathPublisherRecordReq{Author: s}) | ||||||
| 	if res.Err != nil { | 	if res.Err != nil { | ||||||
| 		return &base.Response{ | 		return &base.Response{ | ||||||
| 			StatusCode: base.StatusBadRequest, | 			StatusCode: base.StatusBadRequest, | ||||||
| @@ -279,10 +279,10 @@ func (s *rtspSession) OnPause(ctx *gortsplib.ServerHandlerOnPauseCtx) (*base.Res | |||||||
| 			s.onReadCmd.Close() | 			s.onReadCmd.Close() | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		s.path.OnReadPublisherPause(readPublisherPauseReq{Author: s}) | 		s.path.OnReaderPause(pathReaderPauseReq{Author: s}) | ||||||
|  |  | ||||||
| 	case gortsplib.ServerSessionStateRecord: | 	case gortsplib.ServerSessionStateRecord: | ||||||
| 		s.path.OnReadPublisherPause(readPublisherPauseReq{Author: s}) | 		s.path.OnPublisherPause(pathPublisherPauseReq{Author: s}) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return &base.Response{ | 	return &base.Response{ | ||||||
| @@ -290,7 +290,7 @@ func (s *rtspSession) OnPause(ctx *gortsplib.ServerHandlerOnPauseCtx) (*base.Res | |||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // OnReaderAccepted implements readPublisher. | // OnReaderAccepted implements reader. | ||||||
| func (s *rtspSession) OnReaderAccepted() { | func (s *rtspSession) OnReaderAccepted() { | ||||||
| 	tracksLen := len(s.ss.SetuppedTracks()) | 	tracksLen := len(s.ss.SetuppedTracks()) | ||||||
|  |  | ||||||
| @@ -306,7 +306,12 @@ func (s *rtspSession) OnReaderAccepted() { | |||||||
| 		s.displayedProtocol()) | 		s.displayedProtocol()) | ||||||
| } | } | ||||||
|  |  | ||||||
| // OnPublisherAccepted implements readPublisher. | // OnReaderFrame implements reader. | ||||||
|  | func (s *rtspSession) OnReaderFrame(trackID int, streamType gortsplib.StreamType, payload []byte) { | ||||||
|  | 	s.ss.WriteFrame(trackID, streamType, payload) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // OnPublisherAccepted implements publisher. | ||||||
| func (s *rtspSession) OnPublisherAccepted(tracksLen int) { | func (s *rtspSession) OnPublisherAccepted(tracksLen int) { | ||||||
| 	s.log(logger.Info, "is publishing to path '%s', %d %s with %s", | 	s.log(logger.Info, "is publishing to path '%s', %d %s with %s", | ||||||
| 		s.path.Name(), | 		s.path.Name(), | ||||||
| @@ -320,11 +325,6 @@ func (s *rtspSession) OnPublisherAccepted(tracksLen int) { | |||||||
| 		s.displayedProtocol()) | 		s.displayedProtocol()) | ||||||
| } | } | ||||||
|  |  | ||||||
| // OnFrame implements readPublisher. |  | ||||||
| func (s *rtspSession) OnFrame(trackID int, streamType gortsplib.StreamType, payload []byte) { |  | ||||||
| 	s.ss.WriteFrame(trackID, streamType, payload) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // OnIncomingFrame is called by rtspServer. | // OnIncomingFrame is called by rtspServer. | ||||||
| func (s *rtspSession) OnIncomingFrame(ctx *gortsplib.ServerHandlerOnFrameCtx) { | func (s *rtspSession) OnIncomingFrame(ctx *gortsplib.ServerHandlerOnFrameCtx) { | ||||||
| 	if s.ss.State() != gortsplib.ServerSessionStateRecord { | 	if s.ss.State() != gortsplib.ServerSessionStateRecord { | ||||||
|   | |||||||
| @@ -23,8 +23,8 @@ const ( | |||||||
|  |  | ||||||
| type rtspSourceParent interface { | type rtspSourceParent interface { | ||||||
| 	Log(logger.Level, string, ...interface{}) | 	Log(logger.Level, string, ...interface{}) | ||||||
| 	OnSourceExternalSetReady(req sourceExtSetReadyReq) | 	OnSourceStaticSetReady(req pathSourceStaticSetReadyReq) | ||||||
| 	OnSourceExternalSetNotReady(req sourceExtSetNotReadyReq) | 	OnSourceStaticSetNotReady(req pathSourceStaticSetNotReadyReq) | ||||||
| 	OnSourceFrame(int, gortsplib.StreamType, []byte) | 	OnSourceFrame(int, gortsplib.StreamType, []byte) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -94,8 +94,8 @@ func (s *rtspSource) Close() { | |||||||
| // IsSource implements source. | // IsSource implements source. | ||||||
| func (s *rtspSource) IsSource() {} | func (s *rtspSource) IsSource() {} | ||||||
|  |  | ||||||
| // IsSourceExternal implements sourceExternal. | // IsSourceStatic implements sourceStatic. | ||||||
| func (s *rtspSource) IsSourceExternal() {} | func (s *rtspSource) IsSourceStatic() {} | ||||||
|  |  | ||||||
| func (s *rtspSource) log(level logger.Level, format string, args ...interface{}) { | func (s *rtspSource) log(level logger.Level, format string, args ...interface{}) { | ||||||
| 	s.parent.Log(level, "[rtsp source] "+format, args...) | 	s.parent.Log(level, "[rtsp source] "+format, args...) | ||||||
| @@ -187,12 +187,12 @@ func (s *rtspSource) runInner() bool { | |||||||
|  |  | ||||||
| 	s.log(logger.Info, "ready") | 	s.log(logger.Info, "ready") | ||||||
|  |  | ||||||
| 	s.parent.OnSourceExternalSetReady(sourceExtSetReadyReq{ | 	s.parent.OnSourceStaticSetReady(pathSourceStaticSetReadyReq{ | ||||||
| 		Tracks: conn.Tracks(), | 		Tracks: conn.Tracks(), | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		s.parent.OnSourceExternalSetNotReady(sourceExtSetNotReadyReq{}) | 		s.parent.OnSourceStaticSetNotReady(pathSourceStaticSetNotReadyReq{}) | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| 	readErr := make(chan error) | 	readErr := make(chan error) | ||||||
|   | |||||||
| @@ -1,26 +1,13 @@ | |||||||
| package core | package core | ||||||
|  |  | ||||||
| import ( | // source is an entity that can provide a stream, statically or dynamically. | ||||||
| 	"github.com/aler9/gortsplib" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type source interface { | type source interface { | ||||||
| 	IsSource() | 	IsSource() | ||||||
| } | } | ||||||
|  |  | ||||||
| type sourceExternal interface { | // sourceStatic is an entity that can provide a static stream. | ||||||
| 	IsSource() | type sourceStatic interface { | ||||||
| 	IsSourceExternal() | 	source | ||||||
|  | 	IsSourceStatic() | ||||||
| 	Close() | 	Close() | ||||||
| } | } | ||||||
|  |  | ||||||
| type sourceExtSetReadyRes struct{} |  | ||||||
|  |  | ||||||
| type sourceExtSetReadyReq struct { |  | ||||||
| 	Tracks gortsplib.Tracks |  | ||||||
| 	Res    chan sourceExtSetReadyRes |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type sourceExtSetNotReadyReq struct { |  | ||||||
| 	Res chan struct{} |  | ||||||
| } |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 aler9
					aler9