1 /* 2 * Copyright 2016 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 #ifndef OBOE_STREAM_H_ 18 #define OBOE_STREAM_H_ 19 20 #include <atomic> 21 #include <cstdint> 22 #include <ctime> 23 #include <mutex> 24 #include "oboe/Definitions.h" 25 #include "oboe/ResultWithValue.h" 26 #include "oboe/AudioStreamBuilder.h" 27 #include "oboe/AudioStreamBase.h" 28 29 /** WARNING - UNDER CONSTRUCTION - THIS API WILL CHANGE. */ 30 31 namespace oboe { 32 33 /** 34 * The default number of nanoseconds to wait for when performing state change operations on the 35 * stream, such as `start` and `stop`. 36 * 37 * @see oboe::AudioStream::start 38 */ 39 constexpr int64_t kDefaultTimeoutNanos = (2000 * kNanosPerMillisecond); 40 41 /** 42 * Base class for Oboe C++ audio stream. 43 */ 44 class AudioStream : public AudioStreamBase { 45 friend class AudioStreamBuilder; // allow access to setWeakThis() and lockWeakThis() 46 public: 47 AudioStream()48 AudioStream() {} 49 50 /** 51 * Construct an `AudioStream` using the given `AudioStreamBuilder` 52 * 53 * @param builder containing all the stream's attributes 54 */ 55 explicit AudioStream(const AudioStreamBuilder &builder); 56 57 virtual ~AudioStream() = default; 58 59 /** 60 * Open a stream based on the current settings. 61 * 62 * Note that we do not recommend re-opening a stream that has been closed. 63 * TODO Should we prevent re-opening? 64 * 65 * @return 66 */ open()67 virtual Result open() { 68 return Result::OK; // Called by subclasses. Might do more in the future. 69 } 70 71 /** 72 * Free the audio resources associated with a stream created by AAudioStreamBuilder_openStream(). 73 * 74 * AAudioStream_close() should be called at some point after calling this function. 75 * 76 * After this call, the stream will be in AAUDIO_STREAM_STATE_CLOSING 77 * 78 * This function is useful if you want to release the audio resources immediately, but still allow 79 * queries to the stream to occur from other threads. This often happens if you are monitoring 80 * stream progress from a UI thread. 81 * 82 * NOTE: This function is only fully implemented for MMAP streams, which are low latency streams 83 * supported by some devices. On other "Legacy" streams some audio resources will still be in use 84 * and some callbacks may still be in process after this call. 85 * 86 * Available in AAudio since API level 30. Returns Result::ErrorUnimplemented otherwise. 87 * 88 * * @return either Result::OK or an error. 89 */ release()90 virtual Result release() { 91 return Result::ErrorUnimplemented; 92 } 93 94 /** 95 * Close the stream and deallocate any resources from the open() call. 96 */ 97 virtual Result close(); 98 99 /** 100 * Start the stream. This will block until the stream has been started, an error occurs 101 * or `timeoutNanoseconds` has been reached. 102 */ 103 virtual Result start(int64_t timeoutNanoseconds = kDefaultTimeoutNanos); 104 105 /** 106 * Pause the stream. This will block until the stream has been paused, an error occurs 107 * or `timeoutNanoseconds` has been reached. 108 */ 109 virtual Result pause(int64_t timeoutNanoseconds = kDefaultTimeoutNanos); 110 111 /** 112 * Flush the stream. This will block until the stream has been flushed, an error occurs 113 * or `timeoutNanoseconds` has been reached. 114 */ 115 virtual Result flush(int64_t timeoutNanoseconds = kDefaultTimeoutNanos); 116 117 /** 118 * Stop the stream. This will block until the stream has been stopped, an error occurs 119 * or `timeoutNanoseconds` has been reached. 120 */ 121 virtual Result stop(int64_t timeoutNanoseconds = kDefaultTimeoutNanos); 122 123 /* Asynchronous requests. 124 * Use waitForStateChange() if you need to wait for completion. 125 */ 126 127 /** 128 * Start the stream asynchronously. Returns immediately (does not block). Equivalent to calling 129 * `start(0)`. 130 */ 131 virtual Result requestStart() = 0; 132 133 /** 134 * Pause the stream asynchronously. Returns immediately (does not block). Equivalent to calling 135 * `pause(0)`. 136 */ 137 virtual Result requestPause() = 0; 138 139 /** 140 * Flush the stream asynchronously. Returns immediately (does not block). Equivalent to calling 141 * `flush(0)`. 142 */ 143 virtual Result requestFlush() = 0; 144 145 /** 146 * Stop the stream asynchronously. Returns immediately (does not block). Equivalent to calling 147 * `stop(0)`. 148 */ 149 virtual Result requestStop() = 0; 150 151 /** 152 * Query the current state, eg. StreamState::Pausing 153 * 154 * @return state or a negative error. 155 */ 156 virtual StreamState getState() = 0; 157 158 /** 159 * Wait until the stream's current state no longer matches the input state. 160 * The input state is passed to avoid race conditions caused by the state 161 * changing between calls. 162 * 163 * Note that generally applications do not need to call this. It is considered 164 * an advanced technique and is mostly used for testing. 165 * 166 * <pre><code> 167 * int64_t timeoutNanos = 500 * kNanosPerMillisecond; // arbitrary 1/2 second 168 * StreamState currentState = stream->getState(); 169 * StreamState nextState = StreamState::Unknown; 170 * while (result == Result::OK && currentState != StreamState::Paused) { 171 * result = stream->waitForStateChange( 172 * currentState, &nextState, timeoutNanos); 173 * currentState = nextState; 174 * } 175 * </code></pre> 176 * 177 * If the state does not change within the timeout period then it will 178 * return ErrorTimeout. This is true even if timeoutNanoseconds is zero. 179 * 180 * @param inputState The state we want to change away from. 181 * @param nextState Pointer to a variable that will be set to the new state. 182 * @param timeoutNanoseconds The maximum time to wait in nanoseconds. 183 * @return Result::OK or a Result::Error. 184 */ 185 virtual Result waitForStateChange(StreamState inputState, 186 StreamState *nextState, 187 int64_t timeoutNanoseconds) = 0; 188 189 /** 190 * This can be used to adjust the latency of the buffer by changing 191 * the threshold where blocking will occur. 192 * By combining this with getXRunCount(), the latency can be tuned 193 * at run-time for each device. 194 * 195 * This cannot be set higher than getBufferCapacity(). 196 * 197 * This should only be used with Output streams. It will 198 * be ignored for Input streams because they are generally kept as empty as possible. 199 * 200 * For OpenSL ES, this method only has an effect on output stream that do NOT 201 * use a callback. The blocking writes goes into a buffer in Oboe and the size of that 202 * buffer is controlled by this method. 203 * 204 * @param requestedFrames requested number of frames that can be filled without blocking 205 * @return the resulting buffer size in frames (obtained using value()) or an error (obtained 206 * using error()) 207 */ setBufferSizeInFrames(int32_t)208 virtual ResultWithValue<int32_t> setBufferSizeInFrames(int32_t /* requestedFrames */) { 209 return Result::ErrorUnimplemented; 210 } 211 212 /** 213 * An XRun is an Underrun or an Overrun. 214 * During playing, an underrun will occur if the stream is not written in time 215 * and the system runs out of valid data. 216 * During recording, an overrun will occur if the stream is not read in time 217 * and there is no place to put the incoming data so it is discarded. 218 * 219 * An underrun or overrun can cause an audible "pop" or "glitch". 220 * 221 * @return a result which is either Result::OK with the xRun count as the value, or a 222 * Result::Error* code 223 */ getXRunCount()224 virtual ResultWithValue<int32_t> getXRunCount() { 225 return ResultWithValue<int32_t>(Result::ErrorUnimplemented); 226 } 227 228 /** 229 * @return true if XRun counts are supported on the stream 230 */ 231 virtual bool isXRunCountSupported() const = 0; 232 233 /** 234 * Query the number of frames that are read or written by the endpoint at one time. 235 * 236 * @return burst size 237 */ getFramesPerBurst()238 int32_t getFramesPerBurst() const { 239 return mFramesPerBurst; 240 } 241 242 /** 243 * Get the number of bytes in each audio frame. This is calculated using the channel count 244 * and the sample format. For example, a 2 channel floating point stream will have 245 * 2 * 4 = 8 bytes per frame. 246 * 247 * @return number of bytes in each audio frame. 248 */ getBytesPerFrame()249 int32_t getBytesPerFrame() const { return mChannelCount * getBytesPerSample(); } 250 251 /** 252 * Get the number of bytes per sample. This is calculated using the sample format. For example, 253 * a stream using 16-bit integer samples will have 2 bytes per sample. 254 * 255 * @return the number of bytes per sample. 256 */ 257 int32_t getBytesPerSample() const; 258 259 /** 260 * The number of audio frames written into the stream. 261 * This monotonic counter will never get reset. 262 * 263 * @return the number of frames written so far 264 */ 265 virtual int64_t getFramesWritten(); 266 267 /** 268 * The number of audio frames read from the stream. 269 * This monotonic counter will never get reset. 270 * 271 * @return the number of frames read so far 272 */ 273 virtual int64_t getFramesRead(); 274 275 /** 276 * Calculate the latency of a stream based on getTimestamp(). 277 * 278 * Output latency is the time it takes for a given frame to travel from the 279 * app to some type of digital-to-analog converter. If the DAC is external, for example 280 * in a USB interface or a TV connected by HDMI, then there may be additional latency 281 * that the Android device is unaware of. 282 * 283 * Input latency is the time it takes to a given frame to travel from an analog-to-digital 284 * converter (ADC) to the app. 285 * 286 * Note that the latency of an OUTPUT stream will increase abruptly when you write data to it 287 * and then decrease slowly over time as the data is consumed. 288 * 289 * The latency of an INPUT stream will decrease abruptly when you read data from it 290 * and then increase slowly over time as more data arrives. 291 * 292 * The latency of an OUTPUT stream is generally higher than the INPUT latency 293 * because an app generally tries to keep the OUTPUT buffer full and the INPUT buffer empty. 294 * 295 * Note that due to issues in Android before R, we recommend NOT calling 296 * this method from a data callback. See this tech note for more details. 297 * https://github.com/google/oboe/wiki/TechNote_ReleaseBuffer 298 * 299 * @return a ResultWithValue which has a result of Result::OK and a value containing the latency 300 * in milliseconds, or a result of Result::Error*. 301 */ calculateLatencyMillis()302 virtual ResultWithValue<double> calculateLatencyMillis() { 303 return ResultWithValue<double>(Result::ErrorUnimplemented); 304 } 305 306 /** 307 * Get the estimated time that the frame at `framePosition` entered or left the audio processing 308 * pipeline. 309 * 310 * This can be used to coordinate events and interactions with the external environment, and to 311 * estimate the latency of an audio stream. An example of usage can be found in the hello-oboe 312 * sample (search for "calculateCurrentOutputLatencyMillis"). 313 * 314 * The time is based on the implementation's best effort, using whatever knowledge is available 315 * to the system, but cannot account for any delay unknown to the implementation. 316 * 317 * Note that due to issues in Android before R, we recommend NOT calling 318 * this method from a data callback. See this tech note for more details. 319 * https://github.com/google/oboe/wiki/TechNote_ReleaseBuffer 320 * 321 * @deprecated since 1.0, use AudioStream::getTimestamp(clockid_t clockId) instead, which 322 * returns ResultWithValue 323 * @param clockId the type of clock to use e.g. CLOCK_MONOTONIC 324 * @param framePosition the frame number to query 325 * @param timeNanoseconds an output parameter which will contain the presentation timestamp 326 */ getTimestamp(clockid_t,int64_t *,int64_t *)327 virtual Result getTimestamp(clockid_t /* clockId */, 328 int64_t* /* framePosition */, 329 int64_t* /* timeNanoseconds */) { 330 return Result::ErrorUnimplemented; 331 } 332 333 /** 334 * Get the estimated time that the frame at `framePosition` entered or left the audio processing 335 * pipeline. 336 * 337 * This can be used to coordinate events and interactions with the external environment, and to 338 * estimate the latency of an audio stream. An example of usage can be found in the hello-oboe 339 * sample (search for "calculateCurrentOutputLatencyMillis"). 340 * 341 * The time is based on the implementation's best effort, using whatever knowledge is available 342 * to the system, but cannot account for any delay unknown to the implementation. 343 * 344 * Note that due to issues in Android before R, we recommend NOT calling 345 * this method from a data callback. See this tech note for more details. 346 * https://github.com/google/oboe/wiki/TechNote_ReleaseBuffer 347 * 348 * See 349 * @param clockId the type of clock to use e.g. CLOCK_MONOTONIC 350 * @return a FrameTimestamp containing the position and time at which a particular audio frame 351 * entered or left the audio processing pipeline, or an error if the operation failed. 352 */ 353 virtual ResultWithValue<FrameTimestamp> getTimestamp(clockid_t /* clockId */); 354 355 // ============== I/O =========================== 356 /** 357 * Write data from the supplied buffer into the stream. This method will block until the write 358 * is complete or it runs out of time. 359 * 360 * If `timeoutNanoseconds` is zero then this call will not wait. 361 * 362 * @param buffer The address of the first sample. 363 * @param numFrames Number of frames to write. Only complete frames will be written. 364 * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion. 365 * @return a ResultWithValue which has a result of Result::OK and a value containing the number 366 * of frames actually written, or result of Result::Error*. 367 */ write(const void *,int32_t,int64_t)368 virtual ResultWithValue<int32_t> write(const void* /* buffer */, 369 int32_t /* numFrames */, 370 int64_t /* timeoutNanoseconds */ ) { 371 return ResultWithValue<int32_t>(Result::ErrorUnimplemented); 372 } 373 374 /** 375 * Read data into the supplied buffer from the stream. This method will block until the read 376 * is complete or it runs out of time. 377 * 378 * If `timeoutNanoseconds` is zero then this call will not wait. 379 * 380 * @param buffer The address of the first sample. 381 * @param numFrames Number of frames to read. Only complete frames will be read. 382 * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion. 383 * @return a ResultWithValue which has a result of Result::OK and a value containing the number 384 * of frames actually read, or result of Result::Error*. 385 */ read(void *,int32_t,int64_t)386 virtual ResultWithValue<int32_t> read(void* /* buffer */, 387 int32_t /* numFrames */, 388 int64_t /* timeoutNanoseconds */) { 389 return ResultWithValue<int32_t>(Result::ErrorUnimplemented); 390 } 391 392 /** 393 * Get the underlying audio API which the stream uses. 394 * 395 * @return the API that this stream uses. 396 */ 397 virtual AudioApi getAudioApi() const = 0; 398 399 /** 400 * Returns true if the underlying audio API is AAudio. 401 * 402 * @return true if this stream is implemented using the AAudio API. 403 */ usesAAudio()404 bool usesAAudio() const { 405 return getAudioApi() == AudioApi::AAudio; 406 } 407 408 /** 409 * Only for debugging. Do not use in production. 410 * If you need to call this method something is wrong. 411 * If you think you need it for production then please let us know 412 * so we can modify Oboe so that you don't need this. 413 * 414 * @return nullptr or a pointer to a stream from the system API 415 */ getUnderlyingStream()416 virtual void *getUnderlyingStream() const { 417 return nullptr; 418 } 419 420 /** 421 * Update mFramesWritten. 422 * For internal use only. 423 */ 424 virtual void updateFramesWritten() = 0; 425 426 /** 427 * Update mFramesRead. 428 * For internal use only. 429 */ 430 virtual void updateFramesRead() = 0; 431 432 /* 433 * Swap old callback for new callback. 434 * This not atomic. 435 * This should only be used internally. 436 * @param dataCallback 437 * @return previous dataCallback 438 */ swapDataCallback(AudioStreamDataCallback * dataCallback)439 AudioStreamDataCallback *swapDataCallback(AudioStreamDataCallback *dataCallback) { 440 AudioStreamDataCallback *previousCallback = mDataCallback; 441 mDataCallback = dataCallback; 442 return previousCallback; 443 } 444 445 /* 446 * Swap old callback for new callback. 447 * This not atomic. 448 * This should only be used internally. 449 * @param errorCallback 450 * @return previous errorCallback 451 */ swapErrorCallback(AudioStreamErrorCallback * errorCallback)452 AudioStreamErrorCallback *swapErrorCallback(AudioStreamErrorCallback *errorCallback) { 453 AudioStreamErrorCallback *previousCallback = mErrorCallback; 454 mErrorCallback = errorCallback; 455 return previousCallback; 456 } 457 458 /** 459 * @return number of frames of data currently in the buffer 460 */ 461 ResultWithValue<int32_t> getAvailableFrames(); 462 463 /** 464 * Wait until the stream has a minimum amount of data available in its buffer. 465 * This can be used with an EXCLUSIVE MMAP input stream to avoid reading data too close to 466 * the DSP write position, which may cause glitches. 467 * 468 * Starting with Oboe 1.7.1, the numFrames will be clipped internally against the 469 * BufferCapacity minus BurstSize. This is to prevent trying to wait for more frames 470 * than could possibly be available. In this case, the return value may be less than numFrames. 471 * Note that there may still be glitching if numFrames is too high. 472 * 473 * @param numFrames requested minimum frames available 474 * @param timeoutNanoseconds 475 * @return number of frames available, ErrorTimeout 476 */ 477 ResultWithValue<int32_t> waitForAvailableFrames(int32_t numFrames, 478 int64_t timeoutNanoseconds); 479 480 /** 481 * @return last result passed from an error callback 482 */ getLastErrorCallbackResult()483 virtual oboe::Result getLastErrorCallbackResult() const { 484 return mErrorCallbackResult; 485 } 486 487 getDelayBeforeCloseMillis()488 int32_t getDelayBeforeCloseMillis() const { 489 return mDelayBeforeCloseMillis; 490 } 491 492 /** 493 * Set the time to sleep before closing the internal stream. 494 * 495 * Sometimes a callback can occur shortly after a stream has been stopped and 496 * even after a close! If the stream has been closed then the callback 497 * might access memory that has been freed, which could cause a crash. 498 * This seems to be more likely in Android P or earlier. 499 * But it can also occur in later versions. By sleeping, we give time for 500 * the callback threads to finish. 501 * 502 * Note that this only has an effect when OboeGlobals::areWorkaroundsEnabled() is true. 503 * 504 * @param delayBeforeCloseMillis time to sleep before close. 505 */ setDelayBeforeCloseMillis(int32_t delayBeforeCloseMillis)506 void setDelayBeforeCloseMillis(int32_t delayBeforeCloseMillis) { 507 mDelayBeforeCloseMillis = delayBeforeCloseMillis; 508 } 509 510 /** 511 * Enable or disable a device specific CPU performance hint. 512 * Runtime benchmarks such as the callback duration may be used to 513 * speed up the CPU and improve real-time performance. 514 * 515 * Note that this feature is device specific and may not be implemented. 516 * Also the benefits may vary by device. 517 * 518 * The flag will be checked in the Oboe data callback. If it transitions from false to true 519 * then the PerformanceHint feature will be started. 520 * This only needs to be called once. 521 * 522 * You may want to enable this if you have a dynamically changing workload 523 * and you notice that you are getting underruns and glitches when your workload increases. 524 * This might happen, for example, if you suddenly go from playing one note to 525 * ten notes on a synthesizer. 526 * 527 * Try the CPU Load test in OboeTester if you would like to experiment with this interactively. 528 * 529 * On some devices, this may be implemented using the "ADPF" library. 530 * 531 * @param enabled true if you would like a performance boost 532 */ setPerformanceHintEnabled(bool enabled)533 void setPerformanceHintEnabled(bool enabled) { 534 mPerformanceHintEnabled = enabled; 535 } 536 537 /** 538 * This only tells you if the feature has been requested. 539 * It does not tell you if the PerformanceHint feature is implemented or active on the device. 540 * 541 * @return true if set using setPerformanceHintEnabled(). 542 */ isPerformanceHintEnabled()543 bool isPerformanceHintEnabled() { 544 return mPerformanceHintEnabled; 545 } 546 547 protected: 548 549 /** 550 * This is used to detect more than one error callback from a stream. 551 * These were bugs in some versions of Android that caused multiple error callbacks. 552 * Internal bug b/63087953 553 * 554 * Calling this sets an atomic<bool> true and returns the previous value. 555 * 556 * @return false on first call, true on subsequent calls 557 */ wasErrorCallbackCalled()558 bool wasErrorCallbackCalled() { 559 return mErrorCallbackCalled.exchange(true); 560 } 561 562 /** 563 * Wait for a transition from one state to another. 564 * @return OK if the endingState was observed, or ErrorUnexpectedState 565 * if any state that was not the startingState or endingState was observed 566 * or ErrorTimeout. 567 */ 568 virtual Result waitForStateTransition(StreamState startingState, 569 StreamState endingState, 570 int64_t timeoutNanoseconds); 571 572 /** 573 * Override this to provide a default for when the application did not specify a callback. 574 * 575 * @param audioData 576 * @param numFrames 577 * @return result 578 */ onDefaultCallback(void *,int)579 virtual DataCallbackResult onDefaultCallback(void* /* audioData */, int /* numFrames */) { 580 return DataCallbackResult::Stop; 581 } 582 583 /** 584 * Override this to provide your own behaviour for the audio callback 585 * 586 * @param audioData container array which audio frames will be written into or read from 587 * @param numFrames number of frames which were read/written 588 * @return the result of the callback: stop or continue 589 * 590 */ 591 DataCallbackResult fireDataCallback(void *audioData, int numFrames); 592 593 /** 594 * @return true if callbacks may be called 595 */ isDataCallbackEnabled()596 bool isDataCallbackEnabled() { 597 return mDataCallbackEnabled; 598 } 599 600 /** 601 * This can be set false internally to prevent callbacks 602 * after DataCallbackResult::Stop has been returned. 603 */ setDataCallbackEnabled(bool enabled)604 void setDataCallbackEnabled(bool enabled) { 605 mDataCallbackEnabled = enabled; 606 } 607 608 /** 609 * This should only be called as a stream is being opened. 610 * Otherwise we might override setDelayBeforeCloseMillis(). 611 */ 612 void calculateDefaultDelayBeforeCloseMillis(); 613 614 /** 615 * Try to avoid a race condition when closing. 616 */ sleepBeforeClose()617 void sleepBeforeClose() { 618 if (mDelayBeforeCloseMillis > 0) { 619 usleep(mDelayBeforeCloseMillis * 1000); 620 } 621 } 622 623 /** 624 * This may be called internally at the beginning of a callback. 625 */ beginPerformanceHintInCallback()626 virtual void beginPerformanceHintInCallback() {} 627 628 /** 629 * This may be called internally at the end of a callback. 630 * @param numFrames passed to the callback 631 */ endPerformanceHintInCallback(int32_t)632 virtual void endPerformanceHintInCallback(int32_t /*numFrames*/) {} 633 634 /** 635 * This will be called when the stream is closed just in case performance hints were enabled. 636 */ closePerformanceHint()637 virtual void closePerformanceHint() {} 638 639 /* 640 * Set a weak_ptr to this stream from the shared_ptr so that we can 641 * later use a shared_ptr in the error callback. 642 */ setWeakThis(std::shared_ptr<oboe::AudioStream> & sharedStream)643 void setWeakThis(std::shared_ptr<oboe::AudioStream> &sharedStream) { 644 mWeakThis = sharedStream; 645 } 646 647 /* 648 * Make a shared_ptr that will prevent this stream from being deleted. 649 */ lockWeakThis()650 std::shared_ptr<oboe::AudioStream> lockWeakThis() { 651 return mWeakThis.lock(); 652 } 653 654 std::weak_ptr<AudioStream> mWeakThis; // weak pointer to this object 655 656 /** 657 * Number of frames which have been written into the stream 658 * 659 * This is signed integer to match the counters in AAudio. 660 * At audio rates, the counter will overflow in about six million years. 661 */ 662 std::atomic<int64_t> mFramesWritten{}; 663 664 /** 665 * Number of frames which have been read from the stream. 666 * 667 * This is signed integer to match the counters in AAudio. 668 * At audio rates, the counter will overflow in about six million years. 669 */ 670 std::atomic<int64_t> mFramesRead{}; 671 672 std::mutex mLock; // for synchronizing start/stop/close 673 674 oboe::Result mErrorCallbackResult = oboe::Result::OK; 675 676 /** 677 * Number of frames which will be copied to/from the audio device in a single read/write 678 * operation 679 */ 680 int32_t mFramesPerBurst = kUnspecified; 681 682 // Time to sleep in order to prevent a race condition with a callback after a close(). 683 // Two milliseconds may be enough but 10 msec is even safer. 684 static constexpr int kMinDelayBeforeCloseMillis = 10; 685 int32_t mDelayBeforeCloseMillis = kMinDelayBeforeCloseMillis; 686 687 private: 688 689 // Log the scheduler if it changes. 690 void checkScheduler(); 691 int mPreviousScheduler = -1; 692 693 std::atomic<bool> mDataCallbackEnabled{false}; 694 std::atomic<bool> mErrorCallbackCalled{false}; 695 696 std::atomic<bool> mPerformanceHintEnabled{false}; // set only by app 697 }; 698 699 /** 700 * This struct is a stateless functor which closes an AudioStream prior to its deletion. 701 * This means it can be used to safely delete a smart pointer referring to an open stream. 702 */ 703 struct StreamDeleterFunctor { operatorStreamDeleterFunctor704 void operator()(AudioStream *audioStream) { 705 if (audioStream) { 706 audioStream->close(); 707 } 708 delete audioStream; 709 } 710 }; 711 } // namespace oboe 712 713 #endif /* OBOE_STREAM_H_ */ 714