Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: does any of the samples show how to record to a file? #135

Closed
AndroidDeveloperLB opened this issue Jun 27, 2018 · 35 comments
Closed
Assignees
Labels
apps related to a test or example app enhancement

Comments

@AndroidDeveloperLB
Copy link
Contributor

If so, to which file formats?
If not, can you please show how to do it?

It's just that I've tried them, and I don't think any of them do it.

@philburk
Copy link
Collaborator

Oboe is focussed on audio I/O. It does not deal with synthesis or file I/O. But luckily there are lots of solutions for reading and writing sample files.

libsndfile is very popular - https://github.com/erikd/libsndfile/

Or you could transfer the data to Java and use a Java solution.

@AndroidDeveloperLB
Copy link
Contributor Author

AndroidDeveloperLB commented Jun 30, 2018

What if I want to save what the Oboe does to the audio, into an audio file?

@AndroidDeveloperLB
Copy link
Contributor Author

Also, I think what you've linked to is GNU, which is the problematic open sourced license ... :(

@philburk
Copy link
Collaborator

If you can get the data into Java then you can use a modified version of this simple WaveFileWriter from JSyn. It is under Apache Open Source License. You could also convert that to C++.

@AndroidDeveloperLB
Copy link
Contributor Author

I wish I knew how to do it. Was a very long time since I programmed in C/C++.
That's why I asked if there is a sample for file saving.

@philburk
Copy link
Collaborator

Oboe is a C++ API. Are you programming your audio engine in Java? If so then I recommend using the Android Java AudioTrack API.

@AndroidDeveloperLB
Copy link
Contributor Author

I want to record audio, hoping that I could find some APIs and capabilities and "hidden" features on C/C++ library that I can't with normal Java/Kotlin library.
That's why I'm here.

@philburk
Copy link
Collaborator

philburk commented Jul 1, 2018

The C++ APIs have fewer features than the Java/Kotlin APIs. The C/C++ APIs are only for high performance and/or low latency.

For audio recording, have you looked at MediaRecorder?

https://developer.android.com/reference/android/media/MediaRecorder

@dturner
Copy link
Collaborator

dturner commented Jul 2, 2018

The closest sample we have is this codelab: https://codelabs.developers.google.com/codelabs/making-waves-2-sampler/index.html?index=..%2F..%2Findex#0

It's for the AAudio API but could easily be ported to Oboe. The only challenge would be to save the audio data which is stored in memory to a file. This can be done using the normal FILE operations in C++. More here: https://stackoverflow.com/questions/1992953/file-operations-in-android-ndk

@dturner dturner closed this as completed Jul 2, 2018
@AndroidDeveloperLB
Copy link
Contributor Author

@philburk Yes, I have. I was just hoping I could find here some possible ways to overcome this:
https://stackoverflow.com/q/50970915/878126

I've noticed the same apps that do overcome this issue - have JNI libraries. I was thinking that maybe using one here could help me figure out how to do it.

But I also think that recording to a file is quite a basic need of any audio-related library. Even here, and even if the focus is on performance.

@dturner
Copy link
Collaborator

dturner commented Jul 2, 2018

I'll reopen this with a view to creating a sample which demonstrates how to use libsndfile or some other file I/O library to write to a file (maybe combined with FFmpeg). This wouldn't be included in the Oboe core library but we can show how to do this as it's a fairly common request.

@dturner dturner reopened this Jul 2, 2018
@AndroidDeveloperLB
Copy link
Contributor Author

Isn't FFmpeg GNU or something?

@AndroidDeveloperLB
Copy link
Contributor Author

Also thank you for considering this.

@stereomatch
Copy link

In the AAudio echo sample, there is an AudioEffect.cpp - process() method. This process() method reads from recording thread and sends it back to AAudio. Meanwhile the process() method is called by dataCallback().

So if one were to do file IO i.e. saving the recording to file, could it be done directly in process() - or is the suggested method to buffer it to some FIFO queue - and then use another thread to output that to file ?

Because the documentation for dataCallBack() seems to suggest they don't want apps to be doing file IO there:

https://developer.android.com/ndk/reference/group/audio.html#group___audio_1gad88ad53a723807879ba75d3b5e07c073
AAudioStream_dataCallback

These are things the function should NOT do:

allocate memory using, for example, malloc() or new
any file operations such as opening, closing, reading or writing
any network operations such as streaming
use any mutexes or other synchronization primitives
sleep
stop or close the stream
AAudioStream_read()
AAudioStream_write()

The following are OK to call from the data callback:

AAudioStream_get*()
AAudio_convertResultToText()

@dturner
Copy link
Collaborator

dturner commented Jul 19, 2018

or is the suggested method to buffer it to some FIFO queue - and then use another thread to output that to file ?

Yes, that's the correct approach. You shouldn't perform any blocking operations inside the callback as this could cause xruns (overruns or underruns).

@stereomatch
Copy link

Thanks.

@AndroidDeveloperLB
Copy link
Contributor Author

Please do consider showing how to do it in the sample.

@AndroidDeveloperLB
Copy link
Contributor Author

@dturner Closed because it now has this sample?

@dturner
Copy link
Collaborator

dturner commented Apr 23, 2019

Apologies, I might have got a bit trigger happy on closing this. Will consider for future sample updates.

@dturner dturner reopened this Apr 23, 2019
@AndroidDeveloperLB
Copy link
Contributor Author

Thank you

@sheraz-nadeem
Copy link

sheraz-nadeem commented May 6, 2019

