1 /* 2 * Copyright 2019 Google LLC 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 * https://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 #ifndef ANDROID_FXLAB_DUPLEXCALLBACK_H 17 #define ANDROID_FXLAB_DUPLEXCALLBACK_H 18 19 #include <oboe/Oboe.h> 20 21 22 23 // This callback handles mono in, stereo out synchronized audio passthrough. 24 // It takes a function which operates on two pointers (beginning and end) 25 // of underlying data. 26 27 template<class numeric_type> 28 class DuplexCallback : public oboe::AudioStreamCallback { 29 public: 30 DuplexCallback(oboe::AudioStream & inStream,std::function<void (numeric_type *,numeric_type *)> fun,size_t buffer_size,std::function<void (void)> restartFunction)31 DuplexCallback(oboe::AudioStream &inStream, 32 std::function<void(numeric_type *, numeric_type *)> fun, 33 size_t buffer_size, std::function<void(void)> restartFunction) : 34 kBufferSize(buffer_size), inRef(inStream), f(fun), restart(restartFunction) {} 35 36 37 oboe::DataCallbackResult onAudioReady(oboe::AudioStream * outputStream,void * audioData,int32_t numFrames)38 onAudioReady(oboe::AudioStream *outputStream, void *audioData, int32_t numFrames) override { 39 auto *outputData = static_cast<numeric_type *>(audioData); 40 auto outputChannelCount = outputStream->getChannelCount(); 41 42 // Silence first to simplify glitch detection 43 std::fill(outputData, outputData + numFrames * outputChannelCount, 0); 44 oboe::ResultWithValue<int32_t> result = inRef.read(inputBuffer.get(), numFrames, 0); 45 int32_t framesRead = result.value(); 46 if (!result) { 47 inRef.requestStop(); 48 return oboe::DataCallbackResult::Stop; 49 } 50 if (mSpinUpCallbacks > 0 && framesRead > 0) { 51 mSpinUpCallbacks--; 52 return oboe::DataCallbackResult::Continue; 53 } 54 f(inputBuffer.get(), inputBuffer.get() + framesRead); 55 for (int i = 0; i < framesRead; i++) { 56 for (size_t j = 0; j < outputChannelCount; j++) { 57 *outputData++ = inputBuffer[i]; 58 } 59 } 60 return oboe::DataCallbackResult::Continue; 61 } 62 onErrorAfterClose(oboe::AudioStream *,oboe::Result result)63 void onErrorAfterClose(oboe::AudioStream *, oboe::Result result) override { 64 inRef.close(); 65 if (result == oboe::Result::ErrorDisconnected) { 66 restart(); 67 } 68 } 69 70 71 private: 72 int mSpinUpCallbacks = 10; // We will let the streams sync for the first few valid frames 73 const size_t kBufferSize; 74 oboe::AudioStream &inRef; 75 std::function<void(numeric_type *, numeric_type *)> f; 76 std::function<void(void)> restart; 77 std::unique_ptr<numeric_type[]> inputBuffer = std::make_unique<numeric_type[]>(kBufferSize); 78 }; 79 80 #endif //ANDROID_FXLAB_DUPLEXCALLBACK_H 81