aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgnattu <gnattu@users.noreply.github.com>2025-04-09 09:22:30 +0800
committerGitHub <noreply@github.com>2025-04-08 19:22:30 -0600
commit32fe92d8f544d6dee1f0dfb5cccada649524084a (patch)
tree7d48373c16dfac57baf4f4a029224f7836bde3dc
parentc152f610ce4acb36d940c032bdf624c269d37d6b (diff)
Only reselect audio streams when user preference is respected (#13832)
-rw-r--r--Emby.Server.Implementations/Library/MediaSourceManager.cs10
-rw-r--r--Jellyfin.Api/Helpers/MediaInfoHelper.cs7
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs32
-rw-r--r--MediaBrowser.Model/Dto/MediaSourceInfo.cs4
-rw-r--r--MediaBrowser.Model/MediaInfo/AudioIndexSource.cs30
5 files changed, 79 insertions, 4 deletions
diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs
index afe5b14e9..c6cfd5391 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -427,6 +427,7 @@ namespace Emby.Server.Implementations.Library
if (source.MediaStreams.Any(i => i.Type == MediaStreamType.Audio && i.Index == index))
{
source.DefaultAudioStreamIndex = index;
+ source.DefaultAudioIndexSource = AudioIndexSource.User;
return;
}
}
@@ -434,6 +435,15 @@ namespace Emby.Server.Implementations.Library
var preferredAudio = NormalizeLanguage(user.AudioLanguagePreference);
source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.PlayDefaultAudioTrack);
+ if (user.PlayDefaultAudioTrack)
+ {
+ source.DefaultAudioIndexSource |= AudioIndexSource.Default;
+ }
+
+ if (preferredAudio.Count > 0)
+ {
+ source.DefaultAudioIndexSource |= AudioIndexSource.Language;
+ }
}
public void SetDefaultAudioAndSubtitleStreamIndices(BaseItem item, MediaSourceInfo source, User user)
diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs
index 63c9c173b..454d3f08e 100644
--- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs
+++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs
@@ -129,6 +129,13 @@ public class MediaInfoHelper
var mediaSourcesClone = JsonSerializer.Deserialize<MediaSourceInfo[]>(JsonSerializer.SerializeToUtf8Bytes(mediaSources));
if (mediaSourcesClone is not null)
{
+ // Carry over the default audio index source.
+ // This field is not intended to be exposed to API clients, but it is used internally by the server
+ for (int i = 0; i < mediaSourcesClone.Length && i < mediaSources.Length; i++)
+ {
+ mediaSourcesClone[i].DefaultAudioIndexSource = mediaSources[i].DefaultAudioIndexSource;
+ }
+
result.MediaSources = mediaSourcesClone;
}
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 806900e9a..61e04a813 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -665,15 +665,39 @@ namespace MediaBrowser.Model.Dlna
// Collect candidate audio streams
ICollection<MediaStream> candidateAudioStreams = audioStream is null ? [] : [audioStream];
- if (!options.AudioStreamIndex.HasValue || options.AudioStreamIndex < 0)
+ // When the index is explicitly required by client or the default is specified by user, don't do any stream reselection.
+ if (!item.DefaultAudioIndexSource.HasFlag(AudioIndexSource.User) && (options.AudioStreamIndex is null or < 0))
{
- if (audioStream?.IsDefault == true)
+ // When user has no preferences allow stream selection on all streams.
+ if (item.DefaultAudioIndexSource == AudioIndexSource.None && audioStream is not null)
{
- candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.IsDefault).ToArray();
+ candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio).ToArray();
+ if (audioStream.IsDefault)
+ {
+ // If default is picked, only allow selection within default streams.
+ candidateAudioStreams = candidateAudioStreams.Where(stream => stream.IsDefault).ToArray();
+ }
}
- else
+
+ if (item.DefaultAudioIndexSource.HasFlag(AudioIndexSource.Language))
{
+ // If user has language preference, only allow stream selection within the same language.
candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.Language == audioStream?.Language).ToArray();
+ if (item.DefaultAudioIndexSource.HasFlag(AudioIndexSource.Default))
+ {
+ var defaultStreamsInPreferredLanguage = candidateAudioStreams.Where(stream => stream.IsDefault).ToArray();
+
+ // If the user also prefers default streams, try limit selection within default tracks in the same language.
+ // If there is no default stream in the preferred language, allow selection on all default streams to match the "Play default audio track regardless of language" setting.
+ candidateAudioStreams = defaultStreamsInPreferredLanguage.Length > 0
+ ? defaultStreamsInPreferredLanguage
+ : item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.IsDefault).ToArray();
+ }
+ }
+ else if (item.DefaultAudioIndexSource.HasFlag(AudioIndexSource.Default))
+ {
+ // If user prefers default streams, only allow stream selection on default streams.
+ candidateAudioStreams = item.MediaStreams.Where(stream => stream.Type == MediaStreamType.Audio && stream.IsDefault).ToArray();
}
}
diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
index 66de18cfe..75ccdcf27 100644
--- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs
+++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
@@ -24,6 +24,7 @@ namespace MediaBrowser.Model.Dto
SupportsDirectPlay = true;
SupportsProbing = true;
UseMostCompatibleTranscodingProfile = false;
+ DefaultAudioIndexSource = AudioIndexSource.None;
}
public MediaProtocol Protocol { get; set; }
@@ -118,6 +119,9 @@ namespace MediaBrowser.Model.Dto
[JsonIgnore]
public TranscodeReason TranscodeReasons { get; set; }
+ [JsonIgnore]
+ public AudioIndexSource DefaultAudioIndexSource { get; set; }
+
public int? DefaultAudioStreamIndex { get; set; }
public int? DefaultSubtitleStreamIndex { get; set; }
diff --git a/MediaBrowser.Model/MediaInfo/AudioIndexSource.cs b/MediaBrowser.Model/MediaInfo/AudioIndexSource.cs
new file mode 100644
index 000000000..810087b92
--- /dev/null
+++ b/MediaBrowser.Model/MediaInfo/AudioIndexSource.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace MediaBrowser.Model.MediaInfo;
+
+/// <summary>
+/// How is the audio index determined.
+/// </summary>
+[Flags]
+public enum AudioIndexSource
+{
+ /// <summary>
+ /// The default index when no preference is specified.
+ /// </summary>
+ None = 0,
+
+ /// <summary>
+ /// The index is calculated whether the track is marked as default or not.
+ /// </summary>
+ Default = 1 << 0,
+
+ /// <summary>
+ /// The index is calculated whether the track is in preferred language or not.
+ /// </summary>
+ Language = 1 << 1,
+
+ /// <summary>
+ /// The index is specified by the user.
+ /// </summary>
+ User = 1 << 2
+}