• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 com.google.android.exoplayer2.audio;
17 
18 import android.media.AudioTrack;
19 import androidx.annotation.Nullable;
20 import com.google.android.exoplayer2.C;
21 import com.google.android.exoplayer2.Format;
22 import com.google.android.exoplayer2.PlaybackParameters;
23 import java.nio.ByteBuffer;
24 
25 /**
26  * A sink that consumes audio data.
27  *
28  * <p>Before starting playback, specify the input audio format by calling {@link #configure(int,
29  * int, int, int, int[], int, int)}.
30  *
31  * <p>Call {@link #handleBuffer(ByteBuffer, long, int)} to write data, and {@link
32  * #handleDiscontinuity()} when the data being fed is discontinuous. Call {@link #play()} to start
33  * playing the written data.
34  *
35  * <p>Call {@link #configure(int, int, int, int, int[], int, int)} whenever the input format
36  * changes. The sink will be reinitialized on the next call to {@link #handleBuffer(ByteBuffer,
37  * long, int)}.
38  *
39  * <p>Call {@link #flush()} to prepare the sink to receive audio data from a new playback position.
40  *
41  * <p>Call {@link #playToEndOfStream()} repeatedly to play out all data when no more input buffers
42  * will be provided via {@link #handleBuffer(ByteBuffer, long, int)} until the next {@link
43  * #flush()}. Call {@link #reset()} when the instance is no longer required.
44  *
45  * <p>The implementation may be backed by a platform {@link AudioTrack}. In this case, {@link
46  * #setAudioSessionId(int)}, {@link #setAudioAttributes(AudioAttributes)}, {@link
47  * #enableTunnelingV21(int)} and/or {@link #disableTunneling()} may be called before writing data to
48  * the sink. These methods may also be called after writing data to the sink, in which case it will
49  * be reinitialized as required. For implementations that are not based on platform {@link
50  * AudioTrack}s, calling methods relating to audio sessions, audio attributes, and tunneling may
51  * have no effect.
52  */
53 public interface AudioSink {
54 
55   /**
56    * Listener for audio sink events.
57    */
58   interface Listener {
59 
60     /**
61      * Called if the audio sink has started rendering audio to a new platform audio session.
62      *
63      * @param audioSessionId The newly generated audio session's identifier.
64      */
onAudioSessionId(int audioSessionId)65     void onAudioSessionId(int audioSessionId);
66 
67     /**
68      * Called when the audio sink handles a buffer whose timestamp is discontinuous with the last
69      * buffer handled since it was reset.
70      */
onPositionDiscontinuity()71     void onPositionDiscontinuity();
72 
73     /**
74      * Called when the audio sink runs out of data.
75      * <p>
76      * An audio sink implementation may never call this method (for example, if audio data is
77      * consumed in batches rather than based on the sink's own clock).
78      *
79      * @param bufferSize The size of the sink's buffer, in bytes.
80      * @param bufferSizeMs The size of the sink's buffer, in milliseconds, if it is configured for
81      *     PCM output. {@link C#TIME_UNSET} if it is configured for encoded audio output, as the
82      *     buffered media can have a variable bitrate so the duration may be unknown.
83      * @param elapsedSinceLastFeedMs The time since the sink was last fed data, in milliseconds.
84      */
onUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs)85     void onUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs);
86 
87     /**
88      * Called when skipping silences is enabled or disabled.
89      *
90      * @param skipSilenceEnabled Whether skipping silences is enabled.
91      */
onSkipSilenceEnabledChanged(boolean skipSilenceEnabled)92     void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled);
93   }
94 
95   /**
96    * Thrown when a failure occurs configuring the sink.
97    */
98   final class ConfigurationException extends Exception {
99 
100     /**
101      * Creates a new configuration exception with the specified {@code cause} and no message.
102      */
ConfigurationException(Throwable cause)103     public ConfigurationException(Throwable cause) {
104       super(cause);
105     }
106 
107     /**
108      * Creates a new configuration exception with the specified {@code message} and no cause.
109      */
ConfigurationException(String message)110     public ConfigurationException(String message) {
111       super(message);
112     }
113 
114   }
115 
116   /**
117    * Thrown when a failure occurs initializing the sink.
118    */
119   final class InitializationException extends Exception {
120 
121     /**
122      * The underlying {@link AudioTrack}'s state, if applicable.
123      */
124     public final int audioTrackState;
125 
126     /**
127      * @param audioTrackState The underlying {@link AudioTrack}'s state, if applicable.
128      * @param sampleRate The requested sample rate in Hz.
129      * @param channelConfig The requested channel configuration.
130      * @param bufferSize The requested buffer size in bytes.
131      */
InitializationException(int audioTrackState, int sampleRate, int channelConfig, int bufferSize)132     public InitializationException(int audioTrackState, int sampleRate, int channelConfig,
133         int bufferSize) {
134       super("AudioTrack init failed: " + audioTrackState + ", Config(" + sampleRate + ", "
135           + channelConfig + ", " + bufferSize + ")");
136       this.audioTrackState = audioTrackState;
137     }
138 
139   }
140 
141   /**
142    * Thrown when a failure occurs writing to the sink.
143    */
144   final class WriteException extends Exception {
145 
146     /**
147      * The error value returned from the sink implementation. If the sink writes to a platform
148      * {@link AudioTrack}, this will be the error value returned from
149      * {@link AudioTrack#write(byte[], int, int)} or {@link AudioTrack#write(ByteBuffer, int, int)}.
150      * Otherwise, the meaning of the error code depends on the sink implementation.
151      */
152     public final int errorCode;
153 
154     /**
155      * @param errorCode The error value returned from the sink implementation.
156      */
WriteException(int errorCode)157     public WriteException(int errorCode) {
158       super("AudioTrack write failed: " + errorCode);
159       this.errorCode = errorCode;
160     }
161 
162   }
163 
164   /**
165    * Returned by {@link #getCurrentPositionUs(boolean)} when the position is not set.
166    */
167   long CURRENT_POSITION_NOT_SET = Long.MIN_VALUE;
168 
169   /**
170    * Sets the listener for sink events, which should be the audio renderer.
171    *
172    * @param listener The listener for sink events, which should be the audio renderer.
173    */
setListener(Listener listener)174   void setListener(Listener listener);
175 
176   /**
177    * Returns whether the sink supports the audio format.
178    *
179    * @param channelCount The number of channels, or {@link Format#NO_VALUE} if not known.
180    * @param encoding The audio encoding, or {@link Format#NO_VALUE} if not known.
181    * @return Whether the sink supports the audio format.
182    */
supportsOutput(int channelCount, @C.Encoding int encoding)183   boolean supportsOutput(int channelCount, @C.Encoding int encoding);
184 
185   /**
186    * Returns the playback position in the stream starting at zero, in microseconds, or
187    * {@link #CURRENT_POSITION_NOT_SET} if it is not yet available.
188    *
189    * @param sourceEnded Specify {@code true} if no more input buffers will be provided.
190    * @return The playback position relative to the start of playback, in microseconds.
191    */
getCurrentPositionUs(boolean sourceEnded)192   long getCurrentPositionUs(boolean sourceEnded);
193 
194   /**
195    * Configures (or reconfigures) the sink.
196    *
197    * @param inputEncoding The encoding of audio data provided in the input buffers.
198    * @param inputChannelCount The number of channels.
199    * @param inputSampleRate The sample rate in Hz.
200    * @param specifiedBufferSize A specific size for the playback buffer in bytes, or 0 to infer a
201    *     suitable buffer size.
202    * @param outputChannels A mapping from input to output channels that is applied to this sink's
203    *     input as a preprocessing step, if handling PCM input. Specify {@code null} to leave the
204    *     input unchanged. Otherwise, the element at index {@code i} specifies index of the input
205    *     channel to map to output channel {@code i} when preprocessing input buffers. After the map
206    *     is applied the audio data will have {@code outputChannels.length} channels.
207    * @param trimStartFrames The number of audio frames to trim from the start of data written to the
208    *     sink after this call.
209    * @param trimEndFrames The number of audio frames to trim from data written to the sink
210    *     immediately preceding the next call to {@link #flush()} or this method.
211    * @throws ConfigurationException If an error occurs configuring the sink.
212    */
configure( @.Encoding int inputEncoding, int inputChannelCount, int inputSampleRate, int specifiedBufferSize, @Nullable int[] outputChannels, int trimStartFrames, int trimEndFrames)213   void configure(
214       @C.Encoding int inputEncoding,
215       int inputChannelCount,
216       int inputSampleRate,
217       int specifiedBufferSize,
218       @Nullable int[] outputChannels,
219       int trimStartFrames,
220       int trimEndFrames)
221       throws ConfigurationException;
222 
223   /**
224    * Starts or resumes consuming audio if initialized.
225    */
play()226   void play();
227 
228   /** Signals to the sink that the next buffer may be discontinuous with the previous buffer. */
handleDiscontinuity()229   void handleDiscontinuity();
230 
231   /**
232    * Attempts to process data from a {@link ByteBuffer}, starting from its current position and
233    * ending at its limit (exclusive). The position of the {@link ByteBuffer} is advanced by the
234    * number of bytes that were handled. {@link Listener#onPositionDiscontinuity()} will be called if
235    * {@code presentationTimeUs} is discontinuous with the last buffer handled since the last reset.
236    *
237    * <p>Returns whether the data was handled in full. If the data was not handled in full then the
238    * same {@link ByteBuffer} must be provided to subsequent calls until it has been fully consumed,
239    * except in the case of an intervening call to {@link #flush()} (or to {@link #configure(int,
240    * int, int, int, int[], int, int)} that causes the sink to be flushed).
241    *
242    * @param buffer The buffer containing audio data.
243    * @param presentationTimeUs The presentation timestamp of the buffer in microseconds.
244    * @param encodedAccessUnitCount The number of encoded access units in the buffer, or 1 if the
245    *     buffer contains PCM audio. This allows batching multiple encoded access units in one
246    *     buffer.
247    * @return Whether the buffer was handled fully.
248    * @throws InitializationException If an error occurs initializing the sink.
249    * @throws WriteException If an error occurs writing the audio data.
250    */
handleBuffer(ByteBuffer buffer, long presentationTimeUs, int encodedAccessUnitCount)251   boolean handleBuffer(ByteBuffer buffer, long presentationTimeUs, int encodedAccessUnitCount)
252       throws InitializationException, WriteException;
253 
254   /**
255    * Processes any remaining data. {@link #isEnded()} will return {@code true} when no data remains.
256    *
257    * @throws WriteException If an error occurs draining data to the sink.
258    */
playToEndOfStream()259   void playToEndOfStream() throws WriteException;
260 
261   /**
262    * Returns whether {@link #playToEndOfStream} has been called and all buffers have been processed.
263    */
isEnded()264   boolean isEnded();
265 
266   /**
267    * Returns whether the sink has data pending that has not been consumed yet.
268    */
hasPendingData()269   boolean hasPendingData();
270 
271   /**
272    * @deprecated Use {@link #setPlaybackSpeed(float)} and {@link #setSkipSilenceEnabled(boolean)}
273    *     instead.
274    */
275   @Deprecated
setPlaybackParameters(PlaybackParameters playbackParameters)276   void setPlaybackParameters(PlaybackParameters playbackParameters);
277 
278   /** @deprecated Use {@link #getPlaybackSpeed()} and {@link #getSkipSilenceEnabled()} instead. */
279   @SuppressWarnings("deprecation")
280   @Deprecated
getPlaybackParameters()281   PlaybackParameters getPlaybackParameters();
282 
283   /** Sets the playback speed. */
setPlaybackSpeed(float playbackSpeed)284   void setPlaybackSpeed(float playbackSpeed);
285 
286   /** Gets the playback speed. */
getPlaybackSpeed()287   float getPlaybackSpeed();
288 
289   /** Sets whether silences should be skipped in the audio stream. */
setSkipSilenceEnabled(boolean skipSilenceEnabled)290   void setSkipSilenceEnabled(boolean skipSilenceEnabled);
291 
292   /** Gets whether silences are skipped in the audio stream. */
getSkipSilenceEnabled()293   boolean getSkipSilenceEnabled();
294 
295   /**
296    * Sets attributes for audio playback. If the attributes have changed and if the sink is not
297    * configured for use with tunneling, then it is reset and the audio session id is cleared.
298    * <p>
299    * If the sink is configured for use with tunneling then the audio attributes are ignored. The
300    * sink is not reset and the audio session id is not cleared. The passed attributes will be used
301    * if the sink is later re-configured into non-tunneled mode.
302    *
303    * @param audioAttributes The attributes for audio playback.
304    */
setAudioAttributes(AudioAttributes audioAttributes)305   void setAudioAttributes(AudioAttributes audioAttributes);
306 
307   /** Sets the audio session id. */
setAudioSessionId(int audioSessionId)308   void setAudioSessionId(int audioSessionId);
309 
310   /** Sets the auxiliary effect. */
setAuxEffectInfo(AuxEffectInfo auxEffectInfo)311   void setAuxEffectInfo(AuxEffectInfo auxEffectInfo);
312 
313   /**
314    * Enables tunneling, if possible. The sink is reset if tunneling was previously disabled or if
315    * the audio session id has changed. Enabling tunneling is only possible if the sink is based on a
316    * platform {@link AudioTrack}, and requires platform API version 21 onwards.
317    *
318    * @param tunnelingAudioSessionId The audio session id to use.
319    * @throws IllegalStateException Thrown if enabling tunneling on platform API version &lt; 21.
320    */
enableTunnelingV21(int tunnelingAudioSessionId)321   void enableTunnelingV21(int tunnelingAudioSessionId);
322 
323   /**
324    * Disables tunneling. If tunneling was previously enabled then the sink is reset and any audio
325    * session id is cleared.
326    */
disableTunneling()327   void disableTunneling();
328 
329   /**
330    * Sets the playback volume.
331    *
332    * @param volume A volume in the range [0.0, 1.0].
333    */
setVolume(float volume)334   void setVolume(float volume);
335 
336   /**
337    * Pauses playback.
338    */
pause()339   void pause();
340 
341   /**
342    * Flushes the sink, after which it is ready to receive buffers from a new playback position.
343    *
344    * <p>The audio session may remain active until {@link #reset()} is called.
345    */
flush()346   void flush();
347 
348   /** Resets the renderer, releasing any resources that it currently holds. */
reset()349   void reset();
350 }
351