-
-
Notifications
You must be signed in to change notification settings - Fork 524
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add preferences to configure audio codecs and 4k transcoding/direct play #3110
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ import android.content.Context | |
import android.view.KeyEvent | ||
import androidx.preference.PreferenceManager | ||
import org.jellyfin.androidtv.preference.constant.AppTheme | ||
import org.jellyfin.androidtv.preference.constant.AudioTranscodeTarget | ||
import org.jellyfin.androidtv.preference.constant.ClockBehavior | ||
import org.jellyfin.androidtv.preference.constant.NextUpBehavior | ||
import org.jellyfin.androidtv.preference.constant.PreferredVideoPlayer | ||
|
@@ -100,6 +101,11 @@ class UserPreferences(context: Context) : SharedPreferenceStore( | |
*/ | ||
var refreshRateSwitchingBehavior = enumPreference("refresh_rate_switching_behavior", RefreshRateSwitchingBehavior.DISABLED) | ||
|
||
/** | ||
* Enable 4k codecs for direct play and transcode target | ||
*/ | ||
var enable4kSupport = booleanPreference("pref_enable_4k_support", DeviceUtils.has4kVideoSupport()) | ||
|
||
/* Playback - Audio related */ | ||
/** | ||
* Preferred behavior for audio streaming. | ||
|
@@ -111,6 +117,21 @@ class UserPreferences(context: Context) : SharedPreferenceStore( | |
*/ | ||
var audioNightMode = enumPreference("audio_night_mode", false) | ||
|
||
/** | ||
* Enable mp2/mp3 | ||
*/ | ||
var mpegEnabled = booleanPreference("pref_bitstream_mpeg", true) | ||
|
||
/** | ||
* Enable PCM | ||
*/ | ||
var pcmEnabled = booleanPreference("pref_bitstream_pcm", true) | ||
|
||
/** | ||
* Enable AAC | ||
*/ | ||
var aacEnabled = booleanPreference("pref_bitstream_aac", true) | ||
|
||
/** | ||
* Enable DTS | ||
*/ | ||
|
@@ -121,6 +142,26 @@ class UserPreferences(context: Context) : SharedPreferenceStore( | |
*/ | ||
var ac3Enabled = booleanPreference("pref_bitstream_ac3", !DeviceUtils.isFireTvStickGen1) | ||
|
||
/** | ||
* Enable EAC3 | ||
*/ | ||
var eac3Enabled = booleanPreference("pref_bitstream_eac3", !DeviceUtils.isFireTvStickGen1) | ||
|
||
/** | ||
* Enable TrueUD | ||
*/ | ||
var thdEnabled = booleanPreference("pref_bitstream_thd", false) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should shorten this to |
||
|
||
/** | ||
* Enable Other | ||
*/ | ||
var otherAudioEnabled = booleanPreference("pref_bitstream_other_audio", false) | ||
|
||
/** | ||
* Preferred audio transcode target codec | ||
*/ | ||
var audioTranscodeTarget = enumPreference("audio_transcode_target", AudioTranscodeTarget.AUTO) | ||
|
||
/** | ||
* Default audio delay in milliseconds for libVLC | ||
*/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package org.jellyfin.androidtv.preference.constant | ||
|
||
import org.jellyfin.androidtv.R | ||
import org.jellyfin.preference.PreferenceEnum | ||
|
||
enum class AudioTranscodeTarget( | ||
override val nameRes: Int, | ||
) : PreferenceEnum { | ||
/** | ||
* Enable all codecs | ||
*/ | ||
AUTO(R.string.lbl_audiotarget_auto), | ||
|
||
PCM(R.string.lbl_codec_pcm), | ||
|
||
AAC(R.string.lbl_codec_aac), | ||
|
||
AC3(R.string.lbl_codec_ac3), | ||
|
||
EAC3(R.string.lbl_codec_eac3), | ||
|
||
DTS(R.string.lbl_codec_dts) | ||
} |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -12,8 +12,10 @@ | |||||||
import androidx.annotation.NonNull; | ||||||||
import androidx.annotation.Nullable; | ||||||||
|
||||||||
import org.acra.config.CoreConfiguration; | ||||||||
import org.jellyfin.androidtv.R; | ||||||||
import org.jellyfin.androidtv.auth.repository.UserRepository; | ||||||||
import org.jellyfin.androidtv.constant.Codec; | ||||||||
import org.jellyfin.androidtv.data.compat.PlaybackException; | ||||||||
import org.jellyfin.androidtv.data.compat.StreamInfo; | ||||||||
import org.jellyfin.androidtv.data.compat.SubtitleStreamInfo; | ||||||||
|
@@ -22,6 +24,7 @@ | |||||||
import org.jellyfin.androidtv.preference.SystemPreferences; | ||||||||
import org.jellyfin.androidtv.preference.UserPreferences; | ||||||||
import org.jellyfin.androidtv.preference.UserSettingPreferences; | ||||||||
import org.jellyfin.androidtv.preference.constant.AudioTranscodeTarget; | ||||||||
import org.jellyfin.androidtv.preference.constant.NextUpBehavior; | ||||||||
import org.jellyfin.androidtv.preference.constant.PreferredVideoPlayer; | ||||||||
import org.jellyfin.androidtv.preference.constant.RefreshRateSwitchingBehavior; | ||||||||
|
@@ -51,6 +54,8 @@ | |||||||
import org.jellyfin.sdk.model.api.PlayAccess; | ||||||||
import org.koin.java.KoinJavaComponent; | ||||||||
|
||||||||
import java.util.ArrayList; | ||||||||
import java.util.Arrays; | ||||||||
import java.util.List; | ||||||||
|
||||||||
import kotlin.Lazy; | ||||||||
|
@@ -569,12 +574,84 @@ private VideoOptions buildExoPlayerOptions(@Nullable Integer forcedSubtitleIndex | |||||||
DeviceProfile internalProfile = new ExoPlayerProfile( | ||||||||
mFragment.getContext(), | ||||||||
isLiveTv && !userPreferences.getValue().get(UserPreferences.Companion.getLiveTvDirectPlayEnabled()), | ||||||||
userPreferences.getValue().get(UserPreferences.Companion.getAc3Enabled()) | ||||||||
getDirectPlayPreferences(), | ||||||||
getAudioTranscodeTarget(), | ||||||||
userPreferences.getValue().get(UserPreferences.Companion.getEnable4kSupport()) | ||||||||
); | ||||||||
internalOptions.setProfile(internalProfile); | ||||||||
return internalOptions; | ||||||||
} | ||||||||
|
||||||||
@NonNull | ||||||||
private String[] getDirectPlayPreferences() { | ||||||||
ArrayList<String> codecs = new ArrayList<>(); | ||||||||
|
||||||||
if(userPreferences.getValue().get(UserPreferences.Companion.getMpegEnabled())) { | ||||||||
codecs.add(Codec.Audio.MP2); | ||||||||
codecs.add(Codec.Audio.MP3); | ||||||||
} | ||||||||
|
||||||||
if(userPreferences.getValue().get(UserPreferences.Companion.getAacEnabled())) { | ||||||||
codecs.add(Codec.Audio.AAC); | ||||||||
codecs.add(Codec.Audio.AAC_LATM); | ||||||||
} | ||||||||
|
||||||||
if(userPreferences.getValue().get(UserPreferences.Companion.getAc3Enabled())) { | ||||||||
codecs.add(Codec.Audio.AC3); | ||||||||
} | ||||||||
|
||||||||
if(userPreferences.getValue().get(UserPreferences.Companion.getEac3Enabled())) { | ||||||||
codecs.add(Codec.Audio.EAC3); | ||||||||
} | ||||||||
|
||||||||
if(userPreferences.getValue().get(UserPreferences.Companion.getDtsEnabled())) { | ||||||||
codecs.add(Codec.Audio.DTS); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
} | ||||||||
|
||||||||
if(userPreferences.getValue().get(UserPreferences.Companion.getThdEnabled())) { | ||||||||
codecs.add(Codec.Audio.TRUEHD); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
} | ||||||||
|
||||||||
if(userPreferences.getValue().get(UserPreferences.Companion.getPcmEnabled())) { | ||||||||
codecs.add(Codec.Audio.PCM_ALAW); | ||||||||
codecs.add(Codec.Audio.PCM_MULAW); | ||||||||
} | ||||||||
|
||||||||
if(userPreferences.getValue().get(UserPreferences.Companion.getOtherAudioEnabled())) { | ||||||||
codecs.add(Codec.Audio.DCA); | ||||||||
codecs.add(Codec.Audio.MLP); | ||||||||
Comment on lines
+621
to
+622
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
codecs.add(Codec.Audio.OPUS); | ||||||||
codecs.add(Codec.Audio.FLAC); | ||||||||
Comment on lines
+623
to
+624
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since you’re adding a new panel and there are only two other codecs, I would add them as separate options. |
||||||||
} | ||||||||
|
||||||||
return codecs.toArray(new String[0]); | ||||||||
} | ||||||||
|
||||||||
@NonNull | ||||||||
private String[] getAudioTranscodeTarget() { | ||||||||
AudioTranscodeTarget target = userPreferences.getValue().get(UserPreferences.Companion.getAudioTranscodeTarget()); | ||||||||
switch (target) { | ||||||||
case AUTO: | ||||||||
String[] directPlayCodecs = getDirectPlayPreferences(); | ||||||||
// If any codecs are enabled, return those | ||||||||
if(directPlayCodecs.length > 0) return directPlayCodecs; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
// Otherwise fallback to MP3 | ||||||||
return new String[]{ Codec.Audio.MP3 }; | ||||||||
case AAC: | ||||||||
return new String[] { Codec.Audio.AAC, Codec.Audio.AAC_LATM }; | ||||||||
case DTS: | ||||||||
return new String[]{ Codec.Audio.DTS }; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
case PCM: | ||||||||
return new String[]{ Codec.Audio.PCM_ALAW, Codec.Audio.PCM_MULAW }; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When trying to transcode to DTS or PCM (original files in an MKV container), the server sends an incompatible file container message and remuxes the file with the original audio and video. I would consider removing these as transcoding options. |
||||||||
case AC3: | ||||||||
return new String[]{ Codec.Audio.AC3 }; | ||||||||
case EAC3: | ||||||||
return new String[]{ Codec.Audio.EAC3 }; | ||||||||
default: | ||||||||
throw new IllegalArgumentException("Unknown audio transcode target preference"); | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
@NonNull | ||||||||
private VideoOptions buildVLCOptions(@Nullable Integer forcedSubtitleIndex, org.jellyfin.sdk.model.api.BaseItemDto item, int maxBitrate) { | ||||||||
VideoOptions vlcOptions = new VideoOptions(); | ||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ import org.jellyfin.androidtv.R | |
import org.jellyfin.androidtv.constant.getQualityProfiles | ||
import org.jellyfin.androidtv.preference.UserPreferences | ||
import org.jellyfin.androidtv.preference.constant.AudioBehavior | ||
import org.jellyfin.androidtv.preference.constant.AudioTranscodeTarget | ||
import org.jellyfin.androidtv.preference.constant.NEXTUP_TIMER_DISABLED | ||
import org.jellyfin.androidtv.preference.constant.NextUpBehavior | ||
import org.jellyfin.androidtv.preference.constant.PreferredVideoPlayer | ||
|
@@ -107,6 +108,12 @@ class PlaybackPreferencesScreen : OptionsFragment() { | |
bind(userPreferences, UserPreferences.refreshRateSwitchingBehavior) | ||
depends { DeviceUtils.is60() && userPreferences[UserPreferences.videoPlayer] != PreferredVideoPlayer.EXTERNAL } | ||
} | ||
|
||
checkbox { | ||
setTitle(R.string.pref_enable_4k_support) | ||
setContent(R.string.pref_enable_4k_support_description) | ||
bind(userPreferences, UserPreferences.enable4kSupport) | ||
} | ||
} | ||
|
||
category { | ||
|
@@ -171,27 +178,19 @@ class PlaybackPreferencesScreen : OptionsFragment() { | |
depends { userPreferences[UserPreferences.videoPlayer] != PreferredVideoPlayer.EXTERNAL } | ||
} | ||
|
||
enum<AudioTranscodeTarget> { | ||
setTitle(R.string.pref_audio_transcodetarget) | ||
bind(userPreferences, UserPreferences.audioTranscodeTarget) | ||
depends { userPreferences[UserPreferences.videoPlayer] != PreferredVideoPlayer.EXTERNAL } | ||
} | ||
|
||
checkbox { | ||
setTitle(R.string.pref_audio_night_mode) | ||
setContent(R.string.desc_audio_night_mode) | ||
bind(userPreferences, UserPreferences.audioNightMode) | ||
depends { Build.VERSION.SDK_INT >= Build.VERSION_CODES.P } | ||
} | ||
|
||
checkbox { | ||
setTitle(R.string.lbl_bitstream_ac3) | ||
setContent(R.string.desc_bitstream_ac3) | ||
bind(userPreferences, UserPreferences.ac3Enabled) | ||
depends { userPreferences[UserPreferences.videoPlayer] != PreferredVideoPlayer.EXTERNAL } | ||
} | ||
|
||
checkbox { | ||
setTitle(R.string.lbl_bitstream_dts) | ||
setContent(R.string.desc_bitstream_ac3) | ||
bind(userPreferences, UserPreferences.dtsEnabled) | ||
depends { userPreferences[UserPreferences.videoPlayer] != PreferredVideoPlayer.EXTERNAL } | ||
} | ||
|
||
@Suppress("MagicNumber") | ||
seekbar { | ||
setTitle(R.string.pref_libvlc_audio_delay_title) | ||
|
@@ -204,6 +203,66 @@ class PlaybackPreferencesScreen : OptionsFragment() { | |
} | ||
} | ||
|
||
category { | ||
setTitle(R.string.pref_audio_directplay) | ||
Comment on lines
+206
to
+207
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be better if add a new preference screen for this category. You can look at |
||
|
||
checkbox { | ||
setTitle(R.string.lbl_codec_mpeg) | ||
setContent(R.string.desc_bitstream_generic) | ||
bind(userPreferences, UserPreferences.mpegEnabled) | ||
depends { userPreferences[UserPreferences.videoPlayer] != PreferredVideoPlayer.EXTERNAL } | ||
} | ||
|
||
checkbox { | ||
setTitle(R.string.lbl_codec_pcm) | ||
setContent(R.string.desc_bitstream_generic) | ||
bind(userPreferences, UserPreferences.pcmEnabled) | ||
depends { userPreferences[UserPreferences.videoPlayer] != PreferredVideoPlayer.EXTERNAL } | ||
} | ||
|
||
checkbox { | ||
setTitle(R.string.lbl_codec_aac) | ||
setContent(R.string.desc_bitstream_generic) | ||
bind(userPreferences, UserPreferences.aacEnabled) | ||
depends { userPreferences[UserPreferences.videoPlayer] != PreferredVideoPlayer.EXTERNAL } | ||
} | ||
|
||
checkbox { | ||
setTitle(R.string.lbl_codec_dts) | ||
setContent(R.string.desc_bitstream_generic) | ||
bind(userPreferences, UserPreferences.dtsEnabled) | ||
depends { userPreferences[UserPreferences.videoPlayer] != PreferredVideoPlayer.EXTERNAL } | ||
} | ||
|
||
checkbox { | ||
setTitle(R.string.lbl_codec_ac3) | ||
setContent(R.string.desc_bitstream_generic) | ||
bind(userPreferences, UserPreferences.ac3Enabled) | ||
depends { userPreferences[UserPreferences.videoPlayer] != PreferredVideoPlayer.EXTERNAL } | ||
} | ||
|
||
checkbox { | ||
setTitle(R.string.lbl_codec_eac3) | ||
setContent(R.string.desc_bitstream_generic) | ||
bind(userPreferences, UserPreferences.eac3Enabled) | ||
depends { userPreferences[UserPreferences.videoPlayer] != PreferredVideoPlayer.EXTERNAL } | ||
} | ||
|
||
checkbox { | ||
setTitle(R.string.lbl_codec_thd) | ||
setContent(R.string.desc_bitstream_generic) | ||
bind(userPreferences, UserPreferences.thdEnabled) | ||
depends { userPreferences[UserPreferences.videoPlayer] != PreferredVideoPlayer.EXTERNAL } | ||
} | ||
|
||
checkbox { | ||
setTitle(R.string.lbl_codec_other) | ||
setContent(R.string.desc_bitstream_generic) | ||
bind(userPreferences, UserPreferences.otherAudioEnabled) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As commented above, I think it makes sense to split out OPUS and FLAC as separate options. |
||
depends { userPreferences[UserPreferences.videoPlayer] != PreferredVideoPlayer.EXTERNAL } | ||
} | ||
} | ||
|
||
category { | ||
setTitle(R.string.pref_music_cat) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Preference keys should not start with
pref_
. This is only used on old keys for compatibility reasons (creating a migration just for a rename of the key is kinda pointless)