diff --git a/README.md b/README.md index 82b9e5c..67c2789 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ Start streaming by choosing from the following broadcast options: - **HLS:** - URL: `http://127.0.0.1:8044/hls/test/master.m3u8` + - Viewer: `http://127.0.0.1:8044/m3u8player.html?streamid=test` - **WHEP:** - URL: `http://127.0.0.1:8044/` diff --git a/config.toml b/config.toml index bbfd96d..64f70bd 100644 --- a/config.toml +++ b/config.toml @@ -5,4 +5,8 @@ port = 1930 llhls = false disk_ram = true [docker] -mode = false \ No newline at end of file +mode = false +[mp4] +record=false +[ebml] +record=false \ No newline at end of file diff --git a/config/config.go b/config/config.go index 1356200..168fa98 100644 --- a/config/config.go +++ b/config/config.go @@ -5,6 +5,8 @@ type Config struct { RTMP RTMP `mapstructure:"rtmp"` Service Service `mapstructure:"service"` Docker DockerConfig `mapstructure:"docker"` + MP4 MP4 `mapstructure:"mp4"` + EBML EBML `mapstructure:"ebml"` } type RTMP struct { @@ -20,3 +22,11 @@ type Service struct { type DockerConfig struct { Mode bool `mapstructure:"mode"` } + +type MP4 struct { + Record bool `mapstructure:"record"` +} + +type EBML struct { + Record bool `mapstructure:"record"` +} diff --git a/go.mod b/go.mod index 813fadf..38a5234 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.21 require ( github.com/asticode/go-astiav v0.19.0 + github.com/asticode/go-astits v1.13.0 github.com/at-wat/ebml-go v0.17.1 github.com/bluenviron/gohlslib v1.4.0 github.com/deepch/vdk v0.0.27 @@ -25,12 +26,12 @@ require ( require ( github.com/abema/go-mp4 v1.2.0 // indirect github.com/asticode/go-astikit v0.43.0 // indirect - github.com/asticode/go-astits v1.13.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bluenviron/mediacommon v1.11.1-0.20240525122142-20163863aa75 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/google/uuid v1.4.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -77,6 +78,7 @@ require ( golang.org/x/net v0.26.0 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.5.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 2efd3fa..632daa9 100644 --- a/go.sum +++ b/go.sum @@ -30,6 +30,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -248,6 +250,8 @@ golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= diff --git a/main.go b/main.go index b6cdb7d..3c4508c 100644 --- a/main.go +++ b/main.go @@ -10,11 +10,11 @@ import ( "liveflow/media/streamer/egress/whep" "liveflow/media/streamer/ingress/whip" "net/http" + _ "net/http/pprof" // pprof을 사용하기 위한 패키지 "strconv" - _ "net/http/pprof" // pprof을 사용하기 위한 패키지 - "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" "github.com/pion/webrtc/v3" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/sirupsen/logrus" @@ -63,11 +63,16 @@ func main() { api.HideBanner = true hlsHub := hlshub.NewHLSHub() hlsHandler := httpsrv.NewHandler(hlsHub) + hlsRoute := api.Group("/hls", middleware.CORSWithConfig(middleware.CORSConfig{ + AllowOrigins: []string{"*"}, // Adjust origins as necessary + AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodOptions}, + })) api.GET("/prometheus", echo.WrapHandler(promhttp.Handler())) api.GET("/debug/pprof/*", echo.WrapHandler(http.DefaultServeMux)) - api.GET("/hls/:streamID/master.m3u8", hlsHandler.HandleMasterM3U8) - api.GET("/hls/:streamID/:playlistName/stream.m3u8", hlsHandler.HandleM3U8) - api.GET("/hls/:streamID/:playlistName/:resourceName", hlsHandler.HandleM3U8) + // Enable CORS only for /hls routes + hlsRoute.GET("/:streamID/master.m3u8", hlsHandler.HandleMasterM3U8) + hlsRoute.GET("/:streamID/:playlistName/stream.m3u8", hlsHandler.HandleM3U8) + hlsRoute.GET("/:streamID/:playlistName/:resourceName", hlsHandler.HandleM3U8) whipServer := whip.NewWHIP(whip.WHIPArgs{ Hub: hub, Tracks: tracks, @@ -82,19 +87,23 @@ func main() { // ingress 의 rtmp, whip 서비스로부터 streamID를 받아 Service, ContainerMP4, WHEP 서비스 시작 for source := range hub.SubscribeToStreamID() { log.Infof(ctx, "New streamID received: %s", source.StreamID()) - mp4 := mp4.NewMP4(mp4.MP4Args{ - Hub: hub, - }) - err = mp4.Start(ctx, source) - if err != nil { - log.Errorf(ctx, "failed to start mp4: %v", err) + if conf.MP4.Record { + mp4 := mp4.NewMP4(mp4.MP4Args{ + Hub: hub, + }) + err = mp4.Start(ctx, source) + if err != nil { + log.Errorf(ctx, "failed to start mp4: %v", err) + } } - webmStarter := webm.NewWEBM(webm.WebMArgs{ - Hub: hub, - }) - err = webmStarter.Start(ctx, source) - if err != nil { - log.Errorf(ctx, "failed to start webm: %v", err) + if conf.EBML.Record { + webmStarter := webm.NewWEBM(webm.WebMArgs{ + Hub: hub, + }) + err = webmStarter.Start(ctx, source) + if err != nil { + log.Errorf(ctx, "failed to start webm: %v", err) + } } hls := hls.NewHLS(hls.HLSArgs{ Hub: hub, diff --git a/media/streamer/egress/hls/handler.go b/media/streamer/egress/hls/handler.go index 44549be..9bd4cc8 100644 --- a/media/streamer/egress/hls/handler.go +++ b/media/streamer/egress/hls/handler.go @@ -70,7 +70,8 @@ func (h *HLS) Start(ctx context.Context, source hub.Source) error { fields.SourceName: source.Name(), }) log.Info(ctx, "start hls") - log.Info(ctx, "view url: ", fmt.Sprintf("http://127.0.0.1:%d/hls/%s/master.m3u8", h.port, source.StreamID())) + log.Info(ctx, "view url: ", + fmt.Sprintf("http://localhost:8044/m3u8player.html?streamid=%s", source.StreamID())) sub := h.hub.Subscribe(source.StreamID()) go func() { diff --git a/media/streamer/ingress/whip/serve.go b/media/streamer/ingress/whip/serve.go index 80ffade..5cf55c3 100644 --- a/media/streamer/ingress/whip/serve.go +++ b/media/streamer/ingress/whip/serve.go @@ -56,7 +56,7 @@ func NewWHIP(args WHIPArgs) *WHIP { func (r *WHIP) RegisterRoute() { whipServer := r.echo - whipServer.Static("/", ".") + whipServer.Static("/", "static") whipServer.POST("/whip", r.whipHandler) whipServer.POST("/whep", r.whepHandler) } diff --git a/index.html b/static/index.html similarity index 100% rename from index.html rename to static/index.html diff --git a/static/m3u8player.html b/static/m3u8player.html new file mode 100644 index 0000000..bb5c1b3 --- /dev/null +++ b/static/m3u8player.html @@ -0,0 +1,41 @@ + + + + + + + M3U8 Player + + +
+ + + + + + + \ No newline at end of file