2

I'm trying to record from the microphone, add some effects, and the save this to a file

I've started with the example native-audio included in the Android NDK. I'va managed to add some reverb and play it back but I haven't found any examples or help on how to accomplish this.

Any and all help is welcome.

Mike Bryant
  • 2,455
  • 9
  • 39
  • 60
  • _"I'va managed to add some reverb and play it back"_ So you've already got it working..? Could you clarify what the actual problem is? – Michael Aug 26 '13 at 12:46
  • the problem is saving the audio to a file, I don't know how to go about doing this – Mike Bryant Aug 26 '13 at 14:11

2 Answers2

8

OpenSL is not a framework for file formats and access. If you want a raw PCM file, simply open it for writing and put all buffers from OpenSL callback into the file. But if you want encoded audio, you need your own codec and format handler. You can use ffmpeg libraries, or built-in stagefright.

Update write playback buffers to local raw PCM file

We start with native-audio-jni.c

#include <stdio.h>
FILE* rawFile = NULL;
int bClosing = 0;

...

void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
    assert(bq == bqPlayerBufferQueue);
    assert(NULL == context);
    // for streaming playback, replace this test by logic to find and fill the next buffer
    if (--nextCount > 0 && NULL != nextBuffer && 0 != nextSize) {
        SLresult result;
        // enqueue another buffer
        result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
        // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
        // which for this code example would indicate a programming error
        assert(SL_RESULT_SUCCESS == result);
        (void)result;

        // AlexC: here we write:
        if (rawFile) {
            fwrite(nextBuffer, nextSize, 1, rawFile);
        }
    }
    if (bClosing) { // it is important to do this in a callback, to be on the correct thread
        fclose(rawFile);
        rawFile = NULL;
    }
    // AlexC: end of changes
}

...

void Java_com_example_nativeaudio_NativeAudio_startRecording(JNIEnv* env, jclass clazz)
{
    bClosing = 0;
    rawFile = fopen("/sdcard/rawFile.pcm", "wb");

...

void Java_com_example_nativeaudio_NativeAudio_shutdown(JNIEnv* env, jclass clazz)
{
    bClosing = 1;

...

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • would it be possible to see an example of your proposed solution please? – Mike Bryant Aug 26 '13 at 14:22
  • the first one please, to save the buffers into the file. – Mike Bryant Aug 26 '13 at 15:34
  • Sure, as soon as I get to a PC. – Alex Cohn Aug 26 '13 at 16:11
  • thanks that would be a lifesaver, one of those pull out your hair and eat your own arm kinda problems for me so far . – Mike Bryant Aug 26 '13 at 16:29
  • Your solution does not work for me. Before the if-clause if (--nextCount > 0 && NULL != nextBuffer && 0 != nextSize) nextCount is 1 and nextBuffer is 11968 and nextSize is 8000. If I change it to "--nextCount >= 0" the first 64byte will be saved to the file, but nothing more, because in the stage nextCount will be 0. – Gingerbread123321 Sep 08 '13 at 07:53
  • @Gingerbread123321: you are right, my change is only relevant for streaming, where nextCount is probably being updated independently. If you use the native-audio sample _as is_, you can simply write all your clip to file from the `...select_Clip()` function. And again, you are right, my code misses the first buffer (which is normally enqueued in `...select_Clip()`). My intention was only to demonstrate how the _PlayerCallback_ can be used to write a PCM file. – Alex Cohn Sep 08 '13 at 15:22
  • Ok, I have put the fopen funktion in the select_clip():"fwrite(nextBuffer, nextSize, 1, rawFile);" It is now after the switch(). The file has a size of 78,12KB (5 seconds of record). But when I play it nothing happens...it just does not play. Is it possible to create a wave file this way? – Gingerbread123321 Sep 08 '13 at 17:38
  • @Gingerbread123321: pcm file can be played back in Audacity and similar sound editors. Converting it into WAV is a whole different topic: http://stackoverflow.com/questions/4777181/creating-a-wav-file-from-raw-pcm-data-using-the-android-sdk – Alex Cohn Sep 10 '13 at 05:25
  • Maybe I'm wrong, the `result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);` must be called before writing out raw file, otherwise it ends up with a 0 size raw file. Can OpenSL ES record audio input and write out raw file at the same time, without stopping recorder? many thanks if you can shed some lights on this. – yorkw Mar 04 '15 at 11:10
  • @yorkw: I have long ago lost involvement with OpenSL, so I cannot currently prove or disprove your statement. This specific example was about storing a playback, not recording. I don't believe recording is incompatible with storing to raw file. On the other hand, it is much less relevant to store same stream to raw file and record it (i.e. store compressed file). – Alex Cohn Mar 05 '15 at 14:57
  • 1
    Alex. I have done some googling and figured it out, the key point here is I need recording while reading the data at the same time. Anyway, Your answer does provide a good start point, thanks. – yorkw Mar 06 '15 at 09:38
  • Can you please publish to Github ? I mean the recording part of audio using OpenSL ES , into a file... – android developer Jun 26 '18 at 12:11
  • @androiddeveloper This was 5 years and no less major projects ago, I haven't code to publish at hand, unfortunately. Note that since then, native MediaCodec support has matured, you don't need ffmpeg anymore. – Alex Cohn Jun 26 '18 at 12:34
  • I guess, but I still want to know how to use OpenSL ES for recording. Could be useful – android developer Jun 26 '18 at 13:07
0

Pass the raw vector from c to java and encode it in mp3 with mediaRecorder, I don't know if you can set the audio source from a raw vector, but maybe...