@Test public void trimsStartFrames() throws Exception { configureDefaultAudioSink( CHANNEL_COUNT_STEREO, TRIM_100_MS_FRAME_COUNT, 0); defaultAudioSink.handleBuffer(createDefaultSilenceBuffer(), 0); assertThat(arrayAudioBufferSink.output) .hasLength( (BYTES_PER_FRAME_16_BIT * CHANNEL_COUNT_STEREO * (SAMPLE_RATE_44_1 - TRIM_100_MS_FRAME_COUNT))); }
@Override @SuppressWarnings("ReferenceEquality") public boolean handleBuffer(ByteBuffer buffer, long presentationTimeUs) throws InitializationException, WriteException { Assertions.checkArgument(inputBuffer == null || buffer == inputBuffer); if (pendingConfiguration != null) { if (!drainAudioProcessorsToEndOfStream()) { return false; } configuration = pendingConfiguration; pendingConfiguration = null; playbackParameters = configuration.canApplyPlaybackParameters ? audioProcessorChain.applyPlaybackParameters(playbackParameters) : PlaybackParameters.DEFAULT; setupAudioProcessors(); } if (!isInitialized()) { initialize(); if (playing) { play(); } } if (!audioTrackPositionTracker.mayHandleBuffer(getWrittenFrames())) { return false; } if (inputBuffer == null) { if (!buffer.hasRemaining()) { return true; } if (!configuration.isInputPcm && framesPerEncodedSample == 0) { framesPerEncodedSample = getFramesPerEncodedSample(configuration.outputEncoding, buffer); if (framesPerEncodedSample == 0) { return true; } } if (afterDrainPlaybackParameters != null) { if (!drainAudioProcessorsToEndOfStream()) { return false; } PlaybackParameters newPlaybackParameters = afterDrainPlaybackParameters; afterDrainPlaybackParameters = null; newPlaybackParameters = audioProcessorChain.applyPlaybackParameters(newPlaybackParameters); playbackParametersCheckpoints.add( new PlaybackParametersCheckpoint( newPlaybackParameters, Math.max(0, presentationTimeUs), configuration.framesToDurationUs(getWrittenFrames()))); setupAudioProcessors(); } if (startMediaTimeState == START_NOT_SET) { startMediaTimeUs = Math.max(0, presentationTimeUs); startMediaTimeState = START_IN_SYNC; } else { long expectedPresentationTimeUs = startMediaTimeUs + configuration.inputFramesToDurationUs( getSubmittedFrames() - trimmingAudioProcessor.getTrimmedFrameCount()); if (startMediaTimeState == START_IN_SYNC && Math.abs(expectedPresentationTimeUs - presentationTimeUs) > 200000) { Log.e(TAG, "Discontinuity detected [expected " + expectedPresentationTimeUs + ", got " + presentationTimeUs + "]"); startMediaTimeState = START_NEED_SYNC; } if (startMediaTimeState == START_NEED_SYNC) { long adjustmentUs = presentationTimeUs - expectedPresentationTimeUs; startMediaTimeUs += adjustmentUs; startMediaTimeState = START_IN_SYNC; if (listener != null && adjustmentUs != 0) { listener.onPositionDiscontinuity(); } } } if (configuration.isInputPcm) { submittedPcmBytes += buffer.remaining(); } else { submittedEncodedFrames += framesPerEncodedSample; } inputBuffer = buffer; } if (configuration.processingEnabled) { processBuffers(presentationTimeUs); } else { writeBuffer(inputBuffer, presentationTimeUs); } if (!inputBuffer.hasRemaining()) { inputBuffer = null; return true; } if (audioTrackPositionTracker.isStalled(getWrittenFrames())) { Log.w(TAG, "Resetting stalled audio track"); flush(); return true; } return false; }
DefaultAudioSink implements AudioSink { @Override @SuppressWarnings("ReferenceEquality") public boolean handleBuffer(ByteBuffer buffer, long presentationTimeUs) throws InitializationException, WriteException { Assertions.checkArgument(inputBuffer == null || buffer == inputBuffer); if (pendingConfiguration != null) { if (!drainAudioProcessorsToEndOfStream()) { return false; } configuration = pendingConfiguration; pendingConfiguration = null; playbackParameters = configuration.canApplyPlaybackParameters ? audioProcessorChain.applyPlaybackParameters(playbackParameters) : PlaybackParameters.DEFAULT; setupAudioProcessors(); } if (!isInitialized()) { initialize(); if (playing) { play(); } } if (!audioTrackPositionTracker.mayHandleBuffer(getWrittenFrames())) { return false; } if (inputBuffer == null) { if (!buffer.hasRemaining()) { return true; } if (!configuration.isInputPcm && framesPerEncodedSample == 0) { framesPerEncodedSample = getFramesPerEncodedSample(configuration.outputEncoding, buffer); if (framesPerEncodedSample == 0) { return true; } } if (afterDrainPlaybackParameters != null) { if (!drainAudioProcessorsToEndOfStream()) { return false; } PlaybackParameters newPlaybackParameters = afterDrainPlaybackParameters; afterDrainPlaybackParameters = null; newPlaybackParameters = audioProcessorChain.applyPlaybackParameters(newPlaybackParameters); playbackParametersCheckpoints.add( new PlaybackParametersCheckpoint( newPlaybackParameters, Math.max(0, presentationTimeUs), configuration.framesToDurationUs(getWrittenFrames()))); setupAudioProcessors(); } if (startMediaTimeState == START_NOT_SET) { startMediaTimeUs = Math.max(0, presentationTimeUs); startMediaTimeState = START_IN_SYNC; } else { long expectedPresentationTimeUs = startMediaTimeUs + configuration.inputFramesToDurationUs( getSubmittedFrames() - trimmingAudioProcessor.getTrimmedFrameCount()); if (startMediaTimeState == START_IN_SYNC && Math.abs(expectedPresentationTimeUs - presentationTimeUs) > 200000) { Log.e(TAG, "Discontinuity detected [expected " + expectedPresentationTimeUs + ", got " + presentationTimeUs + "]"); startMediaTimeState = START_NEED_SYNC; } if (startMediaTimeState == START_NEED_SYNC) { long adjustmentUs = presentationTimeUs - expectedPresentationTimeUs; startMediaTimeUs += adjustmentUs; startMediaTimeState = START_IN_SYNC; if (listener != null && adjustmentUs != 0) { listener.onPositionDiscontinuity(); } } } if (configuration.isInputPcm) { submittedPcmBytes += buffer.remaining(); } else { submittedEncodedFrames += framesPerEncodedSample; } inputBuffer = buffer; } if (configuration.processingEnabled) { processBuffers(presentationTimeUs); } else { writeBuffer(inputBuffer, presentationTimeUs); } if (!inputBuffer.hasRemaining()) { inputBuffer = null; return true; } if (audioTrackPositionTracker.isStalled(getWrittenFrames())) { Log.w(TAG, "Resetting stalled audio track"); flush(); return true; } return false; } }
DefaultAudioSink implements AudioSink { @Override @SuppressWarnings("ReferenceEquality") public boolean handleBuffer(ByteBuffer buffer, long presentationTimeUs) throws InitializationException, WriteException { Assertions.checkArgument(inputBuffer == null || buffer == inputBuffer); if (pendingConfiguration != null) { if (!drainAudioProcessorsToEndOfStream()) { return false; } configuration = pendingConfiguration; pendingConfiguration = null; playbackParameters = configuration.canApplyPlaybackParameters ? audioProcessorChain.applyPlaybackParameters(playbackParameters) : PlaybackParameters.DEFAULT; setupAudioProcessors(); } if (!isInitialized()) { initialize(); if (playing) { play(); } } if (!audioTrackPositionTracker.mayHandleBuffer(getWrittenFrames())) { return false; } if (inputBuffer == null) { if (!buffer.hasRemaining()) { return true; } if (!configuration.isInputPcm && framesPerEncodedSample == 0) { framesPerEncodedSample = getFramesPerEncodedSample(configuration.outputEncoding, buffer); if (framesPerEncodedSample == 0) { return true; } } if (afterDrainPlaybackParameters != null) { if (!drainAudioProcessorsToEndOfStream()) { return false; } PlaybackParameters newPlaybackParameters = afterDrainPlaybackParameters; afterDrainPlaybackParameters = null; newPlaybackParameters = audioProcessorChain.applyPlaybackParameters(newPlaybackParameters); playbackParametersCheckpoints.add( new PlaybackParametersCheckpoint( newPlaybackParameters, Math.max(0, presentationTimeUs), configuration.framesToDurationUs(getWrittenFrames()))); setupAudioProcessors(); } if (startMediaTimeState == START_NOT_SET) { startMediaTimeUs = Math.max(0, presentationTimeUs); startMediaTimeState = START_IN_SYNC; } else { long expectedPresentationTimeUs = startMediaTimeUs + configuration.inputFramesToDurationUs( getSubmittedFrames() - trimmingAudioProcessor.getTrimmedFrameCount()); if (startMediaTimeState == START_IN_SYNC && Math.abs(expectedPresentationTimeUs - presentationTimeUs) > 200000) { Log.e(TAG, "Discontinuity detected [expected " + expectedPresentationTimeUs + ", got " + presentationTimeUs + "]"); startMediaTimeState = START_NEED_SYNC; } if (startMediaTimeState == START_NEED_SYNC) { long adjustmentUs = presentationTimeUs - expectedPresentationTimeUs; startMediaTimeUs += adjustmentUs; startMediaTimeState = START_IN_SYNC; if (listener != null && adjustmentUs != 0) { listener.onPositionDiscontinuity(); } } } if (configuration.isInputPcm) { submittedPcmBytes += buffer.remaining(); } else { submittedEncodedFrames += framesPerEncodedSample; } inputBuffer = buffer; } if (configuration.processingEnabled) { processBuffers(presentationTimeUs); } else { writeBuffer(inputBuffer, presentationTimeUs); } if (!inputBuffer.hasRemaining()) { inputBuffer = null; return true; } if (audioTrackPositionTracker.isStalled(getWrittenFrames())) { Log.w(TAG, "Resetting stalled audio track"); flush(); return true; } return false; } DefaultAudioSink(
      @Nullable AudioCapabilities audioCapabilities, AudioProcessor[] audioProcessors);  DefaultAudioSink(
      @Nullable AudioCapabilities audioCapabilities,
      AudioProcessor[] audioProcessors,
      boolean enableConvertHighResIntPcmToFloat);  DefaultAudioSink(
      @Nullable AudioCapabilities audioCapabilities,
      AudioProcessorChain audioProcessorChain,
      boolean enableConvertHighResIntPcmToFloat); }
