@@ -426,6 +426,7 @@ public void play(long position) {
426426
427427 protected void play (long position , @ Nullable Integer forcedSubtitleIndex ) {
428428 String forcedAudioLanguage = videoQueueManager .getValue ().getLastPlayedAudioLanguageIsoCode ();
429+ String forcedAudioCodec = videoQueueManager .getValue ().getLastPlayedAudioCodec ();
429430 Timber .i ("Play called from state: %s with pos: %d, sub index: %d and forced audio: %s" , mPlaybackState , position , forcedSubtitleIndex , forcedAudioLanguage );
430431
431432 if (mFragment == null ) {
@@ -515,7 +516,7 @@ public void onClick(DialogInterface dialog, int which) {
515516 // undo setting mSeekPosition for liveTV
516517 if (isLiveTv ) mSeekPosition = -1 ;
517518
518- VideoOptions internalOptions = buildExoPlayerOptions (forcedSubtitleIndex , forcedAudioLanguage , item );
519+ VideoOptions internalOptions = buildExoPlayerOptions (forcedSubtitleIndex , forcedAudioLanguage , forcedAudioCodec , item );
519520
520521 playInternal (getCurrentlyPlayingItem (), position , internalOptions );
521522 mPlaybackState = PlaybackState .BUFFERING ;
@@ -534,6 +535,7 @@ public void onClick(DialogInterface dialog, int which) {
534535 private VideoOptions buildExoPlayerOptions (
535536 @ Nullable Integer forcedSubtitleIndex ,
536537 @ Nullable String forcedAudioLanguage ,
538+ @ Nullable String forcedAudioCodec ,
537539 BaseItemDto item ) {
538540 VideoOptions internalOptions = new VideoOptions ();
539541 internalOptions .setItemId (item .getId ());
@@ -557,14 +559,27 @@ private VideoOptions buildExoPlayerOptions(
557559 internalOptions .setSubtitleStreamIndex (forcedSubtitleIndex );
558560 }
559561 MediaSourceInfo currentMediaSource = getCurrentMediaSource ();
560- if (forcedAudioLanguage != null ) {
561- // find the first audio stream with the requested language
562- for (MediaStream stream : currentMediaSource .getMediaStreams ()) {
563- if (stream .getType () == MediaStreamType .AUDIO && forcedAudioLanguage .equals (stream .getLanguage ())) {
564- internalOptions .setAudioStreamIndex (stream .getIndex ());
565- break ;
562+ if (forcedAudioLanguage != null ){
563+ Integer matchingIndex = null ;
564+ if (forcedAudioCodec != null ) {
565+ // find the first audio stream with the requested language and codec
566+ for (MediaStream stream : currentMediaSource .getMediaStreams ()) {
567+ if (stream .getType () == MediaStreamType .AUDIO && forcedAudioLanguage .equals (stream .getLanguage ()) && forcedAudioCodec .equals (stream .getCodec ())) {
568+ matchingIndex = stream .getIndex ();
569+ break ;
570+ }
571+ }
572+ }
573+ if (matchingIndex == null ) {
574+ // find the first audio stream with the requested language (fallback to language only)
575+ for (MediaStream stream : currentMediaSource .getMediaStreams ()) {
576+ if (stream .getType () == MediaStreamType .AUDIO && forcedAudioLanguage .equals (stream .getLanguage ())) {
577+ matchingIndex = stream .getIndex ();
578+ break ;
579+ }
566580 }
567581 }
582+ internalOptions .setAudioStreamIndex (matchingIndex );
568583 }
569584 if (storedAudioIndex != null ) {
570585 internalOptions .setAudioStreamIndex (storedAudioIndex );
@@ -676,17 +691,41 @@ private void startItem(BaseItemDto item, long position, StreamInfo response) {
676691 if (!TrackSelectionManager .INSTANCE .hasSelectedSubtitleTrack (item .getId ())) {
677692 // get subtitle info - prefer saved language preference over server default
678693 String lastSubtitleLanguage = videoQueueManager .getValue ().getLastPlayedSubtitleLanguageIsoCode ();
694+ Boolean lastSubtitleForcedState = videoQueueManager .getValue ().getLastPlayedSubtitleForcedState ();
695+ String lastSubtitleCodec = videoQueueManager .getValue ().getLastPlayedSubtitleCodec ();
696+ String lastSubtitleTitle = videoQueueManager .getValue ().getLastPlayedSubtitleTitle ();
679697 if (lastSubtitleLanguage != null ) {
680698 if (lastSubtitleLanguage .isEmpty ()) {
681699 // User explicitly disabled subtitles
682700 mCurrentOptions .setSubtitleStreamIndex (null );
683701 } else if (response .getMediaSource ().getMediaStreams () != null ) {
684702 // Find subtitle stream matching saved language
685703 Integer matchingIndex = null ;
686- for (MediaStream stream : response .getMediaSource ().getMediaStreams ()) {
687- if (stream .getType () == MediaStreamType .SUBTITLE && lastSubtitleLanguage .equals (stream .getLanguage ())) {
688- matchingIndex = stream .getIndex ();
689- break ;
704+ // Try with all previous subtitle info (title, codec, forced state, language)
705+ if (lastSubtitleCodec != null && lastSubtitleTitle != null ) {
706+ for (MediaStream stream : response .getMediaSource ().getMediaStreams ()) {
707+ if (stream .getType () == MediaStreamType .SUBTITLE && lastSubtitleLanguage .equals (stream .getLanguage ()) && lastSubtitleForcedState .equals (stream .isForced ()) && lastSubtitleCodec .equals (stream .getCodec ()) && lastSubtitleTitle .equals (stream .getTitle ())) {
708+ matchingIndex = stream .getIndex ();
709+ break ;
710+ }
711+ }
712+ }
713+ // Fallback without title (codec, forced state, language)
714+ if (matchingIndex == null && lastSubtitleCodec != null ) {
715+ for (MediaStream stream : response .getMediaSource ().getMediaStreams ()) {
716+ if (stream .getType () == MediaStreamType .SUBTITLE && lastSubtitleLanguage .equals (stream .getLanguage ()) && lastSubtitleForcedState .equals (stream .isForced ()) && lastSubtitleCodec .equals (stream .getCodec ())) {
717+ matchingIndex = stream .getIndex ();
718+ break ;
719+ }
720+ }
721+ }
722+ // Fallback without codec (forced state, language)
723+ if (matchingIndex == null ) {
724+ for (MediaStream stream : response .getMediaSource ().getMediaStreams ()) {
725+ if (stream .getType () == MediaStreamType .SUBTITLE && lastSubtitleLanguage .equals (stream .getLanguage ()) && lastSubtitleForcedState .equals (stream .isForced ())) {
726+ matchingIndex = stream .getIndex ();
727+ break ;
728+ }
690729 }
691730 }
692731 mCurrentOptions .setSubtitleStreamIndex (matchingIndex );
@@ -788,6 +827,22 @@ private Integer lastChosenLanguageAudioTrack(MediaSourceInfo info) {
788827 return null ;
789828
790829 boolean videoFound = false ;
830+ for (MediaStream track : info .getMediaStreams ()) {
831+ if (track .getType () == MediaStreamType .VIDEO ) {
832+ videoFound = true ;
833+ } else {
834+ if (videoFound
835+ && track .getType () == MediaStreamType .AUDIO
836+ && (track .getLanguage () != null
837+ && track .getLanguage ().equals (videoQueueManager .getValue ().getLastPlayedAudioLanguageIsoCode ())
838+ && (track .getCodec () != null
839+ && track .getCodec ().equals (videoQueueManager .getValue ().getLastPlayedAudioCodec ())))
840+ )
841+ return track .getIndex ();
842+ }
843+ }
844+
845+ videoFound = false ;
791846 for (MediaStream track : info .getMediaStreams ()) {
792847 if (track .getType () == MediaStreamType .VIDEO ) {
793848 videoFound = true ;
@@ -830,14 +885,13 @@ public void switchAudioStream(int index) {
830885 return ;
831886 }
832887
833- String lastAudioIsoCode = videoQueueManager .getValue ().getLastPlayedAudioLanguageIsoCode ();
834888 String currentAudioIsoCode = currentMediaSource .getMediaStreams ().get (index ).getLanguage ();
835-
836- if ( currentAudioIsoCode != null
837- && ( lastAudioIsoCode == null || ! lastAudioIsoCode . equals ( currentAudioIsoCode ))) {
838- videoQueueManager . getValue (). setLastPlayedAudioLanguageIsoCode (
839- currentAudioIsoCode
840- );
889+ if ( currentAudioIsoCode != null ) {
890+ videoQueueManager . getValue (). setLastPlayedAudioLanguageIsoCode ( currentAudioIsoCode );
891+ String currentAudioCodec = currentMediaSource . getMediaStreams (). get ( index ). getCodec ();
892+ if ( currentAudioCodec != null ) {
893+ videoQueueManager . getValue (). setLastPlayedAudioCodec ( currentAudioCodec );
894+ }
841895 }
842896
843897 int currAudioIndex = getAudioStreamIndex ();
0 commit comments