Option to transcode surround sound audio to AC3

This commit is contained in:
Damontecres 2026-02-21 14:29:33 -05:00
parent 55b148971e
commit eecdea92e0
No known key found for this signature in database
7 changed files with 97 additions and 6 deletions

View file

@ -52,7 +52,10 @@ sealed interface AppPreference<Pref, T> {
value: T?,
): String? = null
fun validate(value: T): PreferenceValidation = PreferenceValidation.Valid
fun validate(
prefs: Pref,
value: T,
): PreferenceValidation = PreferenceValidation.Valid
companion object {
val SkipForward =
@ -414,18 +417,49 @@ sealed interface AppPreference<Pref, T> {
defaultValue = true,
getter = { it.playbackPreferences.overrides.ac3Supported },
setter = { prefs, value ->
prefs.updatePlaybackOverrides { ac3Supported = value }
prefs.updatePlaybackOverrides {
ac3Supported = value
if (!value) preferAc3Surround = false
}
},
summaryOn = R.string.enabled,
summaryOff = R.string.disabled,
)
val PreferAc3ForSurround =
AppSwitchPreference<AppPreferences>(
title = R.string.prefer_ac3_for_surround,
defaultValue = true,
getter = { it.playbackPreferences.overrides.preferAc3Surround },
setter = { prefs, value ->
prefs.updatePlaybackOverrides {
preferAc3Surround = value
}
},
summaryOn = R.string.prefer_ac3_for_surround_summary,
// summaryOn = R.string.enabled,
summaryOff = R.string.disabled,
validator = { prefs, value ->
prefs.playbackPreferences.overrides.let {
if (value && !it.ac3Supported) {
PreferenceValidation.Invalid("AC3 support is not enabled")
} else if (value && it.downmixStereo) {
PreferenceValidation.Invalid("Always downmixing to stereo")
} else {
PreferenceValidation.Valid
}
}
},
)
val DownMixStereo =
AppSwitchPreference<AppPreferences>(
title = R.string.downmix_stereo,
defaultValue = false,
getter = { it.playbackPreferences.overrides.downmixStereo },
setter = { prefs, value ->
prefs.updatePlaybackOverrides { downmixStereo = value }
prefs.updatePlaybackOverrides {
downmixStereo = value
if (value) preferAc3Surround = false
}
},
summaryOn = R.string.enabled,
summaryOff = R.string.disabled,
@ -1066,6 +1100,7 @@ private val ExoPlayerSettings =
AppPreference.FfmpegPreference,
AppPreference.DownMixStereo,
AppPreference.Ac3Supported,
AppPreference.PreferAc3ForSurround,
AppPreference.DirectPlayAss,
AppPreference.DirectPlayPgs,
AppPreference.DirectPlayDoviProfile7,
@ -1206,11 +1241,16 @@ data class AppSwitchPreference<Pref>(
override val defaultValue: Boolean,
override val getter: (prefs: Pref) -> Boolean,
override val setter: (prefs: Pref, value: Boolean) -> Pref,
val validator: (value: Boolean) -> PreferenceValidation = { PreferenceValidation.Valid },
val validator: (prefs: Pref, value: Boolean) -> PreferenceValidation = { _, _ -> PreferenceValidation.Valid },
@param:StringRes val summary: Int? = null,
@param:StringRes val summaryOn: Int? = null,
@param:StringRes val summaryOff: Int? = null,
) : AppPreference<Pref, Boolean> {
override fun validate(
prefs: Pref,
value: Boolean,
): PreferenceValidation = validator.invoke(prefs, value)
override fun summary(
context: Context,
value: Boolean?,

View file

@ -44,6 +44,7 @@ class DeviceProfileService
pgsDirectPlay = prefs.overrides.directPlayPgs,
dolbyVisionELDirectPlay = prefs.overrides.directPlayDolbyVisionEL,
decodeAv1 = prefs.overrides.decodeAv1,
preferAc3ForSurround = prefs.overrides.preferAc3Surround,
jellyfinTenEleven =
serverVersion != null && serverVersion >= ServerVersion(10, 11, 0),
)
@ -59,6 +60,7 @@ class DeviceProfileService
pgsDirectPlay = newConfig.pgsDirectPlay,
dolbyVisionELDirectPlay = newConfig.dolbyVisionELDirectPlay,
decodeAv1 = prefs.overrides.decodeAv1,
preferAc3ForSurround = prefs.overrides.preferAc3Surround,
jellyfinTenEleven = newConfig.jellyfinTenEleven,
)
}
@ -78,5 +80,6 @@ data class DeviceProfileConfiguration(
val pgsDirectPlay: Boolean,
val dolbyVisionELDirectPlay: Boolean,
val decodeAv1: Boolean,
val preferAc3ForSurround: Boolean,
val jellyfinTenEleven: Boolean,
)

View file

@ -441,7 +441,7 @@ fun PreferencesContent(
value = value,
onNavigate = viewModel.navigationManager::navigateTo,
onValueChange = { newValue ->
val validation = pref.validate(newValue)
val validation = pref.validate(preferences, newValue)
when (validation) {
is PreferenceValidation.Invalid -> {
// TODO?

View file

@ -153,7 +153,7 @@ fun SubtitlePreferencesContent(
value = value,
onNavigate = viewModel.navigationManager::navigateTo,
onValueChange = { newValue ->
val validation = pref.validate(newValue)
val validation = pref.validate(preferences, newValue)
when (validation) {
is PreferenceValidation.Invalid -> {
// TODO?

View file

@ -71,6 +71,7 @@ fun createDeviceProfile(
dolbyVisionELDirectPlay: Boolean,
decodeAv1: Boolean,
jellyfinTenEleven: Boolean,
preferAc3ForSurround: Boolean,
) = buildDeviceProfile {
val allowedAudioCodecs =
when {
@ -132,6 +133,23 @@ fun createDeviceProfile(
// / Transcoding profiles
// Video
if (preferAc3ForSurround) {
transcodingProfile {
type = DlnaProfileType.VIDEO
context = EncodingContext.STREAMING
container = Codec.Container.TS
protocol = MediaStreamProtocol.HLS
if (supportsHevc) videoCodec(Codec.Video.HEVC)
videoCodec(Codec.Video.H264)
audioCodec(Codec.Audio.AC3)
copyTimestamps = false
enableSubtitlesInManifest = true
}
}
transcodingProfile {
type = DlnaProfileType.VIDEO
context = EncodingContext.STREAMING
@ -516,6 +534,33 @@ fun createDeviceProfile(
}
}
if (preferAc3ForSurround) {
codecProfile {
type = CodecType.VIDEO_AUDIO
codec = Codec.Audio.AAC
conditions {
ProfileConditionValue.AUDIO_PROFILE equals "none"
}
applyConditions {
ProfileConditionValue.AUDIO_CHANNELS greaterThanOrEquals 3
}
}
codecProfile {
type = CodecType.VIDEO_AUDIO
codec = Codec.Audio.OPUS
conditions {
ProfileConditionValue.AUDIO_PROFILE equals "none"
}
applyConditions {
ProfileConditionValue.AUDIO_CHANNELS greaterThanOrEquals 3
}
}
}
// Audio channel profile
codecProfile {
type = CodecType.VIDEO_AUDIO

View file

@ -48,6 +48,7 @@ message PlaybackOverrides{
MediaExtensionStatus media_extensions_enabled = 5;
bool direct_play_dolby_vision_e_l = 6;
bool decode_av1 = 7;
bool prefer_ac3_surround = 8;
}
message PlaybackPreferences {

View file

@ -522,6 +522,8 @@
<string name="display_presets">Display presets</string>
<string name="display_presets_description">Built-in presets to quickly style all rows</string>
<string name="customize_home_summary">Choose rows and images on the home page</string>
<string name="prefer_ac3_for_surround_summary"><![CDATA[Transcode 2+ channel audio to AC3/Dolby Digital]]></string>
<string name="prefer_ac3_for_surround">Use AC3 for surround sound audio</string>
<string-array name="theme_song_volume">
<item>Disabled</item>