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 #include <memory>
18
19 #include "FilterAudioStream.h"
20
21 using namespace oboe;
22 using namespace flowgraph;
23
24 // Output callback uses FixedBlockReader::read()
25 // <= SourceFloatCaller::onProcess()
26 // <=== DataConversionFlowGraph::read()
27 // <== FilterAudioStream::onAudioReady()
28 //
29 // Output blocking uses no block adapter because AAudio can accept
30 // writes of any size. It uses DataConversionFlowGraph::read() <== FilterAudioStream::write() <= app
31 //
32 // Input callback uses FixedBlockWriter::write()
33 // <= DataConversionFlowGraph::write()
34 // <= FilterAudioStream::onAudioReady()
35 //
36 // Input blocking uses FixedBlockReader::read() // TODO may not need block adapter
37 // <= SourceFloatCaller::onProcess()
38 // <=== SinkFloat::read()
39 // <= DataConversionFlowGraph::read()
40 // <== FilterAudioStream::read()
41 // <= app
42
configureFlowGraph()43 Result FilterAudioStream::configureFlowGraph() {
44 mFlowGraph = std::make_unique<DataConversionFlowGraph>();
45 bool isOutput = getDirection() == Direction::Output;
46
47 AudioStream *sourceStream = isOutput ? this : mChildStream.get();
48 AudioStream *sinkStream = isOutput ? mChildStream.get() : this;
49
50 mRateScaler = ((double) sourceStream->getSampleRate()) / sinkStream->getSampleRate();
51
52 return mFlowGraph->configure(sourceStream, sinkStream);
53 }
54
55 // Put the data to be written at the source end of the flowgraph.
56 // Then read (pull) the data from the flowgraph and write it to the
57 // child stream.
write(const void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)58 ResultWithValue<int32_t> FilterAudioStream::write(const void *buffer,
59 int32_t numFrames,
60 int64_t timeoutNanoseconds) {
61 int32_t framesWritten = 0;
62 mFlowGraph->setSource(buffer, numFrames);
63 while (true) {
64 int32_t numRead = mFlowGraph->read(mBlockingBuffer.get(),
65 getFramesPerBurst(),
66 timeoutNanoseconds);
67 if (numRead < 0) {
68 return ResultWithValue<int32_t>::createBasedOnSign(numRead);
69 }
70 if (numRead == 0) {
71 break; // finished processing the source buffer
72 }
73 auto writeResult = mChildStream->write(mBlockingBuffer.get(),
74 numRead,
75 timeoutNanoseconds);
76 if (!writeResult) {
77 return writeResult;
78 }
79 framesWritten += writeResult.value();
80 }
81 return ResultWithValue<int32_t>::createBasedOnSign(framesWritten);
82 }
83
84 // Read (pull) the data we want from the sink end of the flowgraph.
85 // The necessary data will be read from the child stream using a flowgraph callback.
read(void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)86 ResultWithValue<int32_t> FilterAudioStream::read(void *buffer,
87 int32_t numFrames,
88 int64_t timeoutNanoseconds) {
89 int32_t framesRead = mFlowGraph->read(buffer, numFrames, timeoutNanoseconds);
90 return ResultWithValue<int32_t>::createBasedOnSign(framesRead);
91 }
92
93