Reputation: 254
Hi I am working on Android JNI Audio part, below jni code I am calling from android 12 times as per my logic. As soon as 1st clip played I send callback event to android and I am again calling selectClip()
to play audio clip. I am able to play 2 times but on third call application throwing error as libOpenSLES Leaving BufferQueue : SL_RESULT_BUFFER_INSUFFICIENT
.
Am I missing something in this?
Any pointer on the same to resolve this?
jboolean flag=JNI_TRUE;
jint clipNote = 0;
// select the desired clip and play count, and enqueue the first buffer if idle
JNIEXPORT jboolean JNICALL Java_com_example_nativeaudio_NativeAudio_selectClip(JNIEnv * env, jobject obj,
jint count)
{
// sleep logic
while((clock() - t)/1000 < 2000) {
usleep(10000); // sleep for 10ms
}
if(clipNote < 12) {
if(flag == JNI_TRUE) {
__android_log_print(ANDROID_LOG_DEBUG , "CustomTag", " flag = true : ClipNote : %d",clipNote);
clipNote = clipNote + 1;
nextBuffer = (short *) audio1;
nextSize = sizeof(audio1);
nextCount = count/2000;
if (nextSize > 0) {
// here we only enqueue one buffer because it is a long clip,
// but for streaming playback we would typically enqueue at least 2 buffers to start
SLresult result;
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
if (SL_RESULT_SUCCESS != result) {
return JNI_FALSE;
}
}
// callback to android
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid = (*env)->GetMethodID(env, cls, "callBackStart", "(I)V");
if (mid == 0) {
return;
}
flag=JNI_FALSE;
(*env)->CallVoidMethod(env, obj, mid, clipNote);
} else {
// callback to android
__android_log_print(ANDROID_LOG_DEBUG , "CustomTag", " flag = false");
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid = (*env)->GetMethodID(env, cls, "callBackRelease", "(I)V");
if (mid == 0) {
return;
}
flag = JNI_TRUE;
(*env)->CallVoidMethod(env, obj, mid, count);
}
t = clock();
} else {
SLresult result;
// make sure the asset audio player was created
if (NULL != fdPlayerPlay) {
result = (*fdPlayerPlay)>SetPlayState(fdPlayerPlay,SL_PLAYSTATE_PAUSED);
assert(SL_RESULT_SUCCESS == result);
(void)result;
}
}
return JNI_TRUE;
}
Upvotes: 2
Views: 2359
Reputation: 161
You can call (*bqPlayerBufferQueue)->Clear(bqPlayerBufferQueue);
when you stop the player, that will allow the previous thread to shutdown without having to wait on a timer.
Upvotes: 0
Reputation: 30216
Set numbuffers
Chances are your numbuffers
on your SLDataLocator_AndroidSimpleBufferQueue
is inappropriately low.
SLDataLocator_AndroidSimpleBufferQueue in_loc;
in_loc.numBuffers = 5; // what number do you have here?
From the OpenSL ES spec:
If the maximum number of buffers specified in the SLDataLocator_BufferQueue structure used as the data source when creating the media object using the CreateAudioPlayer or CreateMidiPlayer method has been reached, the buffer is not added to the buffer queue and SL_RESULT_BUFFER_INSUFFICIENT is returned. At this point the client should wait until it receives a callback notification for a buffer completion at which time it can enqueue the buffer.
Alternatives
If changing your numbuffers
to even a very high number doesn't work, ensure that you set your state to playing:
(*player)->SetPlayState( player, SL_PLAYSTATE_PLAYING ); // begin playback
Upvotes: 1
Reputation: 254
SL_RESULT_BUFFER_INSUFFICIENT error was occurring due to the issue in timing. Second thread gets started before the first is complete. The third thread gets started when the first two are in progress. This cannot be handled so it was throwing an error. The timing was increased sufficient enough to complete the first thread, the issue was solved.
Upvotes: 2