mirror of
https://github.com/lkmio/lkm.git
synced 2025-09-27 03:26:01 +08:00
统一sourceid格式
This commit is contained in:
93
api.go
93
api.go
@@ -40,8 +40,34 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func withCheckParams(f func(sourceId string, w http.ResponseWriter, req *http.Request), suffix string) func(http.ResponseWriter, *http.Request) {
|
||||||
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
source, err := stream.Path2SourceId(req.URL.Path, suffix)
|
||||||
|
if err != nil {
|
||||||
|
httpResponse(w, http.StatusBadRequest, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f(source, w, req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func startApiServer(addr string) {
|
func startApiServer(addr string) {
|
||||||
apiServer.router.HandleFunc("/live/{source}", apiServer.filterLive)
|
/**
|
||||||
|
http://host:port/xxx.flv
|
||||||
|
http://host:port/xxx.rtc
|
||||||
|
http://host:port/xxx.m3u8
|
||||||
|
http://host:port/xxx_0.ts
|
||||||
|
ws://host:port/xxx.flv
|
||||||
|
*/
|
||||||
|
apiServer.router.HandleFunc("/{source}.flv", withCheckParams(apiServer.onFlv, ".flv"))
|
||||||
|
apiServer.router.HandleFunc("/{source}/{stream}.flv", withCheckParams(apiServer.onFlv, ".flv"))
|
||||||
|
apiServer.router.HandleFunc("/{source}.m3u8", withCheckParams(apiServer.onHLS, ".m3u8"))
|
||||||
|
apiServer.router.HandleFunc("/{source}/{stream}.m3u8", withCheckParams(apiServer.onHLS, ".m3u8"))
|
||||||
|
apiServer.router.HandleFunc("/{source}.ts", withCheckParams(apiServer.onTS, ".ts"))
|
||||||
|
apiServer.router.HandleFunc("/{source}/{stream}.ts", withCheckParams(apiServer.onTS, ".ts"))
|
||||||
|
apiServer.router.HandleFunc("/{source}.rtc", withCheckParams(apiServer.onRtc, ".rtc"))
|
||||||
|
apiServer.router.HandleFunc("/{source}/{stream}.rtc", withCheckParams(apiServer.onRtc, ".rtc"))
|
||||||
|
|
||||||
apiServer.router.HandleFunc("/v1/gb28181/source/create", apiServer.createGBSource)
|
apiServer.router.HandleFunc("/v1/gb28181/source/create", apiServer.createGBSource)
|
||||||
//TCP主动,设置连接地址
|
//TCP主动,设置连接地址
|
||||||
@@ -218,6 +244,15 @@ func (api *ApiServer) generateSinkId(remoteAddr string) stream.SinkId {
|
|||||||
return stream.GenerateSinkId(tcpAddr)
|
return stream.GenerateSinkId(tcpAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *ApiServer) generateSourceId(remoteAddr string) stream.SinkId {
|
||||||
|
tcpAddr, err := net.ResolveTCPAddr("tcp", remoteAddr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream.GenerateSinkId(tcpAddr)
|
||||||
|
}
|
||||||
|
|
||||||
func (api *ApiServer) doPlay(sink stream.ISink) utils.HookState {
|
func (api *ApiServer) doPlay(sink stream.ISink) utils.HookState {
|
||||||
ok := utils.HookStateOK
|
ok := utils.HookStateOK
|
||||||
stream.HookPlaying(sink, func() {
|
stream.HookPlaying(sink, func() {
|
||||||
@@ -229,52 +264,22 @@ func (api *ApiServer) doPlay(sink stream.ISink) utils.HookState {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ApiServer) filterLive(w http.ResponseWriter, r *http.Request) {
|
func (api *ApiServer) onFlv(sourceId string, w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
ws := true
|
||||||
source := vars["source"]
|
if !("upgrade" == strings.ToLower(r.Header.Get("Connection"))) {
|
||||||
index := strings.LastIndex(source, ".")
|
ws = false
|
||||||
if index < 0 || index == len(source)-1 {
|
} else if !("websocket" == strings.ToLower(r.Header.Get("Upgrade"))) {
|
||||||
log.Sugar.Errorf("bad request:%s. stream format must be passed at the end of the URL", r.URL.Path)
|
ws = false
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
} else if !("13" == r.Header.Get("Sec-Websocket-Version")) {
|
||||||
return
|
ws = false
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceId := source[:index]
|
if ws {
|
||||||
format := source[index+1:]
|
apiServer.onWSFlv(sourceId, w, r)
|
||||||
|
} else {
|
||||||
/**
|
apiServer.onHttpFLV(sourceId, w, r)
|
||||||
http://host:port/xxx.flv
|
|
||||||
http://host:port/xxx.rtc
|
|
||||||
http://host:port/xxx.m3u8
|
|
||||||
http://host:port/xxx_0.ts
|
|
||||||
ws://host:port/xxx.flv
|
|
||||||
*/
|
|
||||||
if "flv" == format {
|
|
||||||
//判断是否是websocket请求
|
|
||||||
ws := true
|
|
||||||
if !("upgrade" == strings.ToLower(r.Header.Get("Connection"))) {
|
|
||||||
ws = false
|
|
||||||
} else if !("websocket" == strings.ToLower(r.Header.Get("Upgrade"))) {
|
|
||||||
ws = false
|
|
||||||
} else if !("13" == r.Header.Get("Sec-Websocket-Version")) {
|
|
||||||
ws = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if ws {
|
|
||||||
api.onWSFlv(sourceId, w, r)
|
|
||||||
} else {
|
|
||||||
api.onFLV(sourceId, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if "m3u8" == format {
|
|
||||||
api.onHLS(sourceId, w, r)
|
|
||||||
} else if "ts" == format {
|
|
||||||
api.onTS(sourceId, w, r)
|
|
||||||
} else if "rtc" == format {
|
|
||||||
api.onRtc(sourceId, w, r)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ApiServer) onWSFlv(sourceId string, w http.ResponseWriter, r *http.Request) {
|
func (api *ApiServer) onWSFlv(sourceId string, w http.ResponseWriter, r *http.Request) {
|
||||||
conn, err := api.upgrader.Upgrade(w, r, nil)
|
conn, err := api.upgrader.Upgrade(w, r, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -304,7 +309,7 @@ func (api *ApiServer) onWSFlv(sourceId string, w http.ResponseWriter, r *http.Re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ApiServer) onFLV(sourceId string, w http.ResponseWriter, r *http.Request) {
|
func (api *ApiServer) onHttpFLV(sourceId string, w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "video/x-flv")
|
w.Header().Set("Content-Type", "video/x-flv")
|
||||||
w.Header().Set("Connection", "Keep-Alive")
|
w.Header().Set("Connection", "Keep-Alive")
|
||||||
w.Header().Set("Transfer-Encoding", "chunked")
|
w.Header().Set("Transfer-Encoding", "chunked")
|
||||||
|
@@ -34,10 +34,20 @@ type sessionImpl struct {
|
|||||||
conn net.Conn
|
conn net.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *sessionImpl) generateSourceId(app, stream_ string) string {
|
||||||
|
if len(app) == 0 {
|
||||||
|
return stream_
|
||||||
|
} else if len(stream_) == 0 {
|
||||||
|
return app
|
||||||
|
} else {
|
||||||
|
return app + "/" + stream_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *sessionImpl) OnPublish(app, stream_ string, response chan utils.HookState) {
|
func (s *sessionImpl) OnPublish(app, stream_ string, response chan utils.HookState) {
|
||||||
log.Sugar.Infof("rtmp onpublish app:%s stream:%s conn:%s", app, stream_, s.conn.RemoteAddr().String())
|
log.Sugar.Infof("rtmp onpublish app:%s stream:%s conn:%s", app, stream_, s.conn.RemoteAddr().String())
|
||||||
|
|
||||||
sourceId := app + "_" + stream_
|
sourceId := s.generateSourceId(app, stream_)
|
||||||
source := NewPublisher(sourceId, s.stack, s.conn)
|
source := NewPublisher(sourceId, s.stack, s.conn)
|
||||||
//设置推流的音视频回调
|
//设置推流的音视频回调
|
||||||
s.stack.SetOnPublishHandler(source)
|
s.stack.SetOnPublishHandler(source)
|
||||||
@@ -57,7 +67,7 @@ func (s *sessionImpl) OnPublish(app, stream_ string, response chan utils.HookSta
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *sessionImpl) OnPlay(app, stream_ string, response chan utils.HookState) {
|
func (s *sessionImpl) OnPlay(app, stream_ string, response chan utils.HookState) {
|
||||||
sourceId := app + "_" + stream_
|
sourceId := s.generateSourceId(app, stream_)
|
||||||
//拉流事件Sink统一处理
|
//拉流事件Sink统一处理
|
||||||
sink := NewSink(stream.GenerateSinkId(s.conn.RemoteAddr()), sourceId, s.conn)
|
sink := NewSink(stream.GenerateSinkId(s.conn.RemoteAddr()), sourceId, s.conn)
|
||||||
|
|
||||||
|
@@ -70,9 +70,14 @@ func (h handler) Process(session *session, method string, url_ *url.URL, headers
|
|||||||
return fmt.Errorf("please establish a session first")
|
return fmt.Errorf("please establish a session first")
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
source := strings.TrimSpace(url_.Path)
|
||||||
split := strings.Split(url_.Path, "/")
|
if strings.HasPrefix(source, "/") {
|
||||||
source := split[len(split)-1]
|
source = source[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(strings.TrimSpace(source)) == 0 {
|
||||||
|
return fmt.Errorf("the request source cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
//反射调用各个处理函数
|
//反射调用各个处理函数
|
||||||
results := m.Call([]reflect.Value{
|
results := m.Call([]reflect.Value{
|
||||||
@@ -80,7 +85,7 @@ func (h handler) Process(session *session, method string, url_ *url.URL, headers
|
|||||||
reflect.ValueOf(Request{session, source, method, url_, headers}),
|
reflect.ValueOf(Request{session, source, method, url_, headers}),
|
||||||
})
|
})
|
||||||
|
|
||||||
err, _ = results[2].Interface().(error)
|
err, _ := results[2].Interface().(error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -97,7 +97,7 @@ func parseMessage(data []byte) (string, *url.URL, textproto.MIMEHeader, error) {
|
|||||||
line, err := tp.ReadLine()
|
line, err := tp.ReadLine()
|
||||||
split := strings.Split(line, " ")
|
split := strings.Split(line, " ")
|
||||||
if len(split) < 3 {
|
if len(split) < 3 {
|
||||||
panic(fmt.Errorf("unknow response line of response:%s", line))
|
panic(fmt.Errorf("wrong request line %s", line))
|
||||||
}
|
}
|
||||||
|
|
||||||
method := strings.ToUpper(split[0])
|
method := strings.ToUpper(split[0])
|
||||||
@@ -109,6 +109,15 @@ func parseMessage(data []byte) (string, *url.URL, textproto.MIMEHeader, error) {
|
|||||||
return "", nil, nil, err
|
return "", nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
path := strings.TrimSpace(url_.Path)
|
||||||
|
if strings.HasPrefix(path, "/") {
|
||||||
|
path = path[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(strings.TrimSpace(path)) == 0 {
|
||||||
|
return "", nil, nil, fmt.Errorf("the request source cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
header, err := tp.ReadMIMEHeader()
|
header, err := tp.ReadMIMEHeader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, nil, err
|
return "", nil, nil, err
|
||||||
|
@@ -52,34 +52,6 @@ const (
|
|||||||
SessionStateClose = SessionState(7) //关闭状态
|
SessionStateClose = SessionState(7) //关闭状态
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s SourceType) ToString() string {
|
|
||||||
if SourceTypeRtmp == s {
|
|
||||||
return "rtmp"
|
|
||||||
} else if SourceType28181 == s {
|
|
||||||
return "28181"
|
|
||||||
} else if SourceType1078 == s {
|
|
||||||
return "jt1078"
|
|
||||||
}
|
|
||||||
|
|
||||||
panic(fmt.Sprintf("unknown source type %d", s))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Protocol) ToString() string {
|
|
||||||
if ProtocolRtmp == p {
|
|
||||||
return "rtmp"
|
|
||||||
} else if ProtocolFlv == p {
|
|
||||||
return "flv"
|
|
||||||
} else if ProtocolRtsp == p {
|
|
||||||
return "rtsp"
|
|
||||||
} else if ProtocolHls == p {
|
|
||||||
return "hls"
|
|
||||||
} else if ProtocolRtc == p {
|
|
||||||
return "rtc"
|
|
||||||
}
|
|
||||||
|
|
||||||
panic(fmt.Sprintf("unknown stream protocol %d", p))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ISource 父类Source负责, 除解析流以外的所有事情
|
// ISource 父类Source负责, 除解析流以外的所有事情
|
||||||
type ISource interface {
|
type ISource interface {
|
||||||
// Id Source的唯一ID/**
|
// Id Source的唯一ID/**
|
||||||
@@ -140,8 +112,6 @@ type ISource interface {
|
|||||||
Init(input func(data []byte) error)
|
Init(input func(data []byte) error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var TranscoderFactory func(src utils.AVStream, dst utils.AVStream) transcode.ITranscoder
|
|
||||||
|
|
||||||
type SourceImpl struct {
|
type SourceImpl struct {
|
||||||
hookSessionImpl
|
hookSessionImpl
|
||||||
|
|
||||||
|
53
stream/source_utils.go
Normal file
53
stream/source_utils.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package stream
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s SourceType) ToString() string {
|
||||||
|
if SourceTypeRtmp == s {
|
||||||
|
return "rtmp"
|
||||||
|
} else if SourceType28181 == s {
|
||||||
|
return "28181"
|
||||||
|
} else if SourceType1078 == s {
|
||||||
|
return "jt1078"
|
||||||
|
}
|
||||||
|
|
||||||
|
panic(fmt.Sprintf("unknown source type %d", s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Protocol) ToString() string {
|
||||||
|
if ProtocolRtmp == p {
|
||||||
|
return "rtmp"
|
||||||
|
} else if ProtocolFlv == p {
|
||||||
|
return "flv"
|
||||||
|
} else if ProtocolRtsp == p {
|
||||||
|
return "rtsp"
|
||||||
|
} else if ProtocolHls == p {
|
||||||
|
return "hls"
|
||||||
|
} else if ProtocolRtc == p {
|
||||||
|
return "rtc"
|
||||||
|
}
|
||||||
|
|
||||||
|
panic(fmt.Sprintf("unknown stream protocol %d", p))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Path2SourceId(path string, suffix string) (string, error) {
|
||||||
|
source := strings.TrimSpace(path)
|
||||||
|
if strings.HasPrefix(source, "/") {
|
||||||
|
source = source[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(suffix) > 0 && strings.HasSuffix(source, suffix) {
|
||||||
|
source = source[:len(source)-len(suffix)]
|
||||||
|
}
|
||||||
|
|
||||||
|
source = strings.TrimSpace(source)
|
||||||
|
|
||||||
|
if len(strings.TrimSpace(source)) == 0 {
|
||||||
|
return "", fmt.Errorf("the request source cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
return source, nil
|
||||||
|
}
|
Reference in New Issue
Block a user