1 /*
2 * Copyright 2015 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 <sys/types.h>
18 #include <pthread.h>
19 #include <thread>
20
21 #include "oboe/AudioClock.h"
22 #include "oboe/AudioStream.h"
23 #include "oboe/Utilities.h"
24 #include "OboeDebug.h"
25
26 namespace oboe {
27
28 /*
29 * AudioStream
30 */
AudioStream(const AudioStreamBuilder & builder)31 AudioStream::AudioStream(const AudioStreamBuilder &builder)
32 : AudioStreamBase(builder) {
33 LOGD("Constructor for AudioStream at %p", this);
34 }
35
~AudioStream()36 AudioStream::~AudioStream() {
37 // This is to help debug use after free bugs.
38 LOGD("Destructor for AudioStream at %p", this);
39 }
40
close()41 Result AudioStream::close() {
42 closePerformanceHint();
43 // Update local counters so they can be read after the close.
44 updateFramesWritten();
45 updateFramesRead();
46 return Result::OK;
47 }
48
49 // Call this from fireDataCallback() if you want to monitor CPU scheduler.
checkScheduler()50 void AudioStream::checkScheduler() {
51 int scheduler = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK; // for current thread
52 if (scheduler != mPreviousScheduler) {
53 LOGD("AudioStream::%s() scheduler = %s", __func__,
54 ((scheduler == SCHED_FIFO) ? "SCHED_FIFO" :
55 ((scheduler == SCHED_OTHER) ? "SCHED_OTHER" :
56 ((scheduler == SCHED_RR) ? "SCHED_RR" : "UNKNOWN")))
57 );
58 mPreviousScheduler = scheduler;
59 }
60 }
61
fireDataCallback(void * audioData,int32_t numFrames)62 DataCallbackResult AudioStream::fireDataCallback(void *audioData, int32_t numFrames) {
63 if (!isDataCallbackEnabled()) {
64 LOGW("AudioStream::%s() called with data callback disabled!", __func__);
65 return DataCallbackResult::Stop; // Should not be getting called
66 }
67
68 beginPerformanceHintInCallback();
69
70 // Call the app to do the work.
71 DataCallbackResult result;
72 if (mDataCallback) {
73 result = mDataCallback->onAudioReady(this, audioData, numFrames);
74 } else {
75 result = onDefaultCallback(audioData, numFrames);
76 }
77 // On Oreo, we might get called after returning stop.
78 // So block that here.
79 setDataCallbackEnabled(result == DataCallbackResult::Continue);
80
81 endPerformanceHintInCallback(numFrames);
82
83 return result;
84 }
85
waitForStateTransition(StreamState startingState,StreamState endingState,int64_t timeoutNanoseconds)86 Result AudioStream::waitForStateTransition(StreamState startingState,
87 StreamState endingState,
88 int64_t timeoutNanoseconds)
89 {
90 StreamState state;
91 {
92 std::lock_guard<std::mutex> lock(mLock);
93 state = getState();
94 if (state == StreamState::Closed) {
95 return Result::ErrorClosed;
96 } else if (state == StreamState::Disconnected) {
97 return Result::ErrorDisconnected;
98 }
99 }
100
101 StreamState nextState = state;
102 // TODO Should this be a while()?!
103 if (state == startingState && state != endingState) {
104 Result result = waitForStateChange(state, &nextState, timeoutNanoseconds);
105 if (result != Result::OK) {
106 return result;
107 }
108 }
109
110 if (nextState != endingState) {
111 return Result::ErrorInvalidState;
112 } else {
113 return Result::OK;
114 }
115 }
116
start(int64_t timeoutNanoseconds)117 Result AudioStream::start(int64_t timeoutNanoseconds)
118 {
119 Result result = requestStart();
120 if (result != Result::OK) return result;
121 if (timeoutNanoseconds <= 0) return result;
122 result = waitForStateTransition(StreamState::Starting,
123 StreamState::Started, timeoutNanoseconds);
124 if (result != Result::OK) {
125 LOGE("AudioStream::%s() timed out before moving from STARTING to STARTED", __func__);
126 }
127 return result;
128 }
129
pause(int64_t timeoutNanoseconds)130 Result AudioStream::pause(int64_t timeoutNanoseconds)
131 {
132 Result result = requestPause();
133 if (result != Result::OK) return result;
134 if (timeoutNanoseconds <= 0) return result;
135 return waitForStateTransition(StreamState::Pausing,
136 StreamState::Paused, timeoutNanoseconds);
137 }
138
flush(int64_t timeoutNanoseconds)139 Result AudioStream::flush(int64_t timeoutNanoseconds)
140 {
141 Result result = requestFlush();
142 if (result != Result::OK) return result;
143 if (timeoutNanoseconds <= 0) return result;
144 return waitForStateTransition(StreamState::Flushing,
145 StreamState::Flushed, timeoutNanoseconds);
146 }
147
stop(int64_t timeoutNanoseconds)148 Result AudioStream::stop(int64_t timeoutNanoseconds)
149 {
150 Result result = requestStop();
151 if (result != Result::OK) return result;
152 if (timeoutNanoseconds <= 0) return result;
153 return waitForStateTransition(StreamState::Stopping,
154 StreamState::Stopped, timeoutNanoseconds);
155 }
156
getBytesPerSample() const157 int32_t AudioStream::getBytesPerSample() const {
158 return convertFormatToSizeInBytes(mFormat);
159 }
160
getFramesRead()161 int64_t AudioStream::getFramesRead() {
162 updateFramesRead();
163 return mFramesRead;
164 }
165
getFramesWritten()166 int64_t AudioStream::getFramesWritten() {
167 updateFramesWritten();
168 return mFramesWritten;
169 }
170
getAvailableFrames()171 ResultWithValue<int32_t> AudioStream::getAvailableFrames() {
172 int64_t readCounter = getFramesRead();
173 if (readCounter < 0) return ResultWithValue<int32_t>::createBasedOnSign(readCounter);
174 int64_t writeCounter = getFramesWritten();
175 if (writeCounter < 0) return ResultWithValue<int32_t>::createBasedOnSign(writeCounter);
176 int32_t framesAvailable = writeCounter - readCounter;
177 return ResultWithValue<int32_t>(framesAvailable);
178 }
179
waitForAvailableFrames(int32_t numFrames,int64_t timeoutNanoseconds)180 ResultWithValue<int32_t> AudioStream::waitForAvailableFrames(int32_t numFrames,
181 int64_t timeoutNanoseconds) {
182 if (numFrames == 0) return Result::OK;
183 if (numFrames < 0) return Result::ErrorOutOfRange;
184
185 // Make sure we don't try to wait for more frames than the buffer can hold.
186 // Subtract framesPerBurst because this is often called from a callback
187 // and we don't want to be sleeping if the buffer is close to overflowing.
188 const int32_t maxAvailableFrames = getBufferCapacityInFrames() - getFramesPerBurst();
189 numFrames = std::min(numFrames, maxAvailableFrames);
190 // The capacity should never be less than one burst. But clip to zero just in case.
191 numFrames = std::max(0, numFrames);
192
193 int64_t framesAvailable = 0;
194 int64_t burstInNanos = getFramesPerBurst() * kNanosPerSecond / getSampleRate();
195 bool ready = false;
196 int64_t deadline = AudioClock::getNanoseconds() + timeoutNanoseconds;
197 do {
198 ResultWithValue<int32_t> result = getAvailableFrames();
199 if (!result) return result;
200 framesAvailable = result.value();
201 ready = (framesAvailable >= numFrames);
202 if (!ready) {
203 int64_t now = AudioClock::getNanoseconds();
204 if (now > deadline) break;
205 AudioClock::sleepForNanos(burstInNanos);
206 }
207 } while (!ready);
208 return (!ready)
209 ? ResultWithValue<int32_t>(Result::ErrorTimeout)
210 : ResultWithValue<int32_t>(framesAvailable);
211 }
212
getTimestamp(clockid_t clockId)213 ResultWithValue<FrameTimestamp> AudioStream::getTimestamp(clockid_t clockId) {
214 FrameTimestamp frame;
215 Result result = getTimestamp(clockId, &frame.position, &frame.timestamp);
216 if (result == Result::OK){
217 return ResultWithValue<FrameTimestamp>(frame);
218 } else {
219 return ResultWithValue<FrameTimestamp>(static_cast<Result>(result));
220 }
221 }
222
calculateDefaultDelayBeforeCloseMillis()223 void AudioStream::calculateDefaultDelayBeforeCloseMillis() {
224 // Calculate delay time before close based on burst duration.
225 // Start with a burst duration then add 1 msec as a safety margin.
226 mDelayBeforeCloseMillis = std::max(kMinDelayBeforeCloseMillis,
227 1 + ((mFramesPerBurst * 1000) / getSampleRate()));
228 LOGD("calculateDefaultDelayBeforeCloseMillis() default = %d",
229 static_cast<int>(mDelayBeforeCloseMillis));
230 }
231
232 } // namespace oboe
233