diff --git a/transcoder/src/api/streams.go b/transcoder/src/api/streams.go index 33ed46a9..b6f65301 100644 --- a/transcoder/src/api/streams.go +++ b/transcoder/src/api/streams.go @@ -20,9 +20,9 @@ func RegisterStreamHandlers(e *echo.Group, transcoder *src.Transcoder) { e.GET("/:path/direct/:identifier", DirectStream) e.GET("/:path/master.m3u8", h.GetMaster) e.GET("/:path/:video/:quality/index.m3u8", h.GetVideoIndex) - e.GET("/:path/audio/:audio/index.m3u8", h.GetAudioIndex) + e.GET("/:path/audio/:audio/:quality/index.m3u8", h.GetAudioIndex) e.GET("/:path/:video/:quality/:chunk", h.GetVideoSegment) - e.GET("/:path/audio/:audio/:chunk", h.GetAudioSegment) + e.GET("/:path/audio/:audio/:quality/:chunk", h.GetAudioSegment) } // @Summary Direct video @@ -115,7 +115,7 @@ func (h *shandler) GetVideoIndex(c echo.Context) error { // This route can take a few seconds to respond since it will way for at least one segment to be // available. // -// Path: /:path/audio/:audio/index.m3u8 +// Path: /:path/audio/:audio/:quality/index.m3u8 // // PRIVATE ROUTE (not documented in swagger, can change at any time) // Only reached via the master.m3u8. @@ -124,6 +124,10 @@ func (h *shandler) GetAudioIndex(c echo.Context) error { if err != nil { return err } + quality, err := src.AudioQualityFromString(c.Param("quality")) + if err != nil { + return err + } client, err := getClientId(c) if err != nil { return err @@ -133,7 +137,7 @@ func (h *shandler) GetAudioIndex(c echo.Context) error { return err } - ret, err := h.transcoder.GetAudioIndex(c.Request().Context(), path, uint32(audio), client, sha) + ret, err := h.transcoder.GetAudioIndex(c.Request().Context(), path, uint32(audio), quality, client, sha) if err != nil { return err } @@ -190,7 +194,7 @@ func (h *shandler) GetVideoSegment(c echo.Context) error { // // Retrieve a chunk of a transcoded audio. // -// Path: /:path/audio/:audio/segments-:chunk.ts +// Path: /:path/audio/:audio/:quality/segments-:chunk.ts // // PRIVATE ROUTE (not documented in swagger, can change at any time) // Only reached via the master.m3u8. @@ -199,6 +203,10 @@ func (h *shandler) GetAudioSegment(c echo.Context) error { if err != nil { return err } + quality, err := src.AudioQualityFromString(c.Param("quality")) + if err != nil { + return err + } segment, err := parseSegment(c.Param("chunk")) if err != nil { return err @@ -212,7 +220,7 @@ func (h *shandler) GetAudioSegment(c echo.Context) error { return err } - ret, err := h.transcoder.GetAudioSegment(c.Request().Context(), path, uint32(audio), segment, client, sha) + ret, err := h.transcoder.GetAudioSegment(c.Request().Context(), path, uint32(audio), quality, segment, client, sha) if err != nil { return err } diff --git a/transcoder/src/filestream.go b/transcoder/src/filestream.go index 45161b25..8a879d79 100644 --- a/transcoder/src/filestream.go +++ b/transcoder/src/filestream.go @@ -19,7 +19,12 @@ type FileStream struct { Out string Info *MediaInfo videos CMap[VideoKey, *VideoStream] - audios CMap[uint32, *AudioStream] + audios CMap[AudioKey, *AudioStream] +} + +type AudioKey struct { + idx uint32 + quality AudioQuality } type VideoKey struct { @@ -32,7 +37,7 @@ func (t *Transcoder) newFileStream(path string, sha string) *FileStream { transcoder: t, Out: fmt.Sprintf("%s/%s", Settings.Outpath, sha), videos: NewCMap[VideoKey, *VideoStream](), - audios: NewCMap[uint32, *AudioStream](), + audios: NewCMap[AudioKey, *AudioStream](), } ret.ready.Add(1) @@ -71,27 +76,28 @@ func (fs *FileStream) Destroy() { func (fs *FileStream) GetMaster(client string) string { master := "#EXTM3U\n" - // TODO: support multiples audio qualities (and original) - for _, audio := range fs.Info.Audios { - master += "#EXT-X-MEDIA:TYPE=AUDIO," - master += "GROUP-ID=\"audio\"," - if audio.Language != nil { - master += fmt.Sprintf("LANGUAGE=\"%s\",", *audio.Language) + for _, quality := range AudioQualities { + for _, audio := range fs.Info.Audios { + master += "#EXT-X-MEDIA:TYPE=AUDIO," + master += fmt.Sprintf("GROUP-ID=\"audio-%s\",", quality) + if audio.Language != nil { + master += fmt.Sprintf("LANGUAGE=\"%s\",", *audio.Language) + } + if audio.Title != nil { + master += fmt.Sprintf("NAME=\"%s\",", *audio.Title) + } else if audio.Language != nil { + master += fmt.Sprintf("NAME=\"%s\",", *audio.Language) + } else { + master += fmt.Sprintf("NAME=\"Audio %d\",", audio.Index) + } + if audio.IsDefault { + master += "DEFAULT=YES," + } + master += "CHANNELS=\"2\"," + master += fmt.Sprintf("URI=\"audio/%d/%s/index.m3u8?clientId=%s\"\n", audio.Index, quality, client) } - if audio.Title != nil { - master += fmt.Sprintf("NAME=\"%s\",", *audio.Title) - } else if audio.Language != nil { - master += fmt.Sprintf("NAME=\"%s\",", *audio.Language) - } else { - master += fmt.Sprintf("NAME=\"Audio %d\",", audio.Index) - } - if audio.IsDefault { - master += "DEFAULT=YES," - } - master += "CHANNELS=\"2\"," - master += fmt.Sprintf("URI=\"audio/%d/index.m3u8?clientId=%s\"\n", audio.Index, client) + master += "\n" } - master += "\n" // codec is the prefix + the level, the level is not part of the codec we want to compare for the same_codec check bellow transcode_prefix := "avc1.6400" @@ -204,25 +210,25 @@ func (fs *FileStream) GetVideoSegment(idx uint32, quality VideoQuality, segment return stream.GetSegment(segment) } -func (fs *FileStream) getAudioStream(audio uint32) (*AudioStream, error) { - stream, _ := fs.audios.GetOrCreate(audio, func() *AudioStream { - ret, _ := fs.transcoder.NewAudioStream(fs, audio) +func (fs *FileStream) getAudioStream(idx uint32, quality AudioQuality) (*AudioStream, error) { + stream, _ := fs.audios.GetOrCreate(AudioKey{idx, quality}, func() *AudioStream { + ret, _ := fs.transcoder.NewAudioStream(fs, idx, quality) return ret }) stream.ready.Wait() return stream, nil } -func (fs *FileStream) GetAudioIndex(audio uint32, client string) (string, error) { - stream, err := fs.getAudioStream(audio) +func (fs *FileStream) GetAudioIndex(idx uint32, quality AudioQuality, client string) (string, error) { + stream, err := fs.getAudioStream(idx, quality) if err != nil { return "", nil } return stream.GetIndex(client) } -func (fs *FileStream) GetAudioSegment(audio uint32, segment int32) (string, error) { - stream, err := fs.getAudioStream(audio) +func (fs *FileStream) GetAudioSegment(idx uint32, quality AudioQuality, segment int32) (string, error) { + stream, err := fs.getAudioStream(idx, quality) if err != nil { return "", nil } diff --git a/transcoder/src/tracker.go b/transcoder/src/tracker.go index 015a89f0..56d4cf2d 100644 --- a/transcoder/src/tracker.go +++ b/transcoder/src/tracker.go @@ -10,7 +10,7 @@ type ClientInfo struct { sha string path string video *VideoKey - audio *uint32 + audio *AudioKey vhead int32 ahead int32 } @@ -151,7 +151,7 @@ func (t *Tracker) DestroyStreamIfOld(sha string) { stream.Destroy() } -func (t *Tracker) KillAudioIfDead(sha string, path string, audio uint32) bool { +func (t *Tracker) KillAudioIfDead(sha string, path string, audio AudioKey) bool { for _, stream := range t.clients { if stream.sha == sha && stream.audio != nil && *stream.audio == audio { return false @@ -191,7 +191,7 @@ func (t *Tracker) KillVideoIfDead(sha string, path string, video VideoKey) bool return true } -func (t *Tracker) KillOrphanedHeads(sha string, video *VideoKey, audio *uint32) { +func (t *Tracker) KillOrphanedHeads(sha string, video *VideoKey, audio *AudioKey) { stream, ok := t.transcoder.streams.Get(sha) if !ok { return diff --git a/transcoder/src/transcoder.go b/transcoder/src/transcoder.go index 5dee0aec..dfb960a4 100644 --- a/transcoder/src/transcoder.go +++ b/transcoder/src/transcoder.go @@ -94,6 +94,7 @@ func (t *Transcoder) GetAudioIndex( ctx context.Context, path string, audio uint32, + quality AudioQuality, client string, sha string, ) (string, error) { @@ -105,18 +106,18 @@ func (t *Transcoder) GetAudioIndex( client: client, sha: sha, path: path, - audio: &audio, + audio: &AudioKey{audio, quality}, vhead: -1, ahead: -1, } - return stream.GetAudioIndex(audio, client) + return stream.GetAudioIndex(audio, quality, client) } func (t *Transcoder) GetVideoSegment( ctx context.Context, path string, video uint32, - quality Quality, + quality VideoQuality, segment int32, client string, sha string, @@ -141,6 +142,7 @@ func (t *Transcoder) GetAudioSegment( ctx context.Context, path string, audio uint32, + quality AudioQuality, segment int32, client string, sha string, @@ -153,9 +155,9 @@ func (t *Transcoder) GetAudioSegment( client: client, sha: sha, path: path, - audio: &audio, + audio: &AudioKey{audio, quality}, ahead: segment, vhead: -1, } - return stream.GetAudioSegment(audio, segment) + return stream.GetAudioSegment(audio, quality, segment) }