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