DefaultAudioSink implements AudioSink { @Override @SuppressWarnings("ReferenceEquality") public boolean handleBuffer(ByteBuffer buffer, long presentationTimeUs) throws InitializationException, WriteException { Assertions.checkArgument(inputBuffer == null || buffer == inputBuffer); if (pendingConfiguration != null) { if (!drainAudioProcessorsToEndOfStream()) { return false; } configuration = pendingConfiguration; pendingConfiguration = null; playbackParameters = configuration.canApplyPlaybackParameters ? audioProcessorChain.applyPlaybackParameters(playbackParameters) : PlaybackParameters.DEFAULT; setupAudioProcessors(); } if (!isInitialized()) { initialize(); if (playing) { play(); } } if (!audioTrackPositionTracker.mayHandleBuffer(getWrittenFrames())) { return false; } if (inputBuffer == null) { if (!buffer.hasRemaining()) { return true; } if (!configuration.isInputPcm && framesPerEncodedSample == 0) { framesPerEncodedSample = getFramesPerEncodedSample(configuration.outputEncoding, buffer); if (framesPerEncodedSample == 0) { return true; } } if (afterDrainPlaybackParameters != null) { if (!drainAudioProcessorsToEndOfStream()) { return false; } PlaybackParameters newPlaybackParameters = afterDrainPlaybackParameters; afterDrainPlaybackParameters = null; newPlaybackParameters = audioProcessorChain.applyPlaybackParameters(newPlaybackParameters); playbackParametersCheckpoints.add( new PlaybackParametersCheckpoint( newPlaybackParameters, Math.max(0, presentationTimeUs), configuration.framesToDurationUs(getWrittenFrames()))); setupAudioProcessors(); } if (startMediaTimeState == START_NOT_SET) { startMediaTimeUs = Math.max(0, presentationTimeUs); startMediaTimeState = START_IN_SYNC; } else { long expectedPresentationTimeUs = startMediaTimeUs + configuration.inputFramesToDurationUs( getSubmittedFrames() - trimmingAudioProcessor.getTrimmedFrameCount()); if (startMediaTimeState == START_IN_SYNC && Math.abs(expectedPresentationTimeUs - presentationTimeUs) > 200000) { Log.e(TAG, "Discontinuity detected [expected " + expectedPresentationTimeUs + ", got " + presentationTimeUs + "]"); startMediaTimeState = START_NEED_SYNC; } if (startMediaTimeState == START_NEED_SYNC) { long adjustmentUs = presentationTimeUs - expectedPresentationTimeUs; startMediaTimeUs += adjustmentUs; startMediaTimeState = START_IN_SYNC; if (listener != null && adjustmentUs != 0) { listener.onPositionDiscontinuity(); } } } if (configuration.isInputPcm) { submittedPcmBytes += buffer.remaining(); } else { submittedEncodedFrames += framesPerEncodedSample; } inputBuffer = buffer; } if (configuration.processingEnabled) { processBuffers(presentationTimeUs); } else { writeBuffer(inputBuffer, presentationTimeUs); } if (!inputBuffer.hasRemaining()) { inputBuffer = null; return true; } if (audioTrackPositionTracker.isStalled(getWrittenFrames())) { Log.w(TAG, "Resetting stalled audio track"); flush(); return true; } return false; } DefaultAudioSink(
      @Nullable AudioCapabilities audioCapabilities, AudioProcessor[] audioProcessors);  DefaultAudioSink(
      @Nullable AudioCapabilities audioCapabilities,
      AudioProcessor[] audioProcessors,
      boolean enableConvertHighResIntPcmToFloat);  DefaultAudioSink(
      @Nullable AudioCapabilities audioCapabilities,
      AudioProcessorChain audioProcessorChain,
      boolean enableConvertHighResIntPcmToFloat); @Override void setListener(Listener listener); @Override boolean supportsOutput(int channelCount, @C.Encoding int encoding); @Override long getCurrentPositionUs(boolean sourceEnded); @Override void configure(
      @C.Encoding int inputEncoding,
      int inputChannelCount,
      int inputSampleRate,
      int specifiedBufferSize,
      @Nullable int[] outputChannels,
      int trimStartFrames,
      int trimEndFrames); @Override void play(); @Override void handleDiscontinuity(); @Override @SuppressWarnings("ReferenceEquality") boolean handleBuffer(ByteBuffer buffer, long presentationTimeUs); @Override void playToEndOfStream(); @Override boolean isEnded(); @Override boolean hasPendingData(); @Override PlaybackParameters setPlaybackParameters(PlaybackParameters playbackParameters); @Override PlaybackParameters getPlaybackParameters(); @Override void setAudioAttributes(AudioAttributes audioAttributes); @Override void setAudioSessionId(int audioSessionId); @Override void setAuxEffectInfo(AuxEffectInfo auxEffectInfo); @Override void enableTunnelingV21(int tunnelingAudioSessionId); @Override void disableTunneling(); @Override void setVolume(float volume); @Override void pause(); @Override void flush(); @Override void reset(); }
