fix: use ADTS for AAC transcoding, temporarily exclude AAC from transcode decisions (#5167)
* fix: use ADTS format for AAC transcoding to avoid silent output on ffmpeg 8.0+ The fragmented MP4 muxer (`-f ipod -movflags frag_keyframe+empty_moov`) produces corrupt/silent audio when ffmpeg pipes to stdout, confirmed on ffmpeg 8.0+. The moof atom offset values are zeroed out in pipe mode, causing AAC decoder errors. Switch to `-f adts` (raw AAC framing) which works reliably via pipe and is widely supported by clients including UPnP/Sonos devices. * fix: exclude AAC from transcode decision, as it is not working for Sonos. Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
@@ -283,7 +283,7 @@ var formatCodecMap = map[string]string{
|
||||
var formatOutputMap = map[string]string{
|
||||
"mp3": "mp3",
|
||||
"opus": "opus",
|
||||
"aac": "ipod",
|
||||
"aac": "adts",
|
||||
"flac": "flac",
|
||||
}
|
||||
|
||||
@@ -339,11 +339,6 @@ func buildDynamicArgs(opts TranscodeOptions) []string {
|
||||
args = append(args, "-f", outputFmt)
|
||||
}
|
||||
|
||||
// For AAC in MP4 container, enable fragmented MP4 for pipe-safe streaming
|
||||
if opts.Format == "aac" {
|
||||
args = append(args, "-movflags", "frag_keyframe+empty_moov")
|
||||
}
|
||||
|
||||
args = append(args, "-")
|
||||
return args
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ var _ = Describe("ffmpeg", func() {
|
||||
Expect(isDefaultCommand("opus", "ffmpeg -i %s -ss %t -map 0:a:0 -b:a %bk -v 0 -c:a libopus -f opus -")).To(BeTrue())
|
||||
})
|
||||
It("returns true for known default aac command", func() {
|
||||
Expect(isDefaultCommand("aac", "ffmpeg -i %s -ss %t -map 0:a:0 -b:a %bk -v 0 -c:a aac -f ipod -movflags frag_keyframe+empty_moov -")).To(BeTrue())
|
||||
Expect(isDefaultCommand("aac", "ffmpeg -i %s -ss %t -map 0:a:0 -b:a %bk -v 0 -c:a aac -f adts -")).To(BeTrue())
|
||||
})
|
||||
It("returns true for known default flac command", func() {
|
||||
Expect(isDefaultCommand("flac", "ffmpeg -i %s -ss %t -map 0:a:0 -v 0 -c:a flac -f flac -")).To(BeTrue())
|
||||
@@ -174,7 +174,7 @@ var _ = Describe("ffmpeg", func() {
|
||||
}))
|
||||
})
|
||||
|
||||
It("builds aac args with fragmented MP4 container", func() {
|
||||
It("builds aac args with ADTS output", func() {
|
||||
args := buildDynamicArgs(TranscodeOptions{
|
||||
Format: "aac",
|
||||
FilePath: "/music/file.flac",
|
||||
@@ -186,8 +186,7 @@ var _ = Describe("ffmpeg", func() {
|
||||
"-c:a", "aac",
|
||||
"-b:a", "256k",
|
||||
"-v", "0",
|
||||
"-f", "ipod",
|
||||
"-movflags", "frag_keyframe+empty_moov",
|
||||
"-f", "adts",
|
||||
"-",
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -80,6 +80,11 @@ func matchesCodec(codec string, codecs []string) bool {
|
||||
return matchesWithAliases(codec, codecs, codecAliasGroups)
|
||||
}
|
||||
|
||||
// IsAACCodec returns true if the given codec or container name resolves to AAC.
|
||||
func IsAACCodec(name string) bool {
|
||||
return matchesCodec(name, []string{"aac"}) || matchesContainer(name, []string{"aac"})
|
||||
}
|
||||
|
||||
func containsIgnoreCase(slice []string, s string) bool {
|
||||
return slices.ContainsFunc(slice, func(item string) bool {
|
||||
return strings.EqualFold(item, s)
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package stream
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Aliases", func() {
|
||||
Describe("IsAACCodec", func() {
|
||||
It("returns true for AAC and its aliases", func() {
|
||||
Expect(IsAACCodec("aac")).To(BeTrue())
|
||||
Expect(IsAACCodec("AAC")).To(BeTrue())
|
||||
Expect(IsAACCodec("adts")).To(BeTrue())
|
||||
Expect(IsAACCodec("m4a")).To(BeTrue())
|
||||
Expect(IsAACCodec("mp4")).To(BeTrue())
|
||||
Expect(IsAACCodec("m4b")).To(BeTrue())
|
||||
})
|
||||
|
||||
It("returns false for non-AAC formats", func() {
|
||||
Expect(IsAACCodec("mp3")).To(BeFalse())
|
||||
Expect(IsAACCodec("opus")).To(BeFalse())
|
||||
Expect(IsAACCodec("flac")).To(BeFalse())
|
||||
Expect(IsAACCodec("ogg")).To(BeFalse())
|
||||
})
|
||||
|
||||
It("returns false for empty string", func() {
|
||||
Expect(IsAACCodec("")).To(BeFalse())
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user