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