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