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