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