1515 */
1616package androidx .media3 .exoplayer .source ;
1717
18+ import static androidx .media3 .common .util .Assertions .checkArgument ;
1819import static java .lang .Math .min ;
1920
2021import androidx .media3 .common .C ;
2122import androidx .media3 .common .util .UnstableApi ;
2223import androidx .media3 .exoplayer .LoadingInfo ;
24+ import com .google .common .collect .ImmutableList ;
25+ import java .util .Collections ;
26+ import java .util .List ;
2327
2428/** A {@link SequenceableLoader} that encapsulates multiple other {@link SequenceableLoader}s. */
2529@ UnstableApi
2630public final class CompositeSequenceableLoader implements SequenceableLoader {
2731
28- private final SequenceableLoader [] loaders ;
32+ private final ImmutableList <SequenceableLoaderWithTrackTypes > loadersWithTrackTypes ;
33+ private long lastAudioVideoBufferedPositionUs ;
2934
35+ /**
36+ * @deprecated Use {@link CompositeSequenceableLoader#CompositeSequenceableLoader(List, List)}
37+ * instead.
38+ */
39+ @ Deprecated
3040 public CompositeSequenceableLoader (SequenceableLoader [] loaders ) {
31- this .loaders = loaders ;
41+ this (
42+ ImmutableList .copyOf (loaders ),
43+ Collections .nCopies (loaders .length , ImmutableList .of (C .TRACK_TYPE_UNKNOWN )));
44+ }
45+
46+ public CompositeSequenceableLoader (
47+ List <? extends SequenceableLoader > loaders ,
48+ List <List <@ C .TrackType Integer >> loaderTrackTypes ) {
49+ ImmutableList .Builder <SequenceableLoaderWithTrackTypes > loaderAndTrackTypes =
50+ ImmutableList .builder ();
51+ checkArgument (loaders .size () == loaderTrackTypes .size ());
52+ for (int i = 0 ; i < loaders .size (); i ++) {
53+ loaderAndTrackTypes .add (
54+ new SequenceableLoaderWithTrackTypes (loaders .get (i ), loaderTrackTypes .get (i )));
55+ }
56+ this .loadersWithTrackTypes = loaderAndTrackTypes .build ();
57+ this .lastAudioVideoBufferedPositionUs = C .TIME_UNSET ;
3258 }
3359
3460 @ Override
3561 public long getBufferedPositionUs () {
3662 long bufferedPositionUs = Long .MAX_VALUE ;
37- for (SequenceableLoader loader : loaders ) {
63+ long bufferedPositionAudioVideoUs = Long .MAX_VALUE ;
64+ for (int i = 0 ; i < loadersWithTrackTypes .size (); i ++) {
65+ SequenceableLoaderWithTrackTypes loader = loadersWithTrackTypes .get (i );
3866 long loaderBufferedPositionUs = loader .getBufferedPositionUs ();
67+
68+ if (loader .getTrackTypes ().contains (C .TRACK_TYPE_AUDIO )
69+ || loader .getTrackTypes ().contains (C .TRACK_TYPE_VIDEO )
70+ || loader .getTrackTypes ().contains (C .TRACK_TYPE_IMAGE )) {
71+ if (loaderBufferedPositionUs != C .TIME_END_OF_SOURCE ) {
72+ bufferedPositionAudioVideoUs =
73+ min (bufferedPositionAudioVideoUs , loaderBufferedPositionUs );
74+ }
75+ }
3976 if (loaderBufferedPositionUs != C .TIME_END_OF_SOURCE ) {
4077 bufferedPositionUs = min (bufferedPositionUs , loaderBufferedPositionUs );
4178 }
4279 }
43- return bufferedPositionUs == Long .MAX_VALUE ? C .TIME_END_OF_SOURCE : bufferedPositionUs ;
80+ if (bufferedPositionAudioVideoUs != Long .MAX_VALUE ) {
81+ lastAudioVideoBufferedPositionUs = bufferedPositionAudioVideoUs ;
82+ return bufferedPositionAudioVideoUs ;
83+ } else if (bufferedPositionUs != Long .MAX_VALUE ) {
84+ // If lastAudioVideoBufferedPositionUs != C.TIME_UNSET, then we know there's at least one a/v
85+ // track (because this is the only time we end up assigning lastAudioVideoBufferedPositionUs
86+ // on a previous invocation).
87+ return lastAudioVideoBufferedPositionUs != C .TIME_UNSET
88+ ? lastAudioVideoBufferedPositionUs
89+ : bufferedPositionUs ;
90+ } else {
91+ return C .TIME_END_OF_SOURCE ;
92+ }
4493 }
4594
4695 @ Override
4796 public long getNextLoadPositionUs () {
4897 long nextLoadPositionUs = Long .MAX_VALUE ;
49- for (SequenceableLoader loader : loaders ) {
98+ for (int i = 0 ; i < loadersWithTrackTypes .size (); i ++) {
99+ SequenceableLoaderWithTrackTypes loader = loadersWithTrackTypes .get (i );
50100 long loaderNextLoadPositionUs = loader .getNextLoadPositionUs ();
51101 if (loaderNextLoadPositionUs != C .TIME_END_OF_SOURCE ) {
52102 nextLoadPositionUs = min (nextLoadPositionUs , loaderNextLoadPositionUs );
@@ -57,8 +107,8 @@ public long getNextLoadPositionUs() {
57107
58108 @ Override
59109 public void reevaluateBuffer (long positionUs ) {
60- for (SequenceableLoader loader : loaders ) {
61- loader .reevaluateBuffer (positionUs );
110+ for (int i = 0 ; i < loadersWithTrackTypes . size (); i ++ ) {
111+ loadersWithTrackTypes . get ( i ) .reevaluateBuffer (positionUs );
62112 }
63113 }
64114
@@ -72,13 +122,13 @@ public boolean continueLoading(LoadingInfo loadingInfo) {
72122 if (nextLoadPositionUs == C .TIME_END_OF_SOURCE ) {
73123 break ;
74124 }
75- for (SequenceableLoader loader : loaders ) {
76- long loaderNextLoadPositionUs = loader .getNextLoadPositionUs ();
125+ for (int i = 0 ; i < loadersWithTrackTypes . size (); i ++ ) {
126+ long loaderNextLoadPositionUs = loadersWithTrackTypes . get ( i ) .getNextLoadPositionUs ();
77127 boolean isLoaderBehind =
78128 loaderNextLoadPositionUs != C .TIME_END_OF_SOURCE
79129 && loaderNextLoadPositionUs <= loadingInfo .playbackPositionUs ;
80130 if (loaderNextLoadPositionUs == nextLoadPositionUs || isLoaderBehind ) {
81- madeProgressThisIteration |= loader .continueLoading (loadingInfo );
131+ madeProgressThisIteration |= loadersWithTrackTypes . get ( i ) .continueLoading (loadingInfo );
82132 }
83133 }
84134 madeProgress |= madeProgressThisIteration ;
@@ -88,11 +138,54 @@ public boolean continueLoading(LoadingInfo loadingInfo) {
88138
89139 @ Override
90140 public boolean isLoading () {
91- for (SequenceableLoader loader : loaders ) {
92- if (loader .isLoading ()) {
141+ for (int i = 0 ; i < loadersWithTrackTypes . size (); i ++ ) {
142+ if (loadersWithTrackTypes . get ( i ) .isLoading ()) {
93143 return true ;
94144 }
95145 }
96146 return false ;
97147 }
148+
149+ private static final class SequenceableLoaderWithTrackTypes implements SequenceableLoader {
150+
151+ private final SequenceableLoader loader ;
152+ private final ImmutableList <@ C .TrackType Integer > trackTypes ;
153+
154+ public SequenceableLoaderWithTrackTypes (
155+ SequenceableLoader loader , List <@ C .TrackType Integer > trackTypes ) {
156+ this .loader = loader ;
157+ this .trackTypes = ImmutableList .copyOf (trackTypes );
158+ }
159+
160+ public ImmutableList <@ C .TrackType Integer > getTrackTypes () {
161+ return trackTypes ;
162+ }
163+
164+ // SequenceableLoader implementation
165+
166+ @ Override
167+ public long getBufferedPositionUs () {
168+ return loader .getBufferedPositionUs ();
169+ }
170+
171+ @ Override
172+ public long getNextLoadPositionUs () {
173+ return loader .getNextLoadPositionUs ();
174+ }
175+
176+ @ Override
177+ public boolean continueLoading (LoadingInfo loadingInfo ) {
178+ return loader .continueLoading (loadingInfo );
179+ }
180+
181+ @ Override
182+ public boolean isLoading () {
183+ return loader .isLoading ();
184+ }
185+
186+ @ Override
187+ public void reevaluateBuffer (long positionUs ) {
188+ loader .reevaluateBuffer (positionUs );
189+ }
190+ }
98191}
0 commit comments