google / oboe

Oboe is a C++ library that makes it easy to build high-performance audio apps on Android.
Apache License 2.0
3.7k stars 566 forks source link

Need onErrorBeforeClose and onErrorAfterClose when there is no error #297

Closed weizhang1999 closed 5 years ago

weizhang1999 commented 5 years ago

Hi, Can you please make oboe call onErrorBeforeClose and onErrorAfterClose even when there is no error? What I want to do is:

  1. In onAudioReady, return DataCallbackResult::Stop when all data are processed.
  2. In onErrorBeforeClose(stream, error), call stream->close() even error code is OK.
  3. In onErrorAfterClose(stream, error), set the stream member variable to nullptr.

According to the doc, "The onError*() methods will be called in a new thread..." With the above procedure, I can properly close the finished streams. It seems there is a max number of streams that can be opened (in my test, it is 14). Thus, I need to close some streams before opening more for multiple sounds playing simultaneously.

Not sure if this will cause any issues for existing code (one need to check the error code in onError*() methods). If yes, is it possible to introduce something like afterStreamStop and afterStreamClose?

Thanks!

dturner commented 5 years ago

You don't need to open multiple streams to play multiple sounds. In fact, you shouldn't do this because you may end up getting much higher latency on some streams if all low latency streams have been allocated.

The correct way to do this is to mix your sounds together before rendering them into a single audio stream which is always running. Take a look at the Mixer class here: https://github.com/google/oboe/blob/master/samples/MegaDrone/src/main/cpp/Mixer.h

If you need to know when a particular sound has finished playing you could extend this SoundRecording object to provide a callback when the last audio frame has been rendered: https://github.com/google/oboe/blob/master/samples/RhythmGame/src/main/cpp/audio/SoundRecording.cpp

You'll need to start a new thread to execute your own callback to avoid blocking onAudioReady.

weizhang1999 commented 5 years ago

Hi Don, Thanks for the explanation. I will try the mixer method.

One more question for the mixer method: Is there a plan for a re-sampler function in oboe? I think it would be very useful if the sound sources have different sampling rate.

Best regards, Wei Zhang

philburk commented 5 years ago

Hello Wei,

We will only call onError* functions if there is an error. But there is a good reason for us to call something in a separate thread if the callback returns DataCallbackResult::Stop. According to this bug: https://github.com/google/oboe/issues/277 there are some issues on various platforms when DataCallbackResult::Stop is returned. We should probably launch a thread and call stop(), but not close(). The stream can then be restarted.

Is there a plan for a re-sampler function in oboe?

Please open a separate Issue for unrelated topics.

dturner commented 5 years ago

@weizhang1999 Just one other thing which you might find helpful, when creating a new thread from onAudioReady I find this method to be quite effective: https://stackoverflow.com/a/46286270/824903

dturner commented 5 years ago

There's a working example here: https://github.com/googlesamples/android-audio-high-performance/blob/master/aaudio/hello-aaudio/src/main/cpp/PlayAudioEngine.cpp#L356

weizhang1999 commented 5 years ago

Thanks again for all the info!