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 com.google.android.exoplayer2.audio; 17 18 import android.annotation.SuppressLint; 19 import android.media.AudioFormat; 20 import android.media.AudioManager; 21 import android.media.AudioTrack; 22 import android.os.ConditionVariable; 23 import android.os.SystemClock; 24 import androidx.annotation.Nullable; 25 import androidx.annotation.RequiresApi; 26 import com.google.android.exoplayer2.C; 27 import com.google.android.exoplayer2.Format; 28 import com.google.android.exoplayer2.PlaybackParameters; 29 import com.google.android.exoplayer2.audio.AudioProcessor.UnhandledAudioFormatException; 30 import com.google.android.exoplayer2.util.Assertions; 31 import com.google.android.exoplayer2.util.Log; 32 import com.google.android.exoplayer2.util.Util; 33 import java.nio.ByteBuffer; 34 import java.nio.ByteOrder; 35 import java.util.ArrayDeque; 36 import java.util.ArrayList; 37 import java.util.Collections; 38 39 /** 40 * Plays audio data. The implementation delegates to an {@link AudioTrack} and handles playback 41 * position smoothing, non-blocking writes and reconfiguration. 42 * <p> 43 * If tunneling mode is enabled, care must be taken that audio processors do not output buffers with 44 * a different duration than their input, and buffer processors must produce output corresponding to 45 * their last input immediately after that input is queued. This means that, for example, speed 46 * adjustment is not possible while using tunneling. 47 */ 48 public final class DefaultAudioSink implements AudioSink { 49 50 /** 51 * Thrown when the audio track has provided a spurious timestamp, if {@link 52 * #failOnSpuriousAudioTimestamp} is set. 53 */ 54 public static final class InvalidAudioTrackTimestampException extends RuntimeException { 55 56 /** 57 * Creates a new invalid timestamp exception with the specified message. 58 * 59 * @param message The detail message for this exception. 60 */ InvalidAudioTrackTimestampException(String message)61 private InvalidAudioTrackTimestampException(String message) { 62 super(message); 63 } 64 65 } 66 67 /** 68 * Provides a chain of audio processors, which are used for any user-defined processing and 69 * applying playback parameters (if supported). Because applying playback parameters can skip and 70 * stretch/compress audio, the sink will query the chain for information on how to transform its 71 * output position to map it onto a media position, via {@link #getMediaDuration(long)} and {@link 72 * #getSkippedOutputFrameCount()}. 73 */ 74 public interface AudioProcessorChain { 75 76 /** 77 * Returns the fixed chain of audio processors that will process audio. This method is called 78 * once during initialization, but audio processors may change state to become active/inactive 79 * during playback. 80 */ getAudioProcessors()81 AudioProcessor[] getAudioProcessors(); 82 83 /** 84 * @deprecated Use {@link #applyPlaybackSpeed(float)} and {@link 85 * #applySkipSilenceEnabled(boolean)} instead. 86 */ 87 @Deprecated applyPlaybackParameters(PlaybackParameters playbackParameters)88 PlaybackParameters applyPlaybackParameters(PlaybackParameters playbackParameters); 89 90 /** 91 * Configures audio processors to apply the specified playback speed immediately, returning the 92 * new playback speed, which may differ from the speed passed in. Only called when processors 93 * have no input pending. 94 * 95 * @param playbackSpeed The playback speed to try to apply. 96 * @return The playback speed that was actually applied. 97 */ applyPlaybackSpeed(float playbackSpeed)98 float applyPlaybackSpeed(float playbackSpeed); 99 100 /** 101 * Configures audio processors to apply whether to skip silences immediately, returning the new 102 * value. Only called when processors have no input pending. 103 * 104 * @param skipSilenceEnabled Whether silences should be skipped in the audio stream. 105 * @return The new value. 106 */ applySkipSilenceEnabled(boolean skipSilenceEnabled)107 boolean applySkipSilenceEnabled(boolean skipSilenceEnabled); 108 109 /** 110 * Scales the specified playout duration to take into account speedup due to audio processing, 111 * returning an input media duration, in arbitrary units. 112 */ getMediaDuration(long playoutDuration)113 long getMediaDuration(long playoutDuration); 114 115 /** 116 * Returns the number of output audio frames skipped since the audio processors were last 117 * flushed. 118 */ getSkippedOutputFrameCount()119 long getSkippedOutputFrameCount(); 120 } 121 122 /** 123 * The default audio processor chain, which applies a (possibly empty) chain of user-defined audio 124 * processors followed by {@link SilenceSkippingAudioProcessor} and {@link SonicAudioProcessor}. 125 */ 126 public static class DefaultAudioProcessorChain implements AudioProcessorChain { 127 128 private final AudioProcessor[] audioProcessors; 129 private final SilenceSkippingAudioProcessor silenceSkippingAudioProcessor; 130 private final SonicAudioProcessor sonicAudioProcessor; 131 132 /** 133 * Creates a new default chain of audio processors, with the user-defined {@code 134 * audioProcessors} applied before silence skipping and playback parameters. 135 */ DefaultAudioProcessorChain(AudioProcessor... audioProcessors)136 public DefaultAudioProcessorChain(AudioProcessor... audioProcessors) { 137 // The passed-in type may be more specialized than AudioProcessor[], so allocate a new array 138 // rather than using Arrays.copyOf. 139 this.audioProcessors = new AudioProcessor[audioProcessors.length + 2]; 140 System.arraycopy( 141 /* src= */ audioProcessors, 142 /* srcPos= */ 0, 143 /* dest= */ this.audioProcessors, 144 /* destPos= */ 0, 145 /* length= */ audioProcessors.length); 146 silenceSkippingAudioProcessor = new SilenceSkippingAudioProcessor(); 147 sonicAudioProcessor = new SonicAudioProcessor(); 148 this.audioProcessors[audioProcessors.length] = silenceSkippingAudioProcessor; 149 this.audioProcessors[audioProcessors.length + 1] = sonicAudioProcessor; 150 } 151 152 @Override getAudioProcessors()153 public AudioProcessor[] getAudioProcessors() { 154 return audioProcessors; 155 } 156 157 /** 158 * @deprecated Use {@link #applyPlaybackSpeed(float)} and {@link 159 * #applySkipSilenceEnabled(boolean)} instead. 160 */ 161 @SuppressWarnings("deprecation") 162 @Deprecated 163 @Override applyPlaybackParameters(PlaybackParameters playbackParameters)164 public PlaybackParameters applyPlaybackParameters(PlaybackParameters playbackParameters) { 165 return new PlaybackParameters(applyPlaybackSpeed(playbackParameters.speed)); 166 } 167 168 @Override applyPlaybackSpeed(float playbackSpeed)169 public float applyPlaybackSpeed(float playbackSpeed) { 170 return sonicAudioProcessor.setSpeed(playbackSpeed); 171 } 172 173 @Override applySkipSilenceEnabled(boolean skipSilenceEnabled)174 public boolean applySkipSilenceEnabled(boolean skipSilenceEnabled) { 175 silenceSkippingAudioProcessor.setEnabled(skipSilenceEnabled); 176 return skipSilenceEnabled; 177 } 178 179 @Override getMediaDuration(long playoutDuration)180 public long getMediaDuration(long playoutDuration) { 181 return sonicAudioProcessor.scaleDurationForSpeedup(playoutDuration); 182 } 183 184 @Override getSkippedOutputFrameCount()185 public long getSkippedOutputFrameCount() { 186 return silenceSkippingAudioProcessor.getSkippedFrames(); 187 } 188 } 189 190 /** 191 * A minimum length for the {@link AudioTrack} buffer, in microseconds. 192 */ 193 private static final long MIN_BUFFER_DURATION_US = 250000; 194 /** 195 * A maximum length for the {@link AudioTrack} buffer, in microseconds. 196 */ 197 private static final long MAX_BUFFER_DURATION_US = 750000; 198 /** 199 * The length for passthrough {@link AudioTrack} buffers, in microseconds. 200 */ 201 private static final long PASSTHROUGH_BUFFER_DURATION_US = 250000; 202 /** 203 * A multiplication factor to apply to the minimum buffer size requested by the underlying 204 * {@link AudioTrack}. 205 */ 206 private static final int BUFFER_MULTIPLICATION_FACTOR = 4; 207 208 /** To avoid underruns on some devices (e.g., Broadcom 7271), scale up the AC3 buffer duration. */ 209 private static final int AC3_BUFFER_MULTIPLICATION_FACTOR = 2; 210 211 /** 212 * @see AudioTrack#ERROR_BAD_VALUE 213 */ 214 private static final int ERROR_BAD_VALUE = AudioTrack.ERROR_BAD_VALUE; 215 /** 216 * @see AudioTrack#MODE_STATIC 217 */ 218 private static final int MODE_STATIC = AudioTrack.MODE_STATIC; 219 /** 220 * @see AudioTrack#MODE_STREAM 221 */ 222 private static final int MODE_STREAM = AudioTrack.MODE_STREAM; 223 /** 224 * @see AudioTrack#STATE_INITIALIZED 225 */ 226 private static final int STATE_INITIALIZED = AudioTrack.STATE_INITIALIZED; 227 /** 228 * @see AudioTrack#WRITE_NON_BLOCKING 229 */ 230 @SuppressLint("InlinedApi") 231 private static final int WRITE_NON_BLOCKING = AudioTrack.WRITE_NON_BLOCKING; 232 /** The default playback speed. */ 233 private static final float DEFAULT_PLAYBACK_SPEED = 1.0f; 234 /** The default skip silence flag. */ 235 private static final boolean DEFAULT_SKIP_SILENCE = false; 236 237 private static final String TAG = "AudioTrack"; 238 239 /** 240 * Whether to enable a workaround for an issue where an audio effect does not keep its session 241 * active across releasing/initializing a new audio track, on platform builds where 242 * {@link Util#SDK_INT} < 21. 243 * <p> 244 * The flag must be set before creating a player. 245 */ 246 public static boolean enablePreV21AudioSessionWorkaround = false; 247 248 /** 249 * Whether to throw an {@link InvalidAudioTrackTimestampException} when a spurious timestamp is 250 * reported from {@link AudioTrack#getTimestamp}. 251 * <p> 252 * The flag must be set before creating a player. Should be set to {@code true} for testing and 253 * debugging purposes only. 254 */ 255 public static boolean failOnSpuriousAudioTimestamp = false; 256 257 @Nullable private final AudioCapabilities audioCapabilities; 258 private final AudioProcessorChain audioProcessorChain; 259 private final boolean enableFloatOutput; 260 private final ChannelMappingAudioProcessor channelMappingAudioProcessor; 261 private final TrimmingAudioProcessor trimmingAudioProcessor; 262 private final AudioProcessor[] toIntPcmAvailableAudioProcessors; 263 private final AudioProcessor[] toFloatPcmAvailableAudioProcessors; 264 private final ConditionVariable releasingConditionVariable; 265 private final AudioTrackPositionTracker audioTrackPositionTracker; 266 private final ArrayDeque<MediaPositionParameters> mediaPositionParametersCheckpoints; 267 268 @Nullable private Listener listener; 269 /** Used to keep the audio session active on pre-V21 builds (see {@link #initialize(long)}). */ 270 @Nullable private AudioTrack keepSessionIdAudioTrack; 271 272 @Nullable private Configuration pendingConfiguration; 273 private Configuration configuration; 274 private AudioTrack audioTrack; 275 276 private AudioAttributes audioAttributes; 277 @Nullable private MediaPositionParameters afterDrainParameters; 278 private MediaPositionParameters mediaPositionParameters; 279 280 @Nullable private ByteBuffer avSyncHeader; 281 private int bytesUntilNextAvSync; 282 283 private long submittedPcmBytes; 284 private long submittedEncodedFrames; 285 private long writtenPcmBytes; 286 private long writtenEncodedFrames; 287 private int framesPerEncodedSample; 288 private boolean startMediaTimeUsNeedsSync; 289 private long startMediaTimeUs; 290 private float volume; 291 292 private AudioProcessor[] activeAudioProcessors; 293 private ByteBuffer[] outputBuffers; 294 @Nullable private ByteBuffer inputBuffer; 295 private int inputBufferAccessUnitCount; 296 @Nullable private ByteBuffer outputBuffer; 297 private byte[] preV21OutputBuffer; 298 private int preV21OutputBufferOffset; 299 private int drainingAudioProcessorIndex; 300 private boolean handledEndOfStream; 301 private boolean stoppedAudioTrack; 302 303 private boolean playing; 304 private int audioSessionId; 305 private AuxEffectInfo auxEffectInfo; 306 private boolean tunneling; 307 private long lastFeedElapsedRealtimeMs; 308 309 /** 310 * Creates a new default audio sink. 311 * 312 * @param audioCapabilities The audio capabilities for playback on this device. May be null if the 313 * default capabilities (no encoded audio passthrough support) should be assumed. 314 * @param audioProcessors An array of {@link AudioProcessor}s that will process PCM audio before 315 * output. May be empty. 316 */ DefaultAudioSink( @ullable AudioCapabilities audioCapabilities, AudioProcessor[] audioProcessors)317 public DefaultAudioSink( 318 @Nullable AudioCapabilities audioCapabilities, AudioProcessor[] audioProcessors) { 319 this(audioCapabilities, audioProcessors, /* enableFloatOutput= */ false); 320 } 321 322 /** 323 * Creates a new default audio sink, optionally using float output for high resolution PCM. 324 * 325 * @param audioCapabilities The audio capabilities for playback on this device. May be null if the 326 * default capabilities (no encoded audio passthrough support) should be assumed. 327 * @param audioProcessors An array of {@link AudioProcessor}s that will process PCM audio before 328 * output. May be empty. 329 * @param enableFloatOutput Whether to enable 32-bit float output. Where possible, 32-bit float 330 * output will be used if the input is 32-bit float, and also if the input is high resolution 331 * (24-bit or 32-bit) integer PCM. Audio processing (for example, speed adjustment) will not 332 * be available when float output is in use. 333 */ DefaultAudioSink( @ullable AudioCapabilities audioCapabilities, AudioProcessor[] audioProcessors, boolean enableFloatOutput)334 public DefaultAudioSink( 335 @Nullable AudioCapabilities audioCapabilities, 336 AudioProcessor[] audioProcessors, 337 boolean enableFloatOutput) { 338 this(audioCapabilities, new DefaultAudioProcessorChain(audioProcessors), enableFloatOutput); 339 } 340 341 /** 342 * Creates a new default audio sink, optionally using float output for high resolution PCM and 343 * with the specified {@code audioProcessorChain}. 344 * 345 * @param audioCapabilities The audio capabilities for playback on this device. May be null if the 346 * default capabilities (no encoded audio passthrough support) should be assumed. 347 * @param audioProcessorChain An {@link AudioProcessorChain} which is used to apply playback 348 * parameters adjustments. The instance passed in must not be reused in other sinks. 349 * @param enableFloatOutput Whether to enable 32-bit float output. Where possible, 32-bit float 350 * output will be used if the input is 32-bit float, and also if the input is high resolution 351 * (24-bit or 32-bit) integer PCM. Audio processing (for example, speed adjustment) will not 352 * be available when float output is in use. 353 */ DefaultAudioSink( @ullable AudioCapabilities audioCapabilities, AudioProcessorChain audioProcessorChain, boolean enableFloatOutput)354 public DefaultAudioSink( 355 @Nullable AudioCapabilities audioCapabilities, 356 AudioProcessorChain audioProcessorChain, 357 boolean enableFloatOutput) { 358 this.audioCapabilities = audioCapabilities; 359 this.audioProcessorChain = Assertions.checkNotNull(audioProcessorChain); 360 this.enableFloatOutput = enableFloatOutput; 361 releasingConditionVariable = new ConditionVariable(true); 362 audioTrackPositionTracker = new AudioTrackPositionTracker(new PositionTrackerListener()); 363 channelMappingAudioProcessor = new ChannelMappingAudioProcessor(); 364 trimmingAudioProcessor = new TrimmingAudioProcessor(); 365 ArrayList<AudioProcessor> toIntPcmAudioProcessors = new ArrayList<>(); 366 Collections.addAll( 367 toIntPcmAudioProcessors, 368 new ResamplingAudioProcessor(), 369 channelMappingAudioProcessor, 370 trimmingAudioProcessor); 371 Collections.addAll(toIntPcmAudioProcessors, audioProcessorChain.getAudioProcessors()); 372 toIntPcmAvailableAudioProcessors = toIntPcmAudioProcessors.toArray(new AudioProcessor[0]); 373 toFloatPcmAvailableAudioProcessors = new AudioProcessor[] {new FloatResamplingAudioProcessor()}; 374 volume = 1.0f; 375 audioAttributes = AudioAttributes.DEFAULT; 376 audioSessionId = C.AUDIO_SESSION_ID_UNSET; 377 auxEffectInfo = new AuxEffectInfo(AuxEffectInfo.NO_AUX_EFFECT_ID, 0f); 378 mediaPositionParameters = 379 new MediaPositionParameters( 380 DEFAULT_PLAYBACK_SPEED, 381 DEFAULT_SKIP_SILENCE, 382 /* mediaTimeUs= */ 0, 383 /* audioTrackPositionUs= */ 0); 384 drainingAudioProcessorIndex = C.INDEX_UNSET; 385 activeAudioProcessors = new AudioProcessor[0]; 386 outputBuffers = new ByteBuffer[0]; 387 mediaPositionParametersCheckpoints = new ArrayDeque<>(); 388 } 389 390 // AudioSink implementation. 391 392 @Override setListener(Listener listener)393 public void setListener(Listener listener) { 394 this.listener = listener; 395 } 396 397 @Override supportsOutput(int channelCount, @C.Encoding int encoding)398 public boolean supportsOutput(int channelCount, @C.Encoding int encoding) { 399 if (Util.isEncodingLinearPcm(encoding)) { 400 // AudioTrack supports 16-bit integer PCM output in all platform API versions, and float 401 // output from platform API version 21 only. Other integer PCM encodings are resampled by this 402 // sink to 16-bit PCM. We assume that the audio framework will downsample any number of 403 // channels to the output device's required number of channels. 404 return encoding != C.ENCODING_PCM_FLOAT || Util.SDK_INT >= 21; 405 } else { 406 return audioCapabilities != null 407 && audioCapabilities.supportsEncoding(encoding) 408 && (channelCount == Format.NO_VALUE 409 || channelCount <= audioCapabilities.getMaxChannelCount()); 410 } 411 } 412 413 @Override getCurrentPositionUs(boolean sourceEnded)414 public long getCurrentPositionUs(boolean sourceEnded) { 415 if (!isInitialized()) { 416 return CURRENT_POSITION_NOT_SET; 417 } 418 long positionUs = audioTrackPositionTracker.getCurrentPositionUs(sourceEnded); 419 positionUs = Math.min(positionUs, configuration.framesToDurationUs(getWrittenFrames())); 420 return applySkipping(applyMediaPositionParameters(positionUs)); 421 } 422 423 @Override configure( @.Encoding int inputEncoding, int inputChannelCount, int inputSampleRate, int specifiedBufferSize, @Nullable int[] outputChannels, int trimStartFrames, int trimEndFrames)424 public void configure( 425 @C.Encoding int inputEncoding, 426 int inputChannelCount, 427 int inputSampleRate, 428 int specifiedBufferSize, 429 @Nullable int[] outputChannels, 430 int trimStartFrames, 431 int trimEndFrames) 432 throws ConfigurationException { 433 if (Util.SDK_INT < 21 && inputChannelCount == 8 && outputChannels == null) { 434 // AudioTrack doesn't support 8 channel output before Android L. Discard the last two (side) 435 // channels to give a 6 channel stream that is supported. 436 outputChannels = new int[6]; 437 for (int i = 0; i < outputChannels.length; i++) { 438 outputChannels[i] = i; 439 } 440 } 441 442 boolean isInputPcm = Util.isEncodingLinearPcm(inputEncoding); 443 boolean processingEnabled = isInputPcm; 444 int sampleRate = inputSampleRate; 445 int channelCount = inputChannelCount; 446 @C.Encoding int encoding = inputEncoding; 447 boolean useFloatOutput = 448 enableFloatOutput 449 && supportsOutput(inputChannelCount, C.ENCODING_PCM_FLOAT) 450 && Util.isEncodingHighResolutionPcm(inputEncoding); 451 AudioProcessor[] availableAudioProcessors = 452 useFloatOutput ? toFloatPcmAvailableAudioProcessors : toIntPcmAvailableAudioProcessors; 453 if (processingEnabled) { 454 trimmingAudioProcessor.setTrimFrameCount(trimStartFrames, trimEndFrames); 455 channelMappingAudioProcessor.setChannelMap(outputChannels); 456 AudioProcessor.AudioFormat outputFormat = 457 new AudioProcessor.AudioFormat(sampleRate, channelCount, encoding); 458 for (AudioProcessor audioProcessor : availableAudioProcessors) { 459 try { 460 AudioProcessor.AudioFormat nextFormat = audioProcessor.configure(outputFormat); 461 if (audioProcessor.isActive()) { 462 outputFormat = nextFormat; 463 } 464 } catch (UnhandledAudioFormatException e) { 465 throw new ConfigurationException(e); 466 } 467 } 468 sampleRate = outputFormat.sampleRate; 469 channelCount = outputFormat.channelCount; 470 encoding = outputFormat.encoding; 471 } 472 473 int outputChannelConfig = getChannelConfig(channelCount, isInputPcm); 474 if (outputChannelConfig == AudioFormat.CHANNEL_INVALID) { 475 throw new ConfigurationException("Unsupported channel count: " + channelCount); 476 } 477 478 int inputPcmFrameSize = 479 isInputPcm ? Util.getPcmFrameSize(inputEncoding, inputChannelCount) : C.LENGTH_UNSET; 480 int outputPcmFrameSize = 481 isInputPcm ? Util.getPcmFrameSize(encoding, channelCount) : C.LENGTH_UNSET; 482 boolean canApplyPlaybackParameters = processingEnabled && !useFloatOutput; 483 Configuration pendingConfiguration = 484 new Configuration( 485 isInputPcm, 486 inputPcmFrameSize, 487 inputSampleRate, 488 outputPcmFrameSize, 489 sampleRate, 490 outputChannelConfig, 491 encoding, 492 specifiedBufferSize, 493 processingEnabled, 494 canApplyPlaybackParameters, 495 availableAudioProcessors); 496 if (isInitialized()) { 497 this.pendingConfiguration = pendingConfiguration; 498 } else { 499 configuration = pendingConfiguration; 500 } 501 } 502 setupAudioProcessors()503 private void setupAudioProcessors() { 504 AudioProcessor[] audioProcessors = configuration.availableAudioProcessors; 505 ArrayList<AudioProcessor> newAudioProcessors = new ArrayList<>(); 506 for (AudioProcessor audioProcessor : audioProcessors) { 507 if (audioProcessor.isActive()) { 508 newAudioProcessors.add(audioProcessor); 509 } else { 510 audioProcessor.flush(); 511 } 512 } 513 int count = newAudioProcessors.size(); 514 activeAudioProcessors = newAudioProcessors.toArray(new AudioProcessor[count]); 515 outputBuffers = new ByteBuffer[count]; 516 flushAudioProcessors(); 517 } 518 flushAudioProcessors()519 private void flushAudioProcessors() { 520 for (int i = 0; i < activeAudioProcessors.length; i++) { 521 AudioProcessor audioProcessor = activeAudioProcessors[i]; 522 audioProcessor.flush(); 523 outputBuffers[i] = audioProcessor.getOutput(); 524 } 525 } 526 initialize(long presentationTimeUs)527 private void initialize(long presentationTimeUs) throws InitializationException { 528 // If we're asynchronously releasing a previous audio track then we block until it has been 529 // released. This guarantees that we cannot end up in a state where we have multiple audio 530 // track instances. Without this guarantee it would be possible, in extreme cases, to exhaust 531 // the shared memory that's available for audio track buffers. This would in turn cause the 532 // initialization of the audio track to fail. 533 releasingConditionVariable.block(); 534 535 audioTrack = 536 Assertions.checkNotNull(configuration) 537 .buildAudioTrack(tunneling, audioAttributes, audioSessionId); 538 int audioSessionId = audioTrack.getAudioSessionId(); 539 if (enablePreV21AudioSessionWorkaround) { 540 if (Util.SDK_INT < 21) { 541 // The workaround creates an audio track with a two byte buffer on the same session, and 542 // does not release it until this object is released, which keeps the session active. 543 if (keepSessionIdAudioTrack != null 544 && audioSessionId != keepSessionIdAudioTrack.getAudioSessionId()) { 545 releaseKeepSessionIdAudioTrack(); 546 } 547 if (keepSessionIdAudioTrack == null) { 548 keepSessionIdAudioTrack = initializeKeepSessionIdAudioTrack(audioSessionId); 549 } 550 } 551 } 552 if (this.audioSessionId != audioSessionId) { 553 this.audioSessionId = audioSessionId; 554 if (listener != null) { 555 listener.onAudioSessionId(audioSessionId); 556 } 557 } 558 559 startMediaTimeUs = Math.max(0, presentationTimeUs); 560 startMediaTimeUsNeedsSync = false; 561 562 applyPlaybackSpeedAndSkipSilence(presentationTimeUs); 563 564 audioTrackPositionTracker.setAudioTrack( 565 audioTrack, 566 configuration.outputEncoding, 567 configuration.outputPcmFrameSize, 568 configuration.bufferSize); 569 setVolumeInternal(); 570 571 if (auxEffectInfo.effectId != AuxEffectInfo.NO_AUX_EFFECT_ID) { 572 audioTrack.attachAuxEffect(auxEffectInfo.effectId); 573 audioTrack.setAuxEffectSendLevel(auxEffectInfo.sendLevel); 574 } 575 } 576 577 @Override play()578 public void play() { 579 playing = true; 580 if (isInitialized()) { 581 audioTrackPositionTracker.start(); 582 audioTrack.play(); 583 } 584 } 585 586 @Override handleDiscontinuity()587 public void handleDiscontinuity() { 588 // Force resynchronization after a skipped buffer. 589 startMediaTimeUsNeedsSync = true; 590 } 591 592 @Override 593 @SuppressWarnings("ReferenceEquality") handleBuffer( ByteBuffer buffer, long presentationTimeUs, int encodedAccessUnitCount)594 public boolean handleBuffer( 595 ByteBuffer buffer, long presentationTimeUs, int encodedAccessUnitCount) 596 throws InitializationException, WriteException { 597 Assertions.checkArgument(inputBuffer == null || buffer == inputBuffer); 598 599 if (pendingConfiguration != null) { 600 if (!drainToEndOfStream()) { 601 // There's still pending data in audio processors to write to the track. 602 return false; 603 } else if (!pendingConfiguration.canReuseAudioTrack(configuration)) { 604 playPendingData(); 605 if (hasPendingData()) { 606 // We're waiting for playout on the current audio track to finish. 607 return false; 608 } 609 flush(); 610 } else { 611 // The current audio track can be reused for the new configuration. 612 configuration = pendingConfiguration; 613 pendingConfiguration = null; 614 } 615 // Re-apply playback parameters. 616 applyPlaybackSpeedAndSkipSilence(presentationTimeUs); 617 } 618 619 if (!isInitialized()) { 620 initialize(presentationTimeUs); 621 if (playing) { 622 play(); 623 } 624 } 625 626 if (!audioTrackPositionTracker.mayHandleBuffer(getWrittenFrames())) { 627 return false; 628 } 629 630 if (inputBuffer == null) { 631 // We are seeing this buffer for the first time. 632 if (!buffer.hasRemaining()) { 633 // The buffer is empty. 634 return true; 635 } 636 637 if (!configuration.isInputPcm && framesPerEncodedSample == 0) { 638 // If this is the first encoded sample, calculate the sample size in frames. 639 framesPerEncodedSample = getFramesPerEncodedSample(configuration.outputEncoding, buffer); 640 if (framesPerEncodedSample == 0) { 641 // We still don't know the number of frames per sample, so drop the buffer. 642 // For TrueHD this can occur after some seek operations, as not every sample starts with 643 // a syncframe header. If we chunked samples together so the extracted samples always 644 // started with a syncframe header, the chunks would be too large. 645 return true; 646 } 647 } 648 649 if (afterDrainParameters != null) { 650 if (!drainToEndOfStream()) { 651 // Don't process any more input until draining completes. 652 return false; 653 } 654 applyPlaybackSpeedAndSkipSilence(presentationTimeUs); 655 afterDrainParameters = null; 656 } 657 658 // Sanity check that presentationTimeUs is consistent with the expected value. 659 long expectedPresentationTimeUs = 660 startMediaTimeUs 661 + configuration.inputFramesToDurationUs( 662 getSubmittedFrames() - trimmingAudioProcessor.getTrimmedFrameCount()); 663 if (!startMediaTimeUsNeedsSync 664 && Math.abs(expectedPresentationTimeUs - presentationTimeUs) > 200000) { 665 Log.e( 666 TAG, 667 "Discontinuity detected [expected " 668 + expectedPresentationTimeUs 669 + ", got " 670 + presentationTimeUs 671 + "]"); 672 startMediaTimeUsNeedsSync = true; 673 } 674 if (startMediaTimeUsNeedsSync) { 675 if (!drainToEndOfStream()) { 676 // Don't update timing until pending AudioProcessor buffers are completely drained. 677 return false; 678 } 679 // Adjust startMediaTimeUs to be consistent with the current buffer's start time and the 680 // number of bytes submitted. 681 long adjustmentUs = presentationTimeUs - expectedPresentationTimeUs; 682 startMediaTimeUs += adjustmentUs; 683 startMediaTimeUsNeedsSync = false; 684 // Re-apply playback parameters because the startMediaTimeUs changed. 685 applyPlaybackSpeedAndSkipSilence(presentationTimeUs); 686 if (listener != null && adjustmentUs != 0) { 687 listener.onPositionDiscontinuity(); 688 } 689 } 690 691 if (configuration.isInputPcm) { 692 submittedPcmBytes += buffer.remaining(); 693 } else { 694 submittedEncodedFrames += framesPerEncodedSample * encodedAccessUnitCount; 695 } 696 697 inputBuffer = buffer; 698 inputBufferAccessUnitCount = encodedAccessUnitCount; 699 } 700 701 processBuffers(presentationTimeUs); 702 703 if (!inputBuffer.hasRemaining()) { 704 inputBuffer = null; 705 inputBufferAccessUnitCount = 0; 706 return true; 707 } 708 709 if (audioTrackPositionTracker.isStalled(getWrittenFrames())) { 710 Log.w(TAG, "Resetting stalled audio track"); 711 flush(); 712 return true; 713 } 714 715 return false; 716 } 717 processBuffers(long avSyncPresentationTimeUs)718 private void processBuffers(long avSyncPresentationTimeUs) throws WriteException { 719 int count = activeAudioProcessors.length; 720 int index = count; 721 while (index >= 0) { 722 ByteBuffer input = index > 0 ? outputBuffers[index - 1] 723 : (inputBuffer != null ? inputBuffer : AudioProcessor.EMPTY_BUFFER); 724 if (index == count) { 725 writeBuffer(input, avSyncPresentationTimeUs); 726 } else { 727 AudioProcessor audioProcessor = activeAudioProcessors[index]; 728 audioProcessor.queueInput(input); 729 ByteBuffer output = audioProcessor.getOutput(); 730 outputBuffers[index] = output; 731 if (output.hasRemaining()) { 732 // Handle the output as input to the next audio processor or the AudioTrack. 733 index++; 734 continue; 735 } 736 } 737 738 if (input.hasRemaining()) { 739 // The input wasn't consumed and no output was produced, so give up for now. 740 return; 741 } 742 743 // Get more input from upstream. 744 index--; 745 } 746 } 747 748 @SuppressWarnings("ReferenceEquality") writeBuffer(ByteBuffer buffer, long avSyncPresentationTimeUs)749 private void writeBuffer(ByteBuffer buffer, long avSyncPresentationTimeUs) throws WriteException { 750 if (!buffer.hasRemaining()) { 751 return; 752 } 753 if (outputBuffer != null) { 754 Assertions.checkArgument(outputBuffer == buffer); 755 } else { 756 outputBuffer = buffer; 757 if (Util.SDK_INT < 21) { 758 int bytesRemaining = buffer.remaining(); 759 if (preV21OutputBuffer == null || preV21OutputBuffer.length < bytesRemaining) { 760 preV21OutputBuffer = new byte[bytesRemaining]; 761 } 762 int originalPosition = buffer.position(); 763 buffer.get(preV21OutputBuffer, 0, bytesRemaining); 764 buffer.position(originalPosition); 765 preV21OutputBufferOffset = 0; 766 } 767 } 768 int bytesRemaining = buffer.remaining(); 769 int bytesWritten = 0; 770 if (Util.SDK_INT < 21) { // isInputPcm == true 771 // Work out how many bytes we can write without the risk of blocking. 772 int bytesToWrite = audioTrackPositionTracker.getAvailableBufferSize(writtenPcmBytes); 773 if (bytesToWrite > 0) { 774 bytesToWrite = Math.min(bytesRemaining, bytesToWrite); 775 bytesWritten = audioTrack.write(preV21OutputBuffer, preV21OutputBufferOffset, bytesToWrite); 776 if (bytesWritten > 0) { 777 preV21OutputBufferOffset += bytesWritten; 778 buffer.position(buffer.position() + bytesWritten); 779 } 780 } 781 } else if (tunneling) { 782 Assertions.checkState(avSyncPresentationTimeUs != C.TIME_UNSET); 783 bytesWritten = writeNonBlockingWithAvSyncV21(audioTrack, buffer, bytesRemaining, 784 avSyncPresentationTimeUs); 785 } else { 786 bytesWritten = writeNonBlockingV21(audioTrack, buffer, bytesRemaining); 787 } 788 789 lastFeedElapsedRealtimeMs = SystemClock.elapsedRealtime(); 790 791 if (bytesWritten < 0) { 792 throw new WriteException(bytesWritten); 793 } 794 795 if (configuration.isInputPcm) { 796 writtenPcmBytes += bytesWritten; 797 } 798 if (bytesWritten == bytesRemaining) { 799 if (!configuration.isInputPcm) { 800 // When playing non-PCM, the inputBuffer is never processed, thus the last inputBuffer 801 // must be the current input buffer. 802 Assertions.checkState(buffer == inputBuffer); 803 writtenEncodedFrames += framesPerEncodedSample * inputBufferAccessUnitCount; 804 } 805 outputBuffer = null; 806 } 807 } 808 809 @Override playToEndOfStream()810 public void playToEndOfStream() throws WriteException { 811 if (!handledEndOfStream && isInitialized() && drainToEndOfStream()) { 812 playPendingData(); 813 handledEndOfStream = true; 814 } 815 } 816 drainToEndOfStream()817 private boolean drainToEndOfStream() throws WriteException { 818 boolean audioProcessorNeedsEndOfStream = false; 819 if (drainingAudioProcessorIndex == C.INDEX_UNSET) { 820 drainingAudioProcessorIndex = 821 configuration.processingEnabled ? 0 : activeAudioProcessors.length; 822 audioProcessorNeedsEndOfStream = true; 823 } 824 while (drainingAudioProcessorIndex < activeAudioProcessors.length) { 825 AudioProcessor audioProcessor = activeAudioProcessors[drainingAudioProcessorIndex]; 826 if (audioProcessorNeedsEndOfStream) { 827 audioProcessor.queueEndOfStream(); 828 } 829 processBuffers(C.TIME_UNSET); 830 if (!audioProcessor.isEnded()) { 831 return false; 832 } 833 audioProcessorNeedsEndOfStream = true; 834 drainingAudioProcessorIndex++; 835 } 836 837 // Finish writing any remaining output to the track. 838 if (outputBuffer != null) { 839 writeBuffer(outputBuffer, C.TIME_UNSET); 840 if (outputBuffer != null) { 841 return false; 842 } 843 } 844 drainingAudioProcessorIndex = C.INDEX_UNSET; 845 return true; 846 } 847 848 @Override isEnded()849 public boolean isEnded() { 850 return !isInitialized() || (handledEndOfStream && !hasPendingData()); 851 } 852 853 @Override hasPendingData()854 public boolean hasPendingData() { 855 return isInitialized() && audioTrackPositionTracker.hasPendingData(getWrittenFrames()); 856 } 857 858 /** 859 * @deprecated Use {@link #setPlaybackSpeed(float)} and {@link #setSkipSilenceEnabled(boolean)} 860 * instead. 861 */ 862 @SuppressWarnings("deprecation") 863 @Deprecated 864 @Override setPlaybackParameters(PlaybackParameters playbackParameters)865 public void setPlaybackParameters(PlaybackParameters playbackParameters) { 866 setPlaybackSpeedAndSkipSilence(playbackParameters.speed, getSkipSilenceEnabled()); 867 } 868 869 /** @deprecated Use {@link #getPlaybackSpeed()} and {@link #getSkipSilenceEnabled()} instead. */ 870 @SuppressWarnings("deprecation") 871 @Deprecated 872 @Override getPlaybackParameters()873 public PlaybackParameters getPlaybackParameters() { 874 MediaPositionParameters mediaPositionParameters = getMediaPositionParameters(); 875 return new PlaybackParameters(mediaPositionParameters.playbackSpeed); 876 } 877 878 @Override setPlaybackSpeed(float playbackSpeed)879 public void setPlaybackSpeed(float playbackSpeed) { 880 setPlaybackSpeedAndSkipSilence(playbackSpeed, getSkipSilenceEnabled()); 881 } 882 883 @Override getPlaybackSpeed()884 public float getPlaybackSpeed() { 885 return getMediaPositionParameters().playbackSpeed; 886 } 887 888 @Override setSkipSilenceEnabled(boolean skipSilenceEnabled)889 public void setSkipSilenceEnabled(boolean skipSilenceEnabled) { 890 setPlaybackSpeedAndSkipSilence(getPlaybackSpeed(), skipSilenceEnabled); 891 } 892 893 @Override getSkipSilenceEnabled()894 public boolean getSkipSilenceEnabled() { 895 return getMediaPositionParameters().skipSilence; 896 } 897 898 @Override setAudioAttributes(AudioAttributes audioAttributes)899 public void setAudioAttributes(AudioAttributes audioAttributes) { 900 if (this.audioAttributes.equals(audioAttributes)) { 901 return; 902 } 903 this.audioAttributes = audioAttributes; 904 if (tunneling) { 905 // The audio attributes are ignored in tunneling mode, so no need to reset. 906 return; 907 } 908 flush(); 909 audioSessionId = C.AUDIO_SESSION_ID_UNSET; 910 } 911 912 @Override setAudioSessionId(int audioSessionId)913 public void setAudioSessionId(int audioSessionId) { 914 if (this.audioSessionId != audioSessionId) { 915 this.audioSessionId = audioSessionId; 916 flush(); 917 } 918 } 919 920 @Override setAuxEffectInfo(AuxEffectInfo auxEffectInfo)921 public void setAuxEffectInfo(AuxEffectInfo auxEffectInfo) { 922 if (this.auxEffectInfo.equals(auxEffectInfo)) { 923 return; 924 } 925 int effectId = auxEffectInfo.effectId; 926 float sendLevel = auxEffectInfo.sendLevel; 927 if (audioTrack != null) { 928 if (this.auxEffectInfo.effectId != effectId) { 929 audioTrack.attachAuxEffect(effectId); 930 } 931 if (effectId != AuxEffectInfo.NO_AUX_EFFECT_ID) { 932 audioTrack.setAuxEffectSendLevel(sendLevel); 933 } 934 } 935 this.auxEffectInfo = auxEffectInfo; 936 } 937 938 @Override enableTunnelingV21(int tunnelingAudioSessionId)939 public void enableTunnelingV21(int tunnelingAudioSessionId) { 940 Assertions.checkState(Util.SDK_INT >= 21); 941 if (!tunneling || audioSessionId != tunnelingAudioSessionId) { 942 tunneling = true; 943 audioSessionId = tunnelingAudioSessionId; 944 flush(); 945 } 946 } 947 948 @Override disableTunneling()949 public void disableTunneling() { 950 if (tunneling) { 951 tunneling = false; 952 audioSessionId = C.AUDIO_SESSION_ID_UNSET; 953 flush(); 954 } 955 } 956 957 @Override setVolume(float volume)958 public void setVolume(float volume) { 959 if (this.volume != volume) { 960 this.volume = volume; 961 setVolumeInternal(); 962 } 963 } 964 setVolumeInternal()965 private void setVolumeInternal() { 966 if (!isInitialized()) { 967 // Do nothing. 968 } else if (Util.SDK_INT >= 21) { 969 setVolumeInternalV21(audioTrack, volume); 970 } else { 971 setVolumeInternalV3(audioTrack, volume); 972 } 973 } 974 975 @Override pause()976 public void pause() { 977 playing = false; 978 if (isInitialized() && audioTrackPositionTracker.pause()) { 979 audioTrack.pause(); 980 } 981 } 982 983 @Override flush()984 public void flush() { 985 if (isInitialized()) { 986 submittedPcmBytes = 0; 987 submittedEncodedFrames = 0; 988 writtenPcmBytes = 0; 989 writtenEncodedFrames = 0; 990 framesPerEncodedSample = 0; 991 mediaPositionParameters = 992 new MediaPositionParameters( 993 getPlaybackSpeed(), 994 getSkipSilenceEnabled(), 995 /* mediaTimeUs= */ 0, 996 /* audioTrackPositionUs= */ 0); 997 startMediaTimeUs = 0; 998 afterDrainParameters = null; 999 mediaPositionParametersCheckpoints.clear(); 1000 trimmingAudioProcessor.resetTrimmedFrameCount(); 1001 flushAudioProcessors(); 1002 inputBuffer = null; 1003 inputBufferAccessUnitCount = 0; 1004 outputBuffer = null; 1005 stoppedAudioTrack = false; 1006 handledEndOfStream = false; 1007 drainingAudioProcessorIndex = C.INDEX_UNSET; 1008 avSyncHeader = null; 1009 bytesUntilNextAvSync = 0; 1010 if (audioTrackPositionTracker.isPlaying()) { 1011 audioTrack.pause(); 1012 } 1013 // AudioTrack.release can take some time, so we call it on a background thread. 1014 final AudioTrack toRelease = audioTrack; 1015 audioTrack = null; 1016 if (pendingConfiguration != null) { 1017 configuration = pendingConfiguration; 1018 pendingConfiguration = null; 1019 } 1020 audioTrackPositionTracker.reset(); 1021 releasingConditionVariable.close(); 1022 new Thread("ExoPlayer:AudioTrackReleaseThread") { 1023 @Override 1024 public void run() { 1025 try { 1026 toRelease.flush(); 1027 toRelease.release(); 1028 } finally { 1029 releasingConditionVariable.open(); 1030 } 1031 } 1032 }.start(); 1033 } 1034 } 1035 1036 @Override reset()1037 public void reset() { 1038 flush(); 1039 releaseKeepSessionIdAudioTrack(); 1040 for (AudioProcessor audioProcessor : toIntPcmAvailableAudioProcessors) { 1041 audioProcessor.reset(); 1042 } 1043 for (AudioProcessor audioProcessor : toFloatPcmAvailableAudioProcessors) { 1044 audioProcessor.reset(); 1045 } 1046 audioSessionId = C.AUDIO_SESSION_ID_UNSET; 1047 playing = false; 1048 } 1049 1050 // Internal methods. 1051 1052 /** Releases {@link #keepSessionIdAudioTrack} asynchronously, if it is non-{@code null}. */ releaseKeepSessionIdAudioTrack()1053 private void releaseKeepSessionIdAudioTrack() { 1054 if (keepSessionIdAudioTrack == null) { 1055 return; 1056 } 1057 1058 // AudioTrack.release can take some time, so we call it on a background thread. 1059 final AudioTrack toRelease = keepSessionIdAudioTrack; 1060 keepSessionIdAudioTrack = null; 1061 new Thread() { 1062 @Override 1063 public void run() { 1064 toRelease.release(); 1065 } 1066 }.start(); 1067 } 1068 setPlaybackSpeedAndSkipSilence(float playbackSpeed, boolean skipSilence)1069 private void setPlaybackSpeedAndSkipSilence(float playbackSpeed, boolean skipSilence) { 1070 MediaPositionParameters currentMediaPositionParameters = getMediaPositionParameters(); 1071 if (playbackSpeed != currentMediaPositionParameters.playbackSpeed 1072 || skipSilence != currentMediaPositionParameters.skipSilence) { 1073 MediaPositionParameters mediaPositionParameters = 1074 new MediaPositionParameters( 1075 playbackSpeed, 1076 skipSilence, 1077 /* mediaTimeUs= */ C.TIME_UNSET, 1078 /* audioTrackPositionUs= */ C.TIME_UNSET); 1079 if (isInitialized()) { 1080 // Drain the audio processors so we can determine the frame position at which the new 1081 // parameters apply. 1082 this.afterDrainParameters = mediaPositionParameters; 1083 } else { 1084 // Update the audio processor chain parameters now. They will be applied to the audio 1085 // processors during initialization. 1086 this.mediaPositionParameters = mediaPositionParameters; 1087 } 1088 } 1089 } 1090 getMediaPositionParameters()1091 private MediaPositionParameters getMediaPositionParameters() { 1092 // Mask the already set parameters. 1093 return afterDrainParameters != null 1094 ? afterDrainParameters 1095 : !mediaPositionParametersCheckpoints.isEmpty() 1096 ? mediaPositionParametersCheckpoints.getLast() 1097 : mediaPositionParameters; 1098 } 1099 applyPlaybackSpeedAndSkipSilence(long presentationTimeUs)1100 private void applyPlaybackSpeedAndSkipSilence(long presentationTimeUs) { 1101 float playbackSpeed = 1102 configuration.canApplyPlaybackParameters 1103 ? audioProcessorChain.applyPlaybackSpeed(getPlaybackSpeed()) 1104 : DEFAULT_PLAYBACK_SPEED; 1105 boolean skipSilenceEnabled = 1106 configuration.canApplyPlaybackParameters 1107 ? audioProcessorChain.applySkipSilenceEnabled(getSkipSilenceEnabled()) 1108 : DEFAULT_SKIP_SILENCE; 1109 mediaPositionParametersCheckpoints.add( 1110 new MediaPositionParameters( 1111 playbackSpeed, 1112 skipSilenceEnabled, 1113 /* mediaTimeUs= */ Math.max(0, presentationTimeUs), 1114 /* audioTrackPositionUs= */ configuration.framesToDurationUs(getWrittenFrames()))); 1115 setupAudioProcessors(); 1116 if (listener != null) { 1117 listener.onSkipSilenceEnabledChanged(skipSilenceEnabled); 1118 } 1119 } 1120 1121 /** 1122 * Applies and updates media position parameters. 1123 * 1124 * @param positionUs The current audio track position, in microseconds. 1125 * @return The current media time, in microseconds. 1126 */ applyMediaPositionParameters(long positionUs)1127 private long applyMediaPositionParameters(long positionUs) { 1128 while (!mediaPositionParametersCheckpoints.isEmpty() 1129 && positionUs >= mediaPositionParametersCheckpoints.getFirst().audioTrackPositionUs) { 1130 // We are playing (or about to play) media with the new parameters, so update them. 1131 mediaPositionParameters = mediaPositionParametersCheckpoints.remove(); 1132 } 1133 1134 long playoutDurationSinceLastCheckpoint = 1135 positionUs - mediaPositionParameters.audioTrackPositionUs; 1136 if (mediaPositionParameters.playbackSpeed != 1f) { 1137 if (mediaPositionParametersCheckpoints.isEmpty()) { 1138 playoutDurationSinceLastCheckpoint = 1139 audioProcessorChain.getMediaDuration(playoutDurationSinceLastCheckpoint); 1140 } else { 1141 // Playing data at a previous playback speed, so fall back to multiplying by the speed. 1142 playoutDurationSinceLastCheckpoint = 1143 Util.getMediaDurationForPlayoutDuration( 1144 playoutDurationSinceLastCheckpoint, mediaPositionParameters.playbackSpeed); 1145 } 1146 } 1147 return mediaPositionParameters.mediaTimeUs + playoutDurationSinceLastCheckpoint; 1148 } 1149 applySkipping(long positionUs)1150 private long applySkipping(long positionUs) { 1151 return positionUs 1152 + configuration.framesToDurationUs(audioProcessorChain.getSkippedOutputFrameCount()); 1153 } 1154 isInitialized()1155 private boolean isInitialized() { 1156 return audioTrack != null; 1157 } 1158 getSubmittedFrames()1159 private long getSubmittedFrames() { 1160 return configuration.isInputPcm 1161 ? (submittedPcmBytes / configuration.inputPcmFrameSize) 1162 : submittedEncodedFrames; 1163 } 1164 getWrittenFrames()1165 private long getWrittenFrames() { 1166 return configuration.isInputPcm 1167 ? (writtenPcmBytes / configuration.outputPcmFrameSize) 1168 : writtenEncodedFrames; 1169 } 1170 initializeKeepSessionIdAudioTrack(int audioSessionId)1171 private static AudioTrack initializeKeepSessionIdAudioTrack(int audioSessionId) { 1172 int sampleRate = 4000; // Equal to private AudioTrack.MIN_SAMPLE_RATE. 1173 int channelConfig = AudioFormat.CHANNEL_OUT_MONO; 1174 @C.PcmEncoding int encoding = C.ENCODING_PCM_16BIT; 1175 int bufferSize = 2; // Use a two byte buffer, as it is not actually used for playback. 1176 return new AudioTrack(C.STREAM_TYPE_DEFAULT, sampleRate, channelConfig, encoding, bufferSize, 1177 MODE_STATIC, audioSessionId); 1178 } 1179 getChannelConfig(int channelCount, boolean isInputPcm)1180 private static int getChannelConfig(int channelCount, boolean isInputPcm) { 1181 if (Util.SDK_INT <= 28 && !isInputPcm) { 1182 // In passthrough mode the channel count used to configure the audio track doesn't affect how 1183 // the stream is handled, except that some devices do overly-strict channel configuration 1184 // checks. Therefore we override the channel count so that a known-working channel 1185 // configuration is chosen in all cases. See [Internal: b/29116190]. 1186 if (channelCount == 7) { 1187 channelCount = 8; 1188 } else if (channelCount == 3 || channelCount == 4 || channelCount == 5) { 1189 channelCount = 6; 1190 } 1191 } 1192 1193 // Workaround for Nexus Player not reporting support for mono passthrough. 1194 // (See [Internal: b/34268671].) 1195 if (Util.SDK_INT <= 26 && "fugu".equals(Util.DEVICE) && !isInputPcm && channelCount == 1) { 1196 channelCount = 2; 1197 } 1198 1199 return Util.getAudioTrackChannelConfig(channelCount); 1200 } 1201 getMaximumEncodedRateBytesPerSecond(@.Encoding int encoding)1202 private static int getMaximumEncodedRateBytesPerSecond(@C.Encoding int encoding) { 1203 switch (encoding) { 1204 case C.ENCODING_MP3: 1205 return MpegAudioUtil.MAX_RATE_BYTES_PER_SECOND; 1206 case C.ENCODING_AAC_LC: 1207 return AacUtil.AAC_LC_MAX_RATE_BYTES_PER_SECOND; 1208 case C.ENCODING_AAC_HE_V1: 1209 return AacUtil.AAC_HE_V1_MAX_RATE_BYTES_PER_SECOND; 1210 case C.ENCODING_AAC_HE_V2: 1211 return AacUtil.AAC_HE_V2_MAX_RATE_BYTES_PER_SECOND; 1212 case C.ENCODING_AAC_XHE: 1213 return AacUtil.AAC_XHE_MAX_RATE_BYTES_PER_SECOND; 1214 case C.ENCODING_AAC_ELD: 1215 return AacUtil.AAC_ELD_MAX_RATE_BYTES_PER_SECOND; 1216 case C.ENCODING_AC3: 1217 return Ac3Util.AC3_MAX_RATE_BYTES_PER_SECOND; 1218 case C.ENCODING_E_AC3: 1219 case C.ENCODING_E_AC3_JOC: 1220 return Ac3Util.E_AC3_MAX_RATE_BYTES_PER_SECOND; 1221 case C.ENCODING_AC4: 1222 return Ac4Util.MAX_RATE_BYTES_PER_SECOND; 1223 case C.ENCODING_DTS: 1224 return DtsUtil.DTS_MAX_RATE_BYTES_PER_SECOND; 1225 case C.ENCODING_DTS_HD: 1226 return DtsUtil.DTS_HD_MAX_RATE_BYTES_PER_SECOND; 1227 case C.ENCODING_DOLBY_TRUEHD: 1228 return Ac3Util.TRUEHD_MAX_RATE_BYTES_PER_SECOND; 1229 case C.ENCODING_PCM_16BIT: 1230 case C.ENCODING_PCM_16BIT_BIG_ENDIAN: 1231 case C.ENCODING_PCM_24BIT: 1232 case C.ENCODING_PCM_32BIT: 1233 case C.ENCODING_PCM_8BIT: 1234 case C.ENCODING_PCM_FLOAT: 1235 case C.ENCODING_INVALID: 1236 case Format.NO_VALUE: 1237 default: 1238 throw new IllegalArgumentException(); 1239 } 1240 } 1241 getFramesPerEncodedSample(@.Encoding int encoding, ByteBuffer buffer)1242 private static int getFramesPerEncodedSample(@C.Encoding int encoding, ByteBuffer buffer) { 1243 switch (encoding) { 1244 case C.ENCODING_MP3: 1245 int headerDataInBigEndian = Util.getBigEndianInt(buffer, buffer.position()); 1246 return MpegAudioUtil.parseMpegAudioFrameSampleCount(headerDataInBigEndian); 1247 case C.ENCODING_AAC_LC: 1248 return AacUtil.AAC_LC_AUDIO_SAMPLE_COUNT; 1249 case C.ENCODING_AAC_HE_V1: 1250 case C.ENCODING_AAC_HE_V2: 1251 return AacUtil.AAC_HE_AUDIO_SAMPLE_COUNT; 1252 case C.ENCODING_AAC_XHE: 1253 return AacUtil.AAC_XHE_AUDIO_SAMPLE_COUNT; 1254 case C.ENCODING_AAC_ELD: 1255 return AacUtil.AAC_LD_AUDIO_SAMPLE_COUNT; 1256 case C.ENCODING_DTS: 1257 case C.ENCODING_DTS_HD: 1258 return DtsUtil.parseDtsAudioSampleCount(buffer); 1259 case C.ENCODING_AC3: 1260 case C.ENCODING_E_AC3: 1261 case C.ENCODING_E_AC3_JOC: 1262 return Ac3Util.parseAc3SyncframeAudioSampleCount(buffer); 1263 case C.ENCODING_AC4: 1264 return Ac4Util.parseAc4SyncframeAudioSampleCount(buffer); 1265 case C.ENCODING_DOLBY_TRUEHD: 1266 int syncframeOffset = Ac3Util.findTrueHdSyncframeOffset(buffer); 1267 return syncframeOffset == C.INDEX_UNSET 1268 ? 0 1269 : (Ac3Util.parseTrueHdSyncframeAudioSampleCount(buffer, syncframeOffset) 1270 * Ac3Util.TRUEHD_RECHUNK_SAMPLE_COUNT); 1271 case C.ENCODING_PCM_16BIT: 1272 case C.ENCODING_PCM_16BIT_BIG_ENDIAN: 1273 case C.ENCODING_PCM_24BIT: 1274 case C.ENCODING_PCM_32BIT: 1275 case C.ENCODING_PCM_8BIT: 1276 case C.ENCODING_PCM_FLOAT: 1277 case C.ENCODING_INVALID: 1278 case Format.NO_VALUE: 1279 default: 1280 throw new IllegalStateException("Unexpected audio encoding: " + encoding); 1281 } 1282 } 1283 1284 @RequiresApi(21) writeNonBlockingV21(AudioTrack audioTrack, ByteBuffer buffer, int size)1285 private static int writeNonBlockingV21(AudioTrack audioTrack, ByteBuffer buffer, int size) { 1286 return audioTrack.write(buffer, size, WRITE_NON_BLOCKING); 1287 } 1288 1289 @RequiresApi(21) writeNonBlockingWithAvSyncV21( AudioTrack audioTrack, ByteBuffer buffer, int size, long presentationTimeUs)1290 private int writeNonBlockingWithAvSyncV21( 1291 AudioTrack audioTrack, ByteBuffer buffer, int size, long presentationTimeUs) { 1292 if (Util.SDK_INT >= 26) { 1293 // The underlying platform AudioTrack writes AV sync headers directly. 1294 return audioTrack.write(buffer, size, WRITE_NON_BLOCKING, presentationTimeUs * 1000); 1295 } 1296 if (avSyncHeader == null) { 1297 avSyncHeader = ByteBuffer.allocate(16); 1298 avSyncHeader.order(ByteOrder.BIG_ENDIAN); 1299 avSyncHeader.putInt(0x55550001); 1300 } 1301 if (bytesUntilNextAvSync == 0) { 1302 avSyncHeader.putInt(4, size); 1303 avSyncHeader.putLong(8, presentationTimeUs * 1000); 1304 avSyncHeader.position(0); 1305 bytesUntilNextAvSync = size; 1306 } 1307 int avSyncHeaderBytesRemaining = avSyncHeader.remaining(); 1308 if (avSyncHeaderBytesRemaining > 0) { 1309 int result = audioTrack.write(avSyncHeader, avSyncHeaderBytesRemaining, WRITE_NON_BLOCKING); 1310 if (result < 0) { 1311 bytesUntilNextAvSync = 0; 1312 return result; 1313 } 1314 if (result < avSyncHeaderBytesRemaining) { 1315 return 0; 1316 } 1317 } 1318 int result = writeNonBlockingV21(audioTrack, buffer, size); 1319 if (result < 0) { 1320 bytesUntilNextAvSync = 0; 1321 return result; 1322 } 1323 bytesUntilNextAvSync -= result; 1324 return result; 1325 } 1326 1327 @RequiresApi(21) setVolumeInternalV21(AudioTrack audioTrack, float volume)1328 private static void setVolumeInternalV21(AudioTrack audioTrack, float volume) { 1329 audioTrack.setVolume(volume); 1330 } 1331 setVolumeInternalV3(AudioTrack audioTrack, float volume)1332 private static void setVolumeInternalV3(AudioTrack audioTrack, float volume) { 1333 audioTrack.setStereoVolume(volume, volume); 1334 } 1335 playPendingData()1336 private void playPendingData() { 1337 if (!stoppedAudioTrack) { 1338 stoppedAudioTrack = true; 1339 audioTrackPositionTracker.handleEndOfStream(getWrittenFrames()); 1340 audioTrack.stop(); 1341 bytesUntilNextAvSync = 0; 1342 } 1343 } 1344 1345 /** Stores parameters used to calculate the current media position. */ 1346 private static final class MediaPositionParameters { 1347 1348 /** The playback speed. */ 1349 public final float playbackSpeed; 1350 /** Whether to skip silences. */ 1351 public final boolean skipSilence; 1352 /** The media time from which the playback parameters apply, in microseconds. */ 1353 public final long mediaTimeUs; 1354 /** The audio track position from which the playback parameters apply, in microseconds. */ 1355 public final long audioTrackPositionUs; 1356 MediaPositionParameters( float playbackSpeed, boolean skipSilence, long mediaTimeUs, long audioTrackPositionUs)1357 private MediaPositionParameters( 1358 float playbackSpeed, boolean skipSilence, long mediaTimeUs, long audioTrackPositionUs) { 1359 this.playbackSpeed = playbackSpeed; 1360 this.skipSilence = skipSilence; 1361 this.mediaTimeUs = mediaTimeUs; 1362 this.audioTrackPositionUs = audioTrackPositionUs; 1363 } 1364 } 1365 1366 private final class PositionTrackerListener implements AudioTrackPositionTracker.Listener { 1367 1368 @Override onPositionFramesMismatch( long audioTimestampPositionFrames, long audioTimestampSystemTimeUs, long systemTimeUs, long playbackPositionUs)1369 public void onPositionFramesMismatch( 1370 long audioTimestampPositionFrames, 1371 long audioTimestampSystemTimeUs, 1372 long systemTimeUs, 1373 long playbackPositionUs) { 1374 String message = 1375 "Spurious audio timestamp (frame position mismatch): " 1376 + audioTimestampPositionFrames 1377 + ", " 1378 + audioTimestampSystemTimeUs 1379 + ", " 1380 + systemTimeUs 1381 + ", " 1382 + playbackPositionUs 1383 + ", " 1384 + getSubmittedFrames() 1385 + ", " 1386 + getWrittenFrames(); 1387 if (failOnSpuriousAudioTimestamp) { 1388 throw new InvalidAudioTrackTimestampException(message); 1389 } 1390 Log.w(TAG, message); 1391 } 1392 1393 @Override onSystemTimeUsMismatch( long audioTimestampPositionFrames, long audioTimestampSystemTimeUs, long systemTimeUs, long playbackPositionUs)1394 public void onSystemTimeUsMismatch( 1395 long audioTimestampPositionFrames, 1396 long audioTimestampSystemTimeUs, 1397 long systemTimeUs, 1398 long playbackPositionUs) { 1399 String message = 1400 "Spurious audio timestamp (system clock mismatch): " 1401 + audioTimestampPositionFrames 1402 + ", " 1403 + audioTimestampSystemTimeUs 1404 + ", " 1405 + systemTimeUs 1406 + ", " 1407 + playbackPositionUs 1408 + ", " 1409 + getSubmittedFrames() 1410 + ", " 1411 + getWrittenFrames(); 1412 if (failOnSpuriousAudioTimestamp) { 1413 throw new InvalidAudioTrackTimestampException(message); 1414 } 1415 Log.w(TAG, message); 1416 } 1417 1418 @Override onInvalidLatency(long latencyUs)1419 public void onInvalidLatency(long latencyUs) { 1420 Log.w(TAG, "Ignoring impossibly large audio latency: " + latencyUs); 1421 } 1422 1423 @Override onUnderrun(int bufferSize, long bufferSizeMs)1424 public void onUnderrun(int bufferSize, long bufferSizeMs) { 1425 if (listener != null) { 1426 long elapsedSinceLastFeedMs = SystemClock.elapsedRealtime() - lastFeedElapsedRealtimeMs; 1427 listener.onUnderrun(bufferSize, bufferSizeMs, elapsedSinceLastFeedMs); 1428 } 1429 } 1430 } 1431 1432 /** Stores configuration relating to the audio format. */ 1433 private static final class Configuration { 1434 1435 public final boolean isInputPcm; 1436 public final int inputPcmFrameSize; 1437 public final int inputSampleRate; 1438 public final int outputPcmFrameSize; 1439 public final int outputSampleRate; 1440 public final int outputChannelConfig; 1441 @C.Encoding public final int outputEncoding; 1442 public final int bufferSize; 1443 public final boolean processingEnabled; 1444 public final boolean canApplyPlaybackParameters; 1445 public final AudioProcessor[] availableAudioProcessors; 1446 Configuration( boolean isInputPcm, int inputPcmFrameSize, int inputSampleRate, int outputPcmFrameSize, int outputSampleRate, int outputChannelConfig, int outputEncoding, int specifiedBufferSize, boolean processingEnabled, boolean canApplyPlaybackParameters, AudioProcessor[] availableAudioProcessors)1447 public Configuration( 1448 boolean isInputPcm, 1449 int inputPcmFrameSize, 1450 int inputSampleRate, 1451 int outputPcmFrameSize, 1452 int outputSampleRate, 1453 int outputChannelConfig, 1454 int outputEncoding, 1455 int specifiedBufferSize, 1456 boolean processingEnabled, 1457 boolean canApplyPlaybackParameters, 1458 AudioProcessor[] availableAudioProcessors) { 1459 this.isInputPcm = isInputPcm; 1460 this.inputPcmFrameSize = inputPcmFrameSize; 1461 this.inputSampleRate = inputSampleRate; 1462 this.outputPcmFrameSize = outputPcmFrameSize; 1463 this.outputSampleRate = outputSampleRate; 1464 this.outputChannelConfig = outputChannelConfig; 1465 this.outputEncoding = outputEncoding; 1466 this.bufferSize = specifiedBufferSize != 0 ? specifiedBufferSize : getDefaultBufferSize(); 1467 this.processingEnabled = processingEnabled; 1468 this.canApplyPlaybackParameters = canApplyPlaybackParameters; 1469 this.availableAudioProcessors = availableAudioProcessors; 1470 } 1471 canReuseAudioTrack(Configuration audioTrackConfiguration)1472 public boolean canReuseAudioTrack(Configuration audioTrackConfiguration) { 1473 return audioTrackConfiguration.outputEncoding == outputEncoding 1474 && audioTrackConfiguration.outputSampleRate == outputSampleRate 1475 && audioTrackConfiguration.outputChannelConfig == outputChannelConfig; 1476 } 1477 inputFramesToDurationUs(long frameCount)1478 public long inputFramesToDurationUs(long frameCount) { 1479 return (frameCount * C.MICROS_PER_SECOND) / inputSampleRate; 1480 } 1481 framesToDurationUs(long frameCount)1482 public long framesToDurationUs(long frameCount) { 1483 return (frameCount * C.MICROS_PER_SECOND) / outputSampleRate; 1484 } 1485 durationUsToFrames(long durationUs)1486 public long durationUsToFrames(long durationUs) { 1487 return (durationUs * outputSampleRate) / C.MICROS_PER_SECOND; 1488 } 1489 buildAudioTrack( boolean tunneling, AudioAttributes audioAttributes, int audioSessionId)1490 public AudioTrack buildAudioTrack( 1491 boolean tunneling, AudioAttributes audioAttributes, int audioSessionId) 1492 throws InitializationException { 1493 AudioTrack audioTrack; 1494 if (Util.SDK_INT >= 21) { 1495 audioTrack = createAudioTrackV21(tunneling, audioAttributes, audioSessionId); 1496 } else { 1497 int streamType = Util.getStreamTypeForAudioUsage(audioAttributes.usage); 1498 if (audioSessionId == C.AUDIO_SESSION_ID_UNSET) { 1499 audioTrack = 1500 new AudioTrack( 1501 streamType, 1502 outputSampleRate, 1503 outputChannelConfig, 1504 outputEncoding, 1505 bufferSize, 1506 MODE_STREAM); 1507 } else { 1508 // Re-attach to the same audio session. 1509 audioTrack = 1510 new AudioTrack( 1511 streamType, 1512 outputSampleRate, 1513 outputChannelConfig, 1514 outputEncoding, 1515 bufferSize, 1516 MODE_STREAM, 1517 audioSessionId); 1518 } 1519 } 1520 1521 int state = audioTrack.getState(); 1522 if (state != STATE_INITIALIZED) { 1523 try { 1524 audioTrack.release(); 1525 } catch (Exception e) { 1526 // The track has already failed to initialize, so it wouldn't be that surprising if 1527 // release were to fail too. Swallow the exception. 1528 } 1529 throw new InitializationException(state, outputSampleRate, outputChannelConfig, bufferSize); 1530 } 1531 return audioTrack; 1532 } 1533 1534 @RequiresApi(21) createAudioTrackV21( boolean tunneling, AudioAttributes audioAttributes, int audioSessionId)1535 private AudioTrack createAudioTrackV21( 1536 boolean tunneling, AudioAttributes audioAttributes, int audioSessionId) { 1537 android.media.AudioAttributes attributes; 1538 if (tunneling) { 1539 attributes = 1540 new android.media.AudioAttributes.Builder() 1541 .setContentType(android.media.AudioAttributes.CONTENT_TYPE_MOVIE) 1542 .setFlags(android.media.AudioAttributes.FLAG_HW_AV_SYNC) 1543 .setUsage(android.media.AudioAttributes.USAGE_MEDIA) 1544 .build(); 1545 } else { 1546 attributes = audioAttributes.getAudioAttributesV21(); 1547 } 1548 AudioFormat format = 1549 new AudioFormat.Builder() 1550 .setChannelMask(outputChannelConfig) 1551 .setEncoding(outputEncoding) 1552 .setSampleRate(outputSampleRate) 1553 .build(); 1554 return new AudioTrack( 1555 attributes, 1556 format, 1557 bufferSize, 1558 MODE_STREAM, 1559 audioSessionId != C.AUDIO_SESSION_ID_UNSET 1560 ? audioSessionId 1561 : AudioManager.AUDIO_SESSION_ID_GENERATE); 1562 } 1563 getDefaultBufferSize()1564 private int getDefaultBufferSize() { 1565 if (isInputPcm) { 1566 int minBufferSize = 1567 AudioTrack.getMinBufferSize(outputSampleRate, outputChannelConfig, outputEncoding); 1568 Assertions.checkState(minBufferSize != ERROR_BAD_VALUE); 1569 int multipliedBufferSize = minBufferSize * BUFFER_MULTIPLICATION_FACTOR; 1570 int minAppBufferSize = 1571 (int) durationUsToFrames(MIN_BUFFER_DURATION_US) * outputPcmFrameSize; 1572 int maxAppBufferSize = 1573 (int) 1574 Math.max( 1575 minBufferSize, durationUsToFrames(MAX_BUFFER_DURATION_US) * outputPcmFrameSize); 1576 return Util.constrainValue(multipliedBufferSize, minAppBufferSize, maxAppBufferSize); 1577 } else { 1578 int rate = getMaximumEncodedRateBytesPerSecond(outputEncoding); 1579 if (outputEncoding == C.ENCODING_AC3) { 1580 rate *= AC3_BUFFER_MULTIPLICATION_FACTOR; 1581 } 1582 return (int) (PASSTHROUGH_BUFFER_DURATION_US * rate / C.MICROS_PER_SECOND); 1583 } 1584 } 1585 } 1586 } 1587