Discussion:
Zero data recorded in OpenSL ES
Sangho Cha
2018-05-03 00:42:52 UTC
Permalink
I'm developing an audio recorder app with OpenSLES on Android. I found out
something wrong in the very first part of the recorded data. Every time I
record, I get zeros only at the first part of the data. The length is
always different. I tested the app on several devices, and the length of
zero differs on each of them.


<Loading Image...>



The codes that I tested are almost same as native-audio
<https://github.com/googlesamples/android-ndk/tree/master/native-audio> given
by Google.

The audio format I tested is a PCM, 16bit sample in 16KHz. I use 2 of a 640
bytes buffer to record, switch them in the callback function and copy the
filled one to another buffer to be written as a file after recording is
done.

I want the buffer is filled with non zero data, or at least I want to be
notified by callback or something when the non-zero data is prepared.

There could be my misunderstanding on OpenSLES. so please guide me if
anybody knows why.

I attach the codes snippet below.


// engine interfacesstatic SLObjectItf engineObject = NULL;static SLEngineItf engineEngine;
// recorder interfacesstatic SLObjectItf recorderObject = NULL;static SLRecordItf recorderRecord;static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
static char audioFilePath[256];
#define RECORDER_FRAMES (160 * 2)#define FILEOUT_BUFFER (16000 * 60)
static short* recorderBuffer = NULL;static short recorderBuffer0[RECORDER_FRAMES];static short recorderBuffer1[RECORDER_FRAMES];
static short* fileoutBuffer = NULL;static unsigned int fileoutBufferPosition = 0;

void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context){
assert(bq == recorderBufferQueue);
assert(NULL == context);

memcpy(fileoutBuffer + fileoutBufferPosition, recorderBuffer, RECORDER_FRAMES * sizeof(short));
fileoutBufferPosition += RECORDER_FRAMES;
recorderBuffer = recorderBuffer == recorderBuffer0 ? recorderBuffer1 : recorderBuffer0;
SLresult result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, recorderBuffer,
RECORDER_FRAMES * sizeof(short)); }
/*
* Class: com_example_slesrecorder_slesrecorder_NativeAudio
* Method: createAudioRecorder
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_com_example_slesrecorder_slesrecorder_NativeAudio_createAudioRecorder
(JNIEnv * env, jclass clazz){
SLresult result;

// configure audio source
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
SLDataSource audioSrc = {&loc_dev, NULL};

// configure audio sink
SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_16,
SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN};
SLDataSink audioSnk = {&loc_bq, &format_pcm};

// create audio recorder
// (requires the RECORD_AUDIO permission)
const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req[1] = {SL_BOOLEAN_TRUE};
result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audioSrc,
&audioSnk, 1, id, req);
if (SL_RESULT_SUCCESS != result) {
return JNI_FALSE;
}

// realize the audio recorder
result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result) {
return JNI_FALSE;
}

// get the record interface
result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
assert(SL_RESULT_SUCCESS == result);
(void)result;

// get the buffer queue interface
result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
&recorderBufferQueue);
assert(SL_RESULT_SUCCESS == result);
(void)result;

// register callback on the buffer queue
result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback,
NULL);
assert(SL_RESULT_SUCCESS == result);
(void)result;

return JNI_TRUE;}
/*
* Class: com_example_slesrecorder_slesrecorder_NativeAudio
* Method: startRecording
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_example_slesrecorder_slesrecorder_NativeAudio_startRecording
(JNIEnv * env, jclass clazz, jstring filepath){
SLresult result;

const char* utf8str = env->GetStringUTFChars(filepath, NULL);
strcpy(audioFilePath, utf8str);

// in case already recording, stop recording and clear buffer queue
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
assert(SL_RESULT_SUCCESS == result);
(void)result;
result = (*recorderBufferQueue)->Clear(recorderBufferQueue);
assert(SL_RESULT_SUCCESS == result);
(void)result;

// enqueue an empty buffer to be filled by the recorder
// (for streaming recording, we would enqueue at least 2 empty buffers to start things off)
recorderBuffer = recorderBuffer0;

result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, recorderBuffer,
RECORDER_FRAMES * sizeof(short));

// 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;

// start recording
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
assert(SL_RESULT_SUCCESS == result);
(void)result;}
/*
* Class: com_example_slesrecorder_slesrecorder_NativeAudio
* Method: stopRecording
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_example_slesrecorder_slesrecorder_NativeAudio_stopRecording
(JNIEnv * env, jclass clazz){
SLresult result;
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);

if (SL_RESULT_SUCCESS == result && fileoutBufferPosition != 0) {
FILE* fp = fopen(audioFilePath, "wb");
fwrite(fileoutBuffer, sizeof(short), fileoutBufferPosition, fp);
fclose(fp);
}
fileoutBufferPosition = 0;
(void)result;}
--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to android-ndk+***@googlegroups.com.
To post to this group, send email to android-***@googlegroups.com.
Visit this group at https://groups.google.com/group/android-ndk.
To view this discussion on the web visit https://groups.google.com/d/msgid/android-ndk/2b044763-80a8-4900-b404-52f757fd2cc3%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
'Phil Burk' via android-ndk
2018-05-03 14:51:58 UTC
Permalink
Hello Sangho,
Post by Sangho Cha
I'm developing an audio recorder app with OpenSLES on Android. I found out
something wrong in the very first part of the recorded data. Every time I
record, I get zeros only at the first part of the data. The length is
always different. I tested the app on several devices, and the length of
zero differs on each of them.
I cannot see all of your code. So I am not sure what the problem is.

Are you Enqueue()ing a buffer before you start recording? If not then you
may be copying data from a buffer that was never filled.

Note that in Oboe we enqueue right before we start.
https://github.com/google/oboe/blob/master/src/opensles/AudioInputStreamOpenSLES.cpp#L179

But I cannot explain why the zero data varies in size. It might just be
because it takes while for the real data to flow through the system. You
might have to just trim off data up to the first non-zero sample.

Phil Burk
--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to android-ndk+***@googlegroups.com.
To post to this group, send email to android-***@googlegroups.com.
Visit this group at https://groups.google.com/group/android-ndk.
To view this discussion on the web visit https://groups.google.com/d/msgid/android-ndk/CACL%3DQ7zDxppCzmHe%3D8WvxEtpuJ1QWx15vT1R8o_wHjLPdPWm%2BQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
Loading...