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
17 #include "DuplexEngine.h"
18 #include "effects/Effects.h"
19
DuplexEngine()20 DuplexEngine::DuplexEngine() {
21 beginStreams();
22 }
23
beginStreams()24 void DuplexEngine::beginStreams() {
25 // This ordering is extremely important
26 openInStream();
27 if (inStream->getFormat() == oboe::AudioFormat::Float) {
28 functionList.emplace<FunctionList<float *>>();
29 createCallback<float_t>();
30 } else if (inStream->getFormat() == oboe::AudioFormat::I16) {
31 createCallback<int16_t>();
32 } else {
33 stopStreams();
34 }
35 SAMPLE_RATE = inStream->getSampleRate();
36 openOutStream();
37
38 oboe::Result result = startStreams();
39 if (result != oboe::Result::OK) stopStreams();
40 }
41
42 template<class numeric>
createCallback()43 void DuplexEngine::createCallback() {
44 mCallback = std::make_unique<DuplexCallback<numeric>>(
45 *inStream, [&functionStack = this->functionList](numeric *beg, numeric *end) {
46 std::get<FunctionList<numeric *>>(functionStack)(beg, end);
47 },
48 inStream->getBufferCapacityInFrames(),
49 std::bind(&DuplexEngine::beginStreams, this));
50 }
51
52
defaultBuilder()53 oboe::AudioStreamBuilder DuplexEngine::defaultBuilder() {
54 return *oboe::AudioStreamBuilder()
55 .setPerformanceMode(oboe::PerformanceMode::LowLatency)
56 ->setSharingMode(oboe::SharingMode::Exclusive);
57 }
58
openInStream()59 void DuplexEngine::openInStream() {
60 defaultBuilder().setDirection(oboe::Direction::Input)
61 ->setFormat(oboe::AudioFormat::Float) // For now
62 ->setChannelCount(1) // Mono in for effects processing
63 ->openManagedStream(inStream);
64 }
65
openOutStream()66 void DuplexEngine::openOutStream() {
67 defaultBuilder().setCallback(mCallback.get())
68 ->setSampleRate(inStream->getSampleRate())
69 ->setFormat(inStream->getFormat())
70 ->setChannelCount(2) // Stereo out
71 ->openManagedStream(outStream);
72 }
73
startStreams()74 oboe::Result DuplexEngine::startStreams() {
75 oboe::Result result = outStream->requestStart();
76 int64_t timeoutNanos = 500 * 1000000; // arbitrary 1/2 second
77 auto currentState = outStream->getState();
78 auto nextState = oboe::StreamState::Unknown;
79 while (result == oboe::Result::OK && currentState != oboe::StreamState::Started) {
80 result = outStream->waitForStateChange(currentState, &nextState, timeoutNanos);
81 currentState = nextState;
82 }
83 if (result != oboe::Result::OK) return result;
84 return inStream->requestStart();
85 }
86
stopStreams()87 oboe::Result DuplexEngine::stopStreams() {
88 oboe::Result outputResult = inStream->requestStop();
89 oboe::Result inputResult = outStream->requestStop();
90 if (outputResult != oboe::Result::OK) return outputResult;
91 return inputResult;
92 }
93
94