1 /*
2  * Copyright 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 
17 #ifndef OBOE_FILTER_AUDIO_STREAM_H
18 #define OBOE_FILTER_AUDIO_STREAM_H
19 
20 #include <memory>
21 #include <oboe/AudioStream.h>
22 #include "DataConversionFlowGraph.h"
23 
24 namespace oboe {
25 
26 /**
27  * An AudioStream that wraps another AudioStream and provides audio data conversion.
28  * Operations may include channel conversion, data format conversion and/or sample rate conversion.
29  */
30 class FilterAudioStream : public AudioStream, AudioStreamCallback {
31 public:
32 
33     /**
34      * Construct an `AudioStream` using the given `AudioStreamBuilder` and a child AudioStream.
35      *
36      * This should only be called internally by AudioStreamBuilder.
37      * Ownership of childStream will be passed to this object.
38      *
39      * @param builder containing all the stream's attributes
40      */
FilterAudioStream(const AudioStreamBuilder & builder,AudioStream * childStream)41     FilterAudioStream(const AudioStreamBuilder &builder, AudioStream *childStream)
42     : AudioStream(builder)
43     , mChildStream(childStream) {
44         // Intercept the callback if used.
45         if (builder.isErrorCallbackSpecified()) {
46             mErrorCallback = mChildStream->swapErrorCallback(this);
47         }
48         if (builder.isDataCallbackSpecified()) {
49             mDataCallback = mChildStream->swapDataCallback(this);
50         } else {
51             const int size = childStream->getFramesPerBurst() * childStream->getBytesPerFrame();
52             mBlockingBuffer = std::make_unique<uint8_t[]>(size);
53         }
54 
55         // Copy parameters that may not match builder.
56         mBufferCapacityInFrames = mChildStream->getBufferCapacityInFrames();
57         mPerformanceMode = mChildStream->getPerformanceMode();
58         mInputPreset = mChildStream->getInputPreset();
59         mFramesPerBurst = mChildStream->getFramesPerBurst();
60         mDeviceId = mChildStream->getDeviceId();
61     }
62 
63     virtual ~FilterAudioStream() = default;
64 
getChildStream()65     AudioStream *getChildStream() const {
66         return mChildStream.get();
67     }
68 
69     Result configureFlowGraph();
70 
71     // Close child and parent.
close()72     Result close()  override {
73         const Result result1 = mChildStream->close();
74         const Result result2 = AudioStream::close();
75         return (result1 != Result::OK ? result1 : result2);
76     }
77 
78     /**
79      * Start the stream asynchronously. Returns immediately (does not block). Equivalent to calling
80      * `start(0)`.
81      */
requestStart()82     Result requestStart() override {
83         return mChildStream->requestStart();
84     }
85 
86     /**
87      * Pause the stream asynchronously. Returns immediately (does not block). Equivalent to calling
88      * `pause(0)`.
89      */
requestPause()90     Result requestPause() override {
91         return mChildStream->requestPause();
92     }
93 
94     /**
95      * Flush the stream asynchronously. Returns immediately (does not block). Equivalent to calling
96      * `flush(0)`.
97      */
requestFlush()98     Result requestFlush() override {
99         return mChildStream->requestFlush();
100     }
101 
102     /**
103      * Stop the stream asynchronously. Returns immediately (does not block). Equivalent to calling
104      * `stop(0)`.
105      */
requestStop()106     Result requestStop() override {
107         return mChildStream->requestStop();
108     }
109 
110     ResultWithValue<int32_t> read(void *buffer,
111             int32_t numFrames,
112             int64_t timeoutNanoseconds) override;
113 
114     ResultWithValue<int32_t> write(const void *buffer,
115             int32_t numFrames,
116             int64_t timeoutNanoseconds) override;
117 
getState()118     StreamState getState() override {
119         return mChildStream->getState();
120     }
121 
waitForStateChange(StreamState inputState,StreamState * nextState,int64_t timeoutNanoseconds)122     Result waitForStateChange(
123             StreamState inputState,
124             StreamState *nextState,
125             int64_t timeoutNanoseconds) override {
126         return mChildStream->waitForStateChange(inputState, nextState, timeoutNanoseconds);
127     }
128 
isXRunCountSupported()129     bool isXRunCountSupported() const override {
130         return mChildStream->isXRunCountSupported();
131     }
132 
getAudioApi()133     AudioApi getAudioApi() const override {
134         return mChildStream->getAudioApi();
135     }
136 
updateFramesWritten()137     void updateFramesWritten() override {
138         // TODO for output, just count local writes?
139         mFramesWritten = static_cast<int64_t>(mChildStream->getFramesWritten() * mRateScaler);
140     }
141 
updateFramesRead()142     void updateFramesRead() override {
143         // TODO for input, just count local reads?
144         mFramesRead = static_cast<int64_t>(mChildStream->getFramesRead() * mRateScaler);
145     }
146 
getUnderlyingStream()147     void *getUnderlyingStream() const  override {
148         return mChildStream->getUnderlyingStream();
149     }
150 
setBufferSizeInFrames(int32_t requestedFrames)151     ResultWithValue<int32_t> setBufferSizeInFrames(int32_t requestedFrames) override {
152         return mChildStream->setBufferSizeInFrames(requestedFrames);
153     }
154 
getBufferSizeInFrames()155     int32_t getBufferSizeInFrames() override {
156         mBufferSizeInFrames = mChildStream->getBufferSizeInFrames();
157         return mBufferSizeInFrames;
158     }
159 
getXRunCount()160     ResultWithValue<int32_t> getXRunCount() override {
161         return mChildStream->getXRunCount();
162     }
163 
calculateLatencyMillis()164     ResultWithValue<double> calculateLatencyMillis() override {
165         // This will automatically include the latency of the flowgraph?
166         return mChildStream->calculateLatencyMillis();
167     }
168 
getTimestamp(clockid_t clockId,int64_t * framePosition,int64_t * timeNanoseconds)169     Result getTimestamp(clockid_t clockId,
170             int64_t *framePosition,
171             int64_t *timeNanoseconds) override {
172         int64_t childPosition = 0;
173         Result result = mChildStream->getTimestamp(clockId, &childPosition, timeNanoseconds);
174         // It is OK if framePosition is null.
175         if (framePosition) {
176             *framePosition = childPosition * mRateScaler;
177         }
178         return result;
179     }
180 
181     DataCallbackResult onAudioReady(AudioStream *oboeStream,
182             void *audioData,
183             int32_t numFrames) override;
184 
onError(AudioStream *,Result error)185     bool onError(AudioStream * /*audioStream*/, Result error) override {
186         if (mErrorCallback != nullptr) {
187             return mErrorCallback->onError(this, error);
188         }
189         return false;
190     }
191 
onErrorBeforeClose(AudioStream *,Result error)192     void onErrorBeforeClose(AudioStream * /*oboeStream*/, Result error) override {
193         if (mErrorCallback != nullptr) {
194             mErrorCallback->onErrorBeforeClose(this, error);
195         }
196     }
197 
onErrorAfterClose(AudioStream *,Result error)198     void onErrorAfterClose(AudioStream * /*oboeStream*/, Result error) override {
199         // Close this parent stream because the callback will only close the child.
200         AudioStream::close();
201         if (mErrorCallback != nullptr) {
202             mErrorCallback->onErrorAfterClose(this, error);
203         }
204     }
205 
206     /**
207      * @return last result passed from an error callback
208      */
getLastErrorCallbackResult()209     oboe::Result getLastErrorCallbackResult() const override {
210         return mChildStream->getLastErrorCallbackResult();
211     }
212 
213 private:
214 
215     std::unique_ptr<AudioStream>             mChildStream; // this stream wraps the child stream
216     std::unique_ptr<DataConversionFlowGraph> mFlowGraph; // for converting data
217     std::unique_ptr<uint8_t[]>               mBlockingBuffer; // temp buffer for write()
218     double                                   mRateScaler = 1.0; // ratio parent/child sample rates
219 };
220 
221 } // oboe
222 
223 #endif //OBOE_FILTER_AUDIO_STREAM_H
224