DefaultAudioSink implements AudioSink { @Override @SuppressWarnings("ReferenceEquality") public boolean handleBuffer(ByteBuffer buffer, long presentationTimeUs) throws InitializationException, WriteException { Assertions.checkArgument(inputBuffer == null || buffer == inputBuffer); if (pendingConfiguration != null) { if (!drainAudioProcessorsToEndOfStream()) { return false; } configuration = pendingConfiguration; pendingConfiguration = null; playbackParameters = configuration.canApplyPlaybackParameters ? audioProcessorChain.applyPlaybackParameters(playbackParameters) : PlaybackParameters.DEFAULT; setupAudioProcessors(); } if (!isInitialized()) { initialize(); if (playing) { play(); } } if (!audioTrackPositionTracker.mayHandleBuffer(getWrittenFrames())) { return false; } if (inputBuffer == null) { if (!buffer.hasRemaining()) { return true; } if (!configuration.isInputPcm && framesPerEncodedSample == 0) { framesPerEncodedSample = getFramesPerEncodedSample(configuration.outputEncoding, buffer); if (framesPerEncodedSample == 0) { return true; } } if (afterDrainPlaybackParameters != null) { if (!drainAudioProcessorsToEndOfStream()) { return false; } PlaybackParameters newPlaybackParameters = afterDrainPlaybackParameters; afterDrainPlaybackParameters = null; newPlaybackParameters = audioProcessorChain.applyPlaybackParameters(newPlaybackParameters); playbackParametersCheckpoints.add( new PlaybackParametersCheckpoint( newPlaybackParameters, Math.max(0, presentationTimeUs), configuration.framesToDurationUs(getWrittenFrames()))); setupAudioProcessors(); } if (startMediaTimeState == START_NOT_SET) { startMediaTimeUs = Math.max(0, presentationTimeUs); startMediaTimeState = START_IN_SYNC; } else { long expectedPresentationTimeUs = startMediaTimeUs + configuration.inputFramesToDurationUs( getSubmittedFrames() - trimmingAudioProcessor.getTrimmedFrameCount()); if (startMediaTimeState == START_IN_SYNC && Math.abs(expectedPresentationTimeUs - presentationTimeUs) > 200000) { Log.e(TAG, "Discontinuity detected [expected " + expectedPresentationTimeUs + ", got " + presentationTimeUs + "]"); startMediaTimeState = START_NEED_SYNC; } if (startMediaTimeState == START_NEED_SYNC) { long adjustmentUs = presentationTimeUs - expectedPresentationTimeUs; startMediaTimeUs += adjustmentUs; startMediaTimeState = START_IN_SYNC; if (listener != null && adjustmentUs != 0) { listener.onPositionDiscontinuity(); } } } if (configuration.isInputPcm) { submittedPcmBytes += buffer.remaining(); } else { submittedEncodedFrames += framesPerEncodedSample; } inputBuffer = buffer; } if (configuration.processingEnabled) { processBuffers(presentationTimeUs); } else { writeBuffer(inputBuffer, presentationTimeUs); } if (!inputBuffer.hasRemaining()) { inputBuffer = null; return true; } if (audioTrackPositionTracker.isStalled(getWrittenFrames())) { Log.w(TAG, "Resetting stalled audio track"); flush(); return true; } return false; } DefaultAudioSink(
      @Nullable AudioCapabilities audioCapabilities, AudioProcessor[] audioProcessors);  DefaultAudioSink(
      @Nullable AudioCapabilities audioCapabilities,
      AudioProcessor[] audioProcessors,
      boolean enableConvertHighResIntPcmToFloat);  DefaultAudioSink(
      @Nullable AudioCapabilities audioCapabilities,
      AudioProcessorChain audioProcessorChain,
      boolean enableConvertHighResIntPcmToFloat); @Override void setListener(Listener listener); @Override boolean supportsOutput(int channelCount, @C.Encoding int encoding); @Override long getCurrentPositionUs(boolean sourceEnded); @Override void configure(
      @C.Encoding int inputEncoding,
      int inputChannelCount,
      int inputSampleRate,
      int specifiedBufferSize,
      @Nullable int[] outputChannels,
      int trimStartFrames,
      int trimEndFrames); @Override void play(); @Override void handleDiscontinuity(); @Override @SuppressWarnings("ReferenceEquality") boolean handleBuffer(ByteBuffer buffer, long presentationTimeUs); @Override void playToEndOfStream(); @Override boolean isEnded(); @Override boolean hasPendingData(); @Override PlaybackParameters setPlaybackParameters(PlaybackParameters playbackParameters); @Override PlaybackParameters getPlaybackParameters(); @Override void setAudioAttributes(AudioAttributes audioAttributes); @Override void setAudioSessionId(int audioSessionId); @Override void setAuxEffectInfo(AuxEffectInfo auxEffectInfo); @Override void enableTunnelingV21(int tunnelingAudioSessionId); @Override void disableTunneling(); @Override void setVolume(float volume); @Override void pause(); @Override void flush(); @Override void reset(); static boolean enablePreV21AudioSessionWorkaround; static boolean failOnSpuriousAudioTimestamp; }