xref: /aosp_15_r20/external/oboe/samples/MegaDrone/src/main/cpp/MegaDroneEngine.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1 /*
2  * Copyright 2018 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 
18 #include <memory>
19 #include "MegaDroneEngine.h"
20 
21 /**
22  * Main audio engine for the MegaDrone sample. It is responsible for:
23  *
24  * - Creating the callback object which will be supplied when constructing the audio stream
25  * - Setting the CPU core IDs to which the callback thread should bind to
26  * - Creating the playback stream, including setting the callback object
27  * - Creating `Synth` which will render the audio inside the callback
28  * - Starting the playback stream
29  * - Restarting the playback stream when `restart()` is called by the callback object
30  *
31  * @param cpuIds
32  */
MegaDroneEngine(std::vector<int> cpuIds)33 MegaDroneEngine::MegaDroneEngine(std::vector<int> cpuIds) {
34     createCallback(cpuIds);
35 }
36 
~MegaDroneEngine()37 MegaDroneEngine::~MegaDroneEngine() {
38     if (mStream) {
39         LOGE("MegaDroneEngine destructor was called without calling stop()."
40              "Please call stop() to ensure stream resources are not leaked.");
41         stop();
42     }
43 }
44 
tap(bool isDown)45 void MegaDroneEngine::tap(bool isDown) {
46     mAudioSource->tap(isDown);
47 }
48 
restart()49 void MegaDroneEngine::restart() {
50     stop();
51     start();
52 }
53 // Create the playback stream
createPlaybackStream()54 oboe::Result MegaDroneEngine::createPlaybackStream() {
55     oboe::AudioStreamBuilder builder;
56     return builder.setSharingMode(oboe::SharingMode::Exclusive)
57             ->setPerformanceMode(oboe::PerformanceMode::LowLatency)
58             ->setFormat(oboe::AudioFormat::Float)
59             ->setDataCallback(mDataCallback)
60             ->setErrorCallback(mErrorCallback)
61             ->openStream(mStream);
62 }
63 
64 // Create the callback and set its thread affinity to the supplied CPU core IDs
createCallback(std::vector<int> cpuIds)65 void MegaDroneEngine::createCallback(std::vector<int> cpuIds){
66 
67     mDataCallback = std::make_shared<DefaultDataCallback>();
68 
69     // Create the error callback, we supply ourselves as the parent so that we can restart the stream
70     // when it's disconnected
71     mErrorCallback = std::make_shared<DefaultErrorCallback>(*this);
72 
73     // Bind the audio callback to specific CPU cores as this can help avoid underruns caused by
74     // core migrations
75     mDataCallback->setCpuIds(cpuIds);
76     mDataCallback->setThreadAffinityEnabled(true);
77 }
78 
start()79 bool MegaDroneEngine::start() {
80     // It is possible for a stream's device to become disconnected during stream open or between
81     // stream open and stream start.
82     // If the stream fails to start, close the old stream and try again.
83     bool didStart = false;
84     int tryCount = 0;
85     do {
86         if (tryCount > 0) {
87             usleep(20 * 1000); // Sleep between tries to give the system time to settle.
88         }
89         didStart = attemptStart();
90     } while (!didStart && tryCount++ < 3);
91     if (!didStart) {
92         LOGE("Failed at starting the stream");
93     }
94     return didStart;
95 }
96 
attemptStart()97 bool MegaDroneEngine::attemptStart() {
98     auto result = createPlaybackStream();
99 
100     if (result == Result::OK) {
101         // Create our synthesizer audio source using the properties of the stream
102         mAudioSource = std::make_shared<Synth>(mStream->getSampleRate(), mStream->getChannelCount());
103         mDataCallback->reset();
104         mDataCallback->setSource(std::dynamic_pointer_cast<IRenderableAudio>(mAudioSource));
105         result = mStream->start();
106         if (result == Result::OK) {
107             return true;
108         } else {
109             LOGW("Failed attempt at starting the playback stream. Error: %s", convertToText(result));
110             return false;
111         }
112     } else {
113         LOGW("Failed attempt at creating the playback stream. Error: %s", convertToText(result));
114         return false;
115     }
116 }
117 
stop()118 bool MegaDroneEngine::stop() {
119     if(mStream && mStream->getState() != oboe::StreamState::Closed) {
120         mStream->stop();
121         mStream->close();
122     }
123     mStream.reset();
124     return true;
125 }
126 
127