1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.mozilla.thirdparty.com.google.android.exoplayer2;
17 
18 import androidx.annotation.Nullable;
19 import org.mozilla.thirdparty.com.google.android.exoplayer2.source.SampleStream;
20 import org.mozilla.thirdparty.com.google.android.exoplayer2.util.Assertions;
21 import org.mozilla.thirdparty.com.google.android.exoplayer2.util.MediaClock;
22 import java.io.IOException;
23 import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
24 
25 /**
26  * A {@link Renderer} implementation whose track type is {@link C#TRACK_TYPE_NONE} and does not
27  * consume data from its {@link SampleStream}.
28  */
29 public abstract class NoSampleRenderer implements Renderer, RendererCapabilities {
30 
31   @MonotonicNonNull private RendererConfiguration configuration;
32   private int index;
33   private int state;
34   @Nullable private SampleStream stream;
35   private boolean streamIsFinal;
36 
37   @Override
getTrackType()38   public final int getTrackType() {
39     return C.TRACK_TYPE_NONE;
40   }
41 
42   @Override
getCapabilities()43   public final RendererCapabilities getCapabilities() {
44     return this;
45   }
46 
47   @Override
setIndex(int index)48   public final void setIndex(int index) {
49     this.index = index;
50   }
51 
52   @Override
53   @Nullable
getMediaClock()54   public MediaClock getMediaClock() {
55     return null;
56   }
57 
58   @Override
getState()59   public final int getState() {
60     return state;
61   }
62 
63   /**
64    * Replaces the {@link SampleStream} that will be associated with this renderer.
65    * <p>
66    * This method may be called when the renderer is in the following states:
67    * {@link #STATE_DISABLED}.
68    *
69    * @param configuration The renderer configuration.
70    * @param formats The enabled formats. Should be empty.
71    * @param stream The {@link SampleStream} from which the renderer should consume.
72    * @param positionUs The player's current position.
73    * @param joining Whether this renderer is being enabled to join an ongoing playback.
74    * @param offsetUs The offset that should be subtracted from {@code positionUs}
75    *     to get the playback position with respect to the media.
76    * @throws ExoPlaybackException If an error occurs.
77    */
78   @Override
enable(RendererConfiguration configuration, Format[] formats, SampleStream stream, long positionUs, boolean joining, long offsetUs)79   public final void enable(RendererConfiguration configuration, Format[] formats,
80       SampleStream stream, long positionUs, boolean joining, long offsetUs)
81       throws ExoPlaybackException {
82     Assertions.checkState(state == STATE_DISABLED);
83     this.configuration = configuration;
84     state = STATE_ENABLED;
85     onEnabled(joining);
86     replaceStream(formats, stream, offsetUs);
87     onPositionReset(positionUs, joining);
88   }
89 
90   @Override
start()91   public final void start() throws ExoPlaybackException {
92     Assertions.checkState(state == STATE_ENABLED);
93     state = STATE_STARTED;
94     onStarted();
95   }
96 
97   /**
98    * Replaces the {@link SampleStream} that will be associated with this renderer.
99    * <p>
100    * This method may be called when the renderer is in the following states:
101    * {@link #STATE_ENABLED}, {@link #STATE_STARTED}.
102    *
103    * @param formats The enabled formats. Should be empty.
104    * @param stream The {@link SampleStream} to be associated with this renderer.
105    * @param offsetUs The offset that should be subtracted from {@code positionUs} in
106    *     {@link #render(long, long)} to get the playback position with respect to the media.
107    * @throws ExoPlaybackException If an error occurs.
108    */
109   @Override
replaceStream(Format[] formats, SampleStream stream, long offsetUs)110   public final void replaceStream(Format[] formats, SampleStream stream, long offsetUs)
111       throws ExoPlaybackException {
112     Assertions.checkState(!streamIsFinal);
113     this.stream = stream;
114     onRendererOffsetChanged(offsetUs);
115   }
116 
117   @Override
118   @Nullable
getStream()119   public final SampleStream getStream() {
120     return stream;
121   }
122 
123   @Override
hasReadStreamToEnd()124   public final boolean hasReadStreamToEnd() {
125     return true;
126   }
127 
128   @Override
getReadingPositionUs()129   public long getReadingPositionUs() {
130     return C.TIME_END_OF_SOURCE;
131   }
132 
133   @Override
setCurrentStreamFinal()134   public final void setCurrentStreamFinal() {
135     streamIsFinal = true;
136   }
137 
138   @Override
isCurrentStreamFinal()139   public final boolean isCurrentStreamFinal() {
140     return streamIsFinal;
141   }
142 
143   @Override
maybeThrowStreamError()144   public final void maybeThrowStreamError() throws IOException {
145   }
146 
147   @Override
resetPosition(long positionUs)148   public final void resetPosition(long positionUs) throws ExoPlaybackException {
149     streamIsFinal = false;
150     onPositionReset(positionUs, false);
151   }
152 
153   @Override
stop()154   public final void stop() throws ExoPlaybackException {
155     Assertions.checkState(state == STATE_STARTED);
156     state = STATE_ENABLED;
157     onStopped();
158   }
159 
160   @Override
disable()161   public final void disable() {
162     Assertions.checkState(state == STATE_ENABLED);
163     state = STATE_DISABLED;
164     stream = null;
165     streamIsFinal = false;
166     onDisabled();
167   }
168 
169   @Override
reset()170   public final void reset() {
171     Assertions.checkState(state == STATE_DISABLED);
172     onReset();
173   }
174 
175   @Override
isReady()176   public boolean isReady() {
177     return true;
178   }
179 
180   @Override
isEnded()181   public boolean isEnded() {
182     return true;
183   }
184 
185   // RendererCapabilities implementation.
186 
187   @Override
188   @Capabilities
supportsFormat(Format format)189   public int supportsFormat(Format format) throws ExoPlaybackException {
190     return RendererCapabilities.create(FORMAT_UNSUPPORTED_TYPE);
191   }
192 
193   @Override
194   @AdaptiveSupport
supportsMixedMimeTypeAdaptation()195   public int supportsMixedMimeTypeAdaptation() throws ExoPlaybackException {
196     return ADAPTIVE_NOT_SUPPORTED;
197   }
198 
199   // PlayerMessage.Target implementation.
200 
201   @Override
handleMessage(int what, @Nullable Object object)202   public void handleMessage(int what, @Nullable Object object) throws ExoPlaybackException {
203     // Do nothing.
204   }
205 
206   // Methods to be overridden by subclasses.
207 
208   /**
209    * Called when the renderer is enabled.
210    * <p>
211    * The default implementation is a no-op.
212    *
213    * @param joining Whether this renderer is being enabled to join an ongoing playback.
214    * @throws ExoPlaybackException If an error occurs.
215    */
onEnabled(boolean joining)216   protected void onEnabled(boolean joining) throws ExoPlaybackException {
217     // Do nothing.
218   }
219 
220   /**
221    * Called when the renderer's offset has been changed.
222    * <p>
223    * The default implementation is a no-op.
224    *
225    * @param offsetUs The offset that should be subtracted from {@code positionUs} in
226    *     {@link #render(long, long)} to get the playback position with respect to the media.
227    * @throws ExoPlaybackException If an error occurs.
228    */
onRendererOffsetChanged(long offsetUs)229   protected void onRendererOffsetChanged(long offsetUs) throws ExoPlaybackException {
230     // Do nothing.
231   }
232 
233   /**
234    * Called when the position is reset. This occurs when the renderer is enabled after
235    * {@link #onRendererOffsetChanged(long)} has been called, and also when a position
236    * discontinuity is encountered.
237    * <p>
238    * The default implementation is a no-op.
239    *
240    * @param positionUs The new playback position in microseconds.
241    * @param joining Whether this renderer is being enabled to join an ongoing playback.
242    * @throws ExoPlaybackException If an error occurs.
243    */
onPositionReset(long positionUs, boolean joining)244   protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
245     // Do nothing.
246   }
247 
248   /**
249    * Called when the renderer is started.
250    * <p>
251    * The default implementation is a no-op.
252    *
253    * @throws ExoPlaybackException If an error occurs.
254    */
onStarted()255   protected void onStarted() throws ExoPlaybackException {
256     // Do nothing.
257   }
258 
259   /**
260    * Called when the renderer is stopped.
261    * <p>
262    * The default implementation is a no-op.
263    *
264    * @throws ExoPlaybackException If an error occurs.
265    */
onStopped()266   protected void onStopped() throws ExoPlaybackException {
267     // Do nothing.
268   }
269 
270   /**
271    * Called when the renderer is disabled.
272    * <p>
273    * The default implementation is a no-op.
274    */
onDisabled()275   protected void onDisabled() {
276     // Do nothing.
277   }
278 
279   /**
280    * Called when the renderer is reset.
281    *
282    * <p>The default implementation is a no-op.
283    */
onReset()284   protected void onReset() {
285     // Do nothing.
286   }
287 
288   // Methods to be called by subclasses.
289 
290   /**
291    * Returns the configuration set when the renderer was most recently enabled, or {@code null} if
292    * the renderer has never been enabled.
293    */
294   @Nullable
getConfiguration()295   protected final RendererConfiguration getConfiguration() {
296     return configuration;
297   }
298 
299   /**
300    * Returns the index of the renderer within the player.
301    */
getIndex()302   protected final int getIndex() {
303     return index;
304   }
305 
306 }
307