• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     }
60 
61     virtual ~FilterAudioStream() = default;
62 
getChildStream()63     AudioStream *getChildStream() const {
64         return mChildStream.get();
65     }
66 
67     Result configureFlowGraph();
68 
69     // Close child and parent.
close()70     Result close()  override {
71         const Result result1 = mChildStream->close();
72         const Result result2 = AudioStream::close();
73         return (result1 != Result::OK ? result1 : result2);
74     }
75 
76     /**
77      * Start the stream asynchronously. Returns immediately (does not block). Equivalent to calling
78      * `start(0)`.
79      */
requestStart()80     Result requestStart() override {
81         return mChildStream->requestStart();
82     }
83 
84     /**
85      * Pause the stream asynchronously. Returns immediately (does not block). Equivalent to calling
86      * `pause(0)`.
87      */
requestPause()88     Result requestPause() override {
89         return mChildStream->requestPause();
90     }
91 
92     /**
93      * Flush the stream asynchronously. Returns immediately (does not block). Equivalent to calling
94      * `flush(0)`.
95      */
requestFlush()96     Result requestFlush() override {
97         return mChildStream->requestFlush();
98     }
99 
100     /**
101      * Stop the stream asynchronously. Returns immediately (does not block). Equivalent to calling
102      * `stop(0)`.
103      */
requestStop()104     Result requestStop() override {
105         return mChildStream->requestStop();
106     }
107 
108     ResultWithValue<int32_t> read(void *buffer,
109             int32_t numFrames,
110             int64_t timeoutNanoseconds) override;
111 
112     ResultWithValue<int32_t> write(const void *buffer,
113             int32_t numFrames,
114             int64_t timeoutNanoseconds) override;
115 
getState()116     StreamState getState() const override {
117         return mChildStream->getState();
118     }
119 
waitForStateChange(StreamState inputState,StreamState * nextState,int64_t timeoutNanoseconds)120     Result waitForStateChange(
121             StreamState inputState,
122             StreamState *nextState,
123             int64_t timeoutNanoseconds) override {
124         return mChildStream->waitForStateChange(inputState, nextState, timeoutNanoseconds);
125     }
126 
isXRunCountSupported()127     bool isXRunCountSupported() const override {
128         return mChildStream->isXRunCountSupported();
129     }
130 
getFramesPerBurst()131     int32_t getFramesPerBurst() override {
132         return mChildStream->getFramesPerBurst();
133     }
134 
getAudioApi()135     AudioApi getAudioApi() const override {
136         return mChildStream->getAudioApi();
137     }
138 
updateFramesWritten()139     void updateFramesWritten() override {
140         // TODO for output, just count local writes?
141         mFramesWritten = static_cast<int64_t>(mChildStream->getFramesWritten() * mRateScaler);
142     }
143 
updateFramesRead()144     void updateFramesRead() override {
145         // TODO for input, just count local reads?
146         mFramesRead = static_cast<int64_t>(mChildStream->getFramesRead() * mRateScaler);
147     }
148 
getUnderlyingStream()149     void *getUnderlyingStream() const  override {
150         return mChildStream->getUnderlyingStream();
151     }
152 
setBufferSizeInFrames(int32_t requestedFrames)153     ResultWithValue<int32_t> setBufferSizeInFrames(int32_t requestedFrames) override {
154         return mChildStream->setBufferSizeInFrames(requestedFrames);
155     }
156 
getBufferSizeInFrames()157     int32_t getBufferSizeInFrames() override {
158         mBufferSizeInFrames = mChildStream->getBufferSizeInFrames();
159         return mBufferSizeInFrames;
160     }
161 
getXRunCount()162     ResultWithValue<int32_t> getXRunCount() const override {
163         return mChildStream->getXRunCount();
164     }
165 
calculateLatencyMillis()166     ResultWithValue<double> calculateLatencyMillis() override {
167         // This will automatically include the latency of the flowgraph?
168         return mChildStream->calculateLatencyMillis();
169     }
170 
getTimestamp(clockid_t clockId,int64_t * framePosition,int64_t * timeNanoseconds)171     Result getTimestamp(clockid_t clockId,
172             int64_t *framePosition,
173             int64_t *timeNanoseconds) override {
174         int64_t childPosition = 0;
175         Result result = mChildStream->getTimestamp(clockId, &childPosition, timeNanoseconds);
176         // It is OK if framePosition is null.
177         if (framePosition) {
178             *framePosition = childPosition * mRateScaler;
179         }
180         return result;
181     }
182 
183     DataCallbackResult onAudioReady(AudioStream *oboeStream,
184             void *audioData,
185             int32_t numFrames) override;
186 
onError(AudioStream * audioStream,Result error)187     bool onError(AudioStream * audioStream, Result error) override {
188         if (mErrorCallback != nullptr) {
189             return mErrorCallback->onError(this, error);
190         }
191         return false;
192     }
193 
onErrorBeforeClose(AudioStream * oboeStream,Result error)194     void onErrorBeforeClose(AudioStream *oboeStream, Result error) override {
195         if (mErrorCallback != nullptr) {
196             mErrorCallback->onErrorBeforeClose(this, error);
197         }
198     }
199 
onErrorAfterClose(AudioStream * oboeStream,Result error)200     void onErrorAfterClose(AudioStream *oboeStream, Result error) override {
201         // Close this parent stream because the callback will only close the child.
202         AudioStream::close();
203         if (mErrorCallback != nullptr) {
204             mErrorCallback->onErrorAfterClose(this, error);
205         }
206     }
207 
208     /**
209      * @return last result passed from an error callback
210      */
getLastErrorCallbackResult()211     oboe::Result getLastErrorCallbackResult() const override {
212         return mChildStream->getLastErrorCallbackResult();
213     }
214 
215 private:
216 
217     std::unique_ptr<AudioStream>             mChildStream; // this stream wraps the child stream
218     std::unique_ptr<DataConversionFlowGraph> mFlowGraph; // for converting data
219     std::unique_ptr<uint8_t[]>               mBlockingBuffer; // temp buffer for write()
220     double                                   mRateScaler = 1.0; // ratio parent/child sample rates
221 };
222 
223 } // oboe
224 
225 #endif //OBOE_FILTER_AUDIO_STREAM_H
226