@dturner @AndroidDeveloperLB
I have created a sample android app here using Oboe & libsndfile to record audio samples and then save it to a .wav file. Please let me know if there is something I could have done properly or with a better approach.

@AndroidDeveloperLB
Copy link
Contributor Author

@sheraz-nadeem Thanks. It has some issues (permissions request even after being granted and some random crash), but overall seems to work fine.

@sheraz-nadeem
Copy link

@AndroidDeveloperLB Thanks for your feedback. I will definitely fix those issues and update the status here. Cheers

@Tim-Kindberg
Copy link

I'm writing native code to capture audio from an external USB device and encode it via ffmpeg into an mp4 (m4a) container.

I've seen the Wavemaker2 sample that uses AAudio to capture audio data and play it back. I'm sticking with Aaudio for the moment but will translate to Oboe once it's working (which I understand to be straightforward).

Naively, I was going to use something like that sample to call ffmpeg's avcodec and avformat functions on each callback. However, I've just read about how these callbacks must not perform blocking operations. I've looked at @sheraz-nadeem's code but it assumes relatively brief total duration (10secs) so that everything can be stored and written to a file at the end. In my case, users might want to record for hours, so I will have to write concurrently.

Has anyone done anything like that?

@dturner dturner self-assigned this May 21, 2019
@dturner
Copy link
Collaborator

dturner commented May 22, 2019

I've just read about how these callbacks must not perform blocking operations

That's true, but if you don't need a low latency stream then you can use non-blocking reads rather than a callback.

If that's the case then I would start a new thread which periodically does the following:

  • Reads all available data from the input stream using stream->read()
  • Encodes that data and writes it to a file using ffmpeg (or some other encoder)

You'll need to ensure your input buffer capacity is large enough to hold all recorded data between iterations otherwise you'll get overruns (because the buffer will be full). You can check the buffer capacity using stream->getBufferCapacityInFrames() and check whether you're getting overruns using stream->getXRunCount().

If you do get overruns you'll need to have your own, larger, buffer which you write the recorded data into.

You'll probably want some way of communicating between your read/encode thread and your UI thread (e.g. the duration of the recording thus far), in this case I'd use an std::atomic<int64_t> for thread safety.

@dturner
Copy link
Collaborator

dturner commented May 22, 2019

@AndroidDeveloperLB Any reason for closing? I was going to keep this open as a feature request for future sample apps

@dturner dturner added the apps related to a test or example app label May 22, 2019
@AndroidDeveloperLB
Copy link
Contributor Author

OK. Sorry

@AndroidDeveloperLB
Copy link
Contributor Author

I thought the sample was updated.

@Tim-Kindberg
Copy link

I've just read about how these callbacks must not perform blocking operations

That's true, but if you don't need a low latency stream then you can use non-blocking reads rather than a callback.

Thanks. I'm looking for low latency wherever possible and so I've implemented a simple buffering policy whereby the callback is filling one buffer (a few seconds' worth) while another thread encodes the previous filled buffer using ffmpeg. Seems to be working although I wouldn't want to post code until I'm sure.

@mariah-smith25
Copy link

I'm working on a similar feature. Any progress @Tim-Kindberg ?

@Tim-Kindberg
Copy link

The solution I mentioned worked: a two-buffer solution where one buffer (sufficient for a second of audio) was being filled at low-latency while the other buffer was being encoded and stored (takes a few hundred milliseconds even on old phones). I swap the buffers when one gets filled. This is fine for recording but I recently had to adapt the implementation for live streaming, where I can't get away with that 1-second throughput latency. I've now found an open-source non-blocking circular buffer implementation which seems to work fine:

https://moodycamel.com/blog/2013/a-fast-lock-free-queue-for-c++.htm

I'm just glad I didn't have to debug any of it!

@mariah-smith25
Copy link

@dturner My use case includes calculating frequency from the low latency callback while also recording audio to .m4a files. My application has been doing the frequency calculation for a while and to add the audio recording I have to build on the same AudioStream (exclusive stream so can't use MediaRecorder or AudioRecord in conjunction).

I'm thinking to implement the double buffer to do the encoding on a separate thread as we should. I just saw your Medium post about ffmpeg. Would you suggest using ffmpeg to continuously encode short int audio data to an .m4a file?

@renetik
Copy link

renetik commented Aug 6, 2020

@dturner @AndroidDeveloperLB
I have created a sample android app here using Oboe & libsndfile to record audio samples and then save it to a .wav file. Please let me know if there is something I could have done properly or with a better approach.

I cannot make this work... Reported issue sheraz-nadeem/oboe_recorder_sample#4

@dturner
Copy link
Collaborator

dturner commented Sep 15, 2020

Would you suggest using ffmpeg to continuously encode short int audio data to an .m4a file?

Yes, that seems like a reasonable solution, or you could use MediaCodec if you don't want to package ffmpeg with your app.

I'm going to close this issue now. With limited resources adding this to our code samples isn't a priority at the moment. Hopefully the guidance in this issue will help anyone interested. Feel free to ask further questions on here (or perhaps better, on StackOverflow with the [oboe] tag).

@dturner dturner closed this as completed Sep 15, 2020
@rpattabi
Copy link
Contributor

Good decision to close this issue. I think oboe team had given more than enough guidance on this. I just wanted to mention that people can also look at OboeTester's RECORD AND PLAY.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
apps related to a test or example app enhancement
Projects
None yet
Development

No branches or pull requests

9 participants