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