• 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; // We should not be getting called any more.
59     }
60 
61     DataCallbackResult result;
62     if (mStreamCallback == nullptr) {
63         result = onDefaultCallback(audioData, numFrames);
64     } else {
65         result = mStreamCallback->onAudioReady(this, 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     int64_t framesAvailable = 0;
170     int64_t burstInNanos = getFramesPerBurst() * kNanosPerSecond / getSampleRate();
171     bool ready = false;
172     int64_t deadline = AudioClock::getNanoseconds() + timeoutNanoseconds;
173     do {
174         ResultWithValue<int32_t> result = getAvailableFrames();
175         if (!result) return result;
176         framesAvailable = result.value();
177         ready = (framesAvailable >= numFrames);
178         if (!ready) {
179             int64_t now = AudioClock::getNanoseconds();
180             if (now > deadline) break;
181             AudioClock::sleepForNanos(burstInNanos);
182         }
183     } while (!ready);
184     return (!ready)
185             ? ResultWithValue<int32_t>(Result::ErrorTimeout)
186             : ResultWithValue<int32_t>(framesAvailable);
187 }
188 
getTimestamp(clockid_t clockId)189 ResultWithValue<FrameTimestamp> AudioStream::getTimestamp(clockid_t clockId) {
190     FrameTimestamp frame;
191     Result result = getTimestamp(clockId, &frame.position, &frame.timestamp);
192     if (result == Result::OK){
193         return ResultWithValue<FrameTimestamp>(frame);
194     } else {
195         return ResultWithValue<FrameTimestamp>(static_cast<Result>(result));
196     }
197 }
198 
oboe_stop_thread_proc(AudioStream * oboeStream)199 static void oboe_stop_thread_proc(AudioStream *oboeStream) {
200     if (oboeStream != nullptr) {
201         oboeStream->requestStop();
202     }
203 }
204 
launchStopThread()205 void AudioStream::launchStopThread() {
206     // Stop this stream on a separate thread
207     std::thread t(oboe_stop_thread_proc, this);
208     t.detach();
209 }
210 
211 } // namespace oboe
212