xref: /aosp_15_r20/external/oboe/src/common/AudioStream.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
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