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 org.mozilla.thirdparty.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