• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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