1 /* 2 * Copyright (C) 2019 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 androidx.annotation.CallSuper; 19 import java.nio.ByteBuffer; 20 import java.nio.ByteOrder; 21 22 /** 23 * Base class for audio processors that keep an output buffer and an internal buffer that is reused 24 * whenever input is queued. Subclasses should override {@link #onConfigure(AudioFormat)} to return 25 * the output audio format for the processor if it's active. 26 */ 27 public abstract class BaseAudioProcessor implements AudioProcessor { 28 29 /** The current input audio format. */ 30 protected AudioFormat inputAudioFormat; 31 /** The current output audio format. */ 32 protected AudioFormat outputAudioFormat; 33 34 private AudioFormat pendingInputAudioFormat; 35 private AudioFormat pendingOutputAudioFormat; 36 private ByteBuffer buffer; 37 private ByteBuffer outputBuffer; 38 private boolean inputEnded; 39 BaseAudioProcessor()40 public BaseAudioProcessor() { 41 buffer = EMPTY_BUFFER; 42 outputBuffer = EMPTY_BUFFER; 43 pendingInputAudioFormat = AudioFormat.NOT_SET; 44 pendingOutputAudioFormat = AudioFormat.NOT_SET; 45 inputAudioFormat = AudioFormat.NOT_SET; 46 outputAudioFormat = AudioFormat.NOT_SET; 47 } 48 49 @Override configure(AudioFormat inputAudioFormat)50 public final AudioFormat configure(AudioFormat inputAudioFormat) 51 throws UnhandledAudioFormatException { 52 pendingInputAudioFormat = inputAudioFormat; 53 pendingOutputAudioFormat = onConfigure(inputAudioFormat); 54 return isActive() ? pendingOutputAudioFormat : AudioFormat.NOT_SET; 55 } 56 57 @Override isActive()58 public boolean isActive() { 59 return pendingOutputAudioFormat != AudioFormat.NOT_SET; 60 } 61 62 @Override queueEndOfStream()63 public final void queueEndOfStream() { 64 inputEnded = true; 65 onQueueEndOfStream(); 66 } 67 68 @CallSuper 69 @Override getOutput()70 public ByteBuffer getOutput() { 71 ByteBuffer outputBuffer = this.outputBuffer; 72 this.outputBuffer = EMPTY_BUFFER; 73 return outputBuffer; 74 } 75 76 @CallSuper 77 @SuppressWarnings("ReferenceEquality") 78 @Override isEnded()79 public boolean isEnded() { 80 return inputEnded && outputBuffer == EMPTY_BUFFER; 81 } 82 83 @Override flush()84 public final void flush() { 85 outputBuffer = EMPTY_BUFFER; 86 inputEnded = false; 87 inputAudioFormat = pendingInputAudioFormat; 88 outputAudioFormat = pendingOutputAudioFormat; 89 onFlush(); 90 } 91 92 @Override reset()93 public final void reset() { 94 flush(); 95 buffer = EMPTY_BUFFER; 96 pendingInputAudioFormat = AudioFormat.NOT_SET; 97 pendingOutputAudioFormat = AudioFormat.NOT_SET; 98 inputAudioFormat = AudioFormat.NOT_SET; 99 outputAudioFormat = AudioFormat.NOT_SET; 100 onReset(); 101 } 102 103 /** 104 * Replaces the current output buffer with a buffer of at least {@code count} bytes and returns 105 * it. Callers should write to the returned buffer then {@link ByteBuffer#flip()} it so it can be 106 * read via {@link #getOutput()}. 107 */ replaceOutputBuffer(int count)108 protected final ByteBuffer replaceOutputBuffer(int count) { 109 if (buffer.capacity() < count) { 110 buffer = ByteBuffer.allocateDirect(count).order(ByteOrder.nativeOrder()); 111 } else { 112 buffer.clear(); 113 } 114 outputBuffer = buffer; 115 return buffer; 116 } 117 118 /** Returns whether the current output buffer has any data remaining. */ hasPendingOutput()119 protected final boolean hasPendingOutput() { 120 return outputBuffer.hasRemaining(); 121 } 122 123 /** Called when the processor is configured for a new input format. */ onConfigure(AudioFormat inputAudioFormat)124 protected AudioFormat onConfigure(AudioFormat inputAudioFormat) 125 throws UnhandledAudioFormatException { 126 return AudioFormat.NOT_SET; 127 } 128 129 /** Called when the end-of-stream is queued to the processor. */ onQueueEndOfStream()130 protected void onQueueEndOfStream() { 131 // Do nothing. 132 } 133 134 /** Called when the processor is flushed, directly or as part of resetting. */ onFlush()135 protected void onFlush() { 136 // Do nothing. 137 } 138 139 /** Called when the processor is reset. */ onReset()140 protected void onReset() { 141 // Do nothing. 142 } 143 } 144