1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 /* This is a JNI example where we use native methods to play sounds 19 * using OpenSL ES. See the corresponding Java source file located at: 20 * 21 * src/com/example/nativeaudio/NativeAudio/NativeAudio.java 22 */ 23 24 #include <assert.h> 25 #include <jni.h> 26 #include <string.h> 27 28 // for __android_log_print(ANDROID_LOG_INFO, "YourApp", "formatted message"); 29 // #include <android/log.h> 30 31 // for native audio 32 #include <SLES/OpenSLES.h> 33 #include <SLES/OpenSLES_Android.h> 34 35 // for native asset manager 36 #include <sys/types.h> 37 #include <android/asset_manager.h> 38 #include <android/asset_manager_jni.h> 39 40 // pre-recorded sound clips, both are 8 kHz mono 16-bit signed little endian 41 42 static const char hello[] = 43 #include "hello_clip.h" 44 ; 45 46 static const char android[] = 47 #include "android_clip.h" 48 ; 49 50 // engine interfaces 51 static SLObjectItf engineObject = NULL; 52 static SLEngineItf engineEngine; 53 54 // output mix interfaces 55 static SLObjectItf outputMixObject = NULL; 56 static SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL; 57 58 // buffer queue player interfaces 59 static SLObjectItf bqPlayerObject = NULL; 60 static SLPlayItf bqPlayerPlay; 61 static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; 62 static SLEffectSendItf bqPlayerEffectSend; 63 static SLMuteSoloItf bqPlayerMuteSolo; 64 static SLVolumeItf bqPlayerVolume; 65 66 // aux effect on the output mix, used by the buffer queue player 67 static const SLEnvironmentalReverbSettings reverbSettings = 68 SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; 69 70 // URI player interfaces 71 static SLObjectItf uriPlayerObject = NULL; 72 static SLPlayItf uriPlayerPlay; 73 static SLSeekItf uriPlayerSeek; 74 static SLMuteSoloItf uriPlayerMuteSolo; 75 static SLVolumeItf uriPlayerVolume; 76 77 // file descriptor player interfaces 78 static SLObjectItf fdPlayerObject = NULL; 79 static SLPlayItf fdPlayerPlay; 80 static SLSeekItf fdPlayerSeek; 81 static SLMuteSoloItf fdPlayerMuteSolo; 82 static SLVolumeItf fdPlayerVolume; 83 84 // recorder interfaces 85 static SLObjectItf recorderObject = NULL; 86 static SLRecordItf recorderRecord; 87 static SLAndroidSimpleBufferQueueItf recorderBufferQueue; 88 89 // synthesized sawtooth clip 90 #define SAWTOOTH_FRAMES 8000 91 static short sawtoothBuffer[SAWTOOTH_FRAMES]; 92 93 // 5 seconds of recorded audio at 16 kHz mono, 16-bit signed little endian 94 #define RECORDER_FRAMES (16000 * 5) 95 static short recorderBuffer[RECORDER_FRAMES]; 96 static unsigned recorderSize = 0; 97 static SLmilliHertz recorderSR; 98 99 // pointer and size of the next player buffer to enqueue, and number of remaining buffers 100 static short *nextBuffer; 101 static unsigned nextSize; 102 static int nextCount; 103 104 105 // synthesize a mono sawtooth wave and place it into a buffer (called automatically on load) 106 __attribute__((constructor)) static void onDlOpen(void) 107 { 108 unsigned i; 109 for (i = 0; i < SAWTOOTH_FRAMES; ++i) { 110 sawtoothBuffer[i] = 32768 - ((i % 100) * 660); 111 } 112 } 113 114 115 // this callback handler is called every time a buffer finishes playing 116 void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) 117 { 118 assert(bq == bqPlayerBufferQueue); 119 assert(NULL == context); 120 // for streaming playback, replace this test by logic to find and fill the next buffer 121 if (--nextCount > 0 && NULL != nextBuffer && 0 != nextSize) { 122 SLresult result; 123 // enqueue another buffer 124 result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize); 125 // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT, 126 // which for this code example would indicate a programming error 127 assert(SL_RESULT_SUCCESS == result); 128 (void)result; 129 } 130 } 131 132 133 // this callback handler is called every time a buffer finishes recording 134 void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context) 135 { 136 assert(bq == bqRecorderBufferQueue); 137 assert(NULL == context); 138 // for streaming recording, here we would call Enqueue to give recorder the next buffer to fill 139 // but instead, this is a one-time buffer so we stop recording 140 SLresult result; 141 result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED); 142 if (SL_RESULT_SUCCESS == result) { 143 recorderSize = RECORDER_FRAMES * sizeof(short); 144 recorderSR = SL_SAMPLINGRATE_16; 145 } 146 } 147 148 149 // create the engine and output mix objects 150 void Java_com_example_nativeaudio_NativeAudio_createEngine(JNIEnv* env, jclass clazz) 151 { 152 SLresult result; 153 154 // create engine 155 result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 156 assert(SL_RESULT_SUCCESS == result); 157 (void)result; 158 159 // realize the engine 160 result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 161 assert(SL_RESULT_SUCCESS == result); 162 (void)result; 163 164 // get the engine interface, which is needed in order to create other objects 165 result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 166 assert(SL_RESULT_SUCCESS == result); 167 (void)result; 168 169 // create output mix, with environmental reverb specified as a non-required interface 170 const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; 171 const SLboolean req[1] = {SL_BOOLEAN_FALSE}; 172 result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req); 173 assert(SL_RESULT_SUCCESS == result); 174 (void)result; 175 176 // realize the output mix 177 result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); 178 assert(SL_RESULT_SUCCESS == result); 179 (void)result; 180 181 // get the environmental reverb interface 182 // this could fail if the environmental reverb effect is not available, 183 // either because the feature is not present, excessive CPU load, or 184 // the required MODIFY_AUDIO_SETTINGS permission was not requested and granted 185 result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, 186 &outputMixEnvironmentalReverb); 187 if (SL_RESULT_SUCCESS == result) { 188 result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties( 189 outputMixEnvironmentalReverb, &reverbSettings); 190 (void)result; 191 } 192 // ignore unsuccessful result codes for environmental reverb, as it is optional for this example 193 194 } 195 196 197 // create buffer queue audio player 198 void Java_com_example_nativeaudio_NativeAudio_createBufferQueueAudioPlayer(JNIEnv* env, 199 jclass clazz) 200 { 201 SLresult result; 202 203 // configure audio source 204 SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; 205 SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_8, 206 SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, 207 SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN}; 208 SLDataSource audioSrc = {&loc_bufq, &format_pcm}; 209 210 // configure audio sink 211 SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; 212 SLDataSink audioSnk = {&loc_outmix, NULL}; 213 214 // create audio player 215 const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, 216 /*SL_IID_MUTESOLO,*/ SL_IID_VOLUME}; 217 const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, 218 /*SL_BOOLEAN_TRUE,*/ SL_BOOLEAN_TRUE}; 219 result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 220 3, ids, req); 221 assert(SL_RESULT_SUCCESS == result); 222 (void)result; 223 224 // realize the player 225 result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); 226 assert(SL_RESULT_SUCCESS == result); 227 (void)result; 228 229 // get the play interface 230 result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay); 231 assert(SL_RESULT_SUCCESS == result); 232 (void)result; 233 234 // get the buffer queue interface 235 result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, 236 &bqPlayerBufferQueue); 237 assert(SL_RESULT_SUCCESS == result); 238 (void)result; 239 240 // register callback on the buffer queue 241 result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL); 242 assert(SL_RESULT_SUCCESS == result); 243 (void)result; 244 245 // get the effect send interface 246 result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND, 247 &bqPlayerEffectSend); 248 assert(SL_RESULT_SUCCESS == result); 249 (void)result; 250 251 #if 0 // mute/solo is not supported for sources that are known to be mono, as this is 252 // get the mute/solo interface 253 result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo); 254 assert(SL_RESULT_SUCCESS == result); 255 (void)result; 256 #endif 257 258 // get the volume interface 259 result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume); 260 assert(SL_RESULT_SUCCESS == result); 261 (void)result; 262 263 // set the player's state to playing 264 result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); 265 assert(SL_RESULT_SUCCESS == result); 266 (void)result; 267 } 268 269 270 // create URI audio player 271 jboolean Java_com_example_nativeaudio_NativeAudio_createUriAudioPlayer(JNIEnv* env, jclass clazz, 272 jstring uri) 273 { 274 SLresult result; 275 276 // convert Java string to UTF-8 277 const char *utf8 = (*env)->GetStringUTFChars(env, uri, NULL); 278 assert(NULL != utf8); 279 280 // configure audio source 281 // (requires the INTERNET permission depending on the uri parameter) 282 SLDataLocator_URI loc_uri = {SL_DATALOCATOR_URI, (SLchar *) utf8}; 283 SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; 284 SLDataSource audioSrc = {&loc_uri, &format_mime}; 285 286 // configure audio sink 287 SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; 288 SLDataSink audioSnk = {&loc_outmix, NULL}; 289 290 // create audio player 291 const SLInterfaceID ids[3] = {SL_IID_SEEK, SL_IID_MUTESOLO, SL_IID_VOLUME}; 292 const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 293 result = (*engineEngine)->CreateAudioPlayer(engineEngine, &uriPlayerObject, &audioSrc, 294 &audioSnk, 3, ids, req); 295 // note that an invalid URI is not detected here, but during prepare/prefetch on Android, 296 // or possibly during Realize on other platforms 297 assert(SL_RESULT_SUCCESS == result); 298 (void)result; 299 300 // release the Java string and UTF-8 301 (*env)->ReleaseStringUTFChars(env, uri, utf8); 302 303 // realize the player 304 result = (*uriPlayerObject)->Realize(uriPlayerObject, SL_BOOLEAN_FALSE); 305 // this will always succeed on Android, but we check result for portability to other platforms 306 if (SL_RESULT_SUCCESS != result) { 307 (*uriPlayerObject)->Destroy(uriPlayerObject); 308 uriPlayerObject = NULL; 309 return JNI_FALSE; 310 } 311 312 // get the play interface 313 result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_PLAY, &uriPlayerPlay); 314 assert(SL_RESULT_SUCCESS == result); 315 (void)result; 316 317 // get the seek interface 318 result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_SEEK, &uriPlayerSeek); 319 assert(SL_RESULT_SUCCESS == result); 320 (void)result; 321 322 // get the mute/solo interface 323 result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_MUTESOLO, &uriPlayerMuteSolo); 324 assert(SL_RESULT_SUCCESS == result); 325 (void)result; 326 327 // get the volume interface 328 result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_VOLUME, &uriPlayerVolume); 329 assert(SL_RESULT_SUCCESS == result); 330 (void)result; 331 332 return JNI_TRUE; 333 } 334 335 336 // set the playing state for the URI audio player 337 // to PLAYING (true) or PAUSED (false) 338 void Java_com_example_nativeaudio_NativeAudio_setPlayingUriAudioPlayer(JNIEnv* env, 339 jclass clazz, jboolean isPlaying) 340 { 341 SLresult result; 342 343 // make sure the URI audio player was created 344 if (NULL != uriPlayerPlay) { 345 346 // set the player's state 347 result = (*uriPlayerPlay)->SetPlayState(uriPlayerPlay, isPlaying ? 348 SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED); 349 assert(SL_RESULT_SUCCESS == result); 350 (void)result; 351 } 352 353 } 354 355 356 // set the whole file looping state for the URI audio player 357 void Java_com_example_nativeaudio_NativeAudio_setLoopingUriAudioPlayer(JNIEnv* env, 358 jclass clazz, jboolean isLooping) 359 { 360 SLresult result; 361 362 // make sure the URI audio player was created 363 if (NULL != uriPlayerSeek) { 364 365 // set the looping state 366 result = (*uriPlayerSeek)->SetLoop(uriPlayerSeek, (SLboolean) isLooping, 0, 367 SL_TIME_UNKNOWN); 368 assert(SL_RESULT_SUCCESS == result); 369 (void)result; 370 } 371 372 } 373 374 375 // expose the mute/solo APIs to Java for one of the 3 players 376 377 static SLMuteSoloItf getMuteSolo() 378 { 379 if (uriPlayerMuteSolo != NULL) 380 return uriPlayerMuteSolo; 381 else if (fdPlayerMuteSolo != NULL) 382 return fdPlayerMuteSolo; 383 else 384 return bqPlayerMuteSolo; 385 } 386 387 void Java_com_example_nativeaudio_NativeAudio_setChannelMuteUriAudioPlayer(JNIEnv* env, 388 jclass clazz, jint chan, jboolean mute) 389 { 390 SLresult result; 391 SLMuteSoloItf muteSoloItf = getMuteSolo(); 392 if (NULL != muteSoloItf) { 393 result = (*muteSoloItf)->SetChannelMute(muteSoloItf, chan, mute); 394 assert(SL_RESULT_SUCCESS == result); 395 (void)result; 396 } 397 } 398 399 void Java_com_example_nativeaudio_NativeAudio_setChannelSoloUriAudioPlayer(JNIEnv* env, 400 jclass clazz, jint chan, jboolean solo) 401 { 402 SLresult result; 403 SLMuteSoloItf muteSoloItf = getMuteSolo(); 404 if (NULL != muteSoloItf) { 405 result = (*muteSoloItf)->SetChannelSolo(muteSoloItf, chan, solo); 406 assert(SL_RESULT_SUCCESS == result); 407 (void)result; 408 } 409 } 410 411 int Java_com_example_nativeaudio_NativeAudio_getNumChannelsUriAudioPlayer(JNIEnv* env, jclass clazz) 412 { 413 SLuint8 numChannels; 414 SLresult result; 415 SLMuteSoloItf muteSoloItf = getMuteSolo(); 416 if (NULL != muteSoloItf) { 417 result = (*muteSoloItf)->GetNumChannels(muteSoloItf, &numChannels); 418 if (SL_RESULT_PRECONDITIONS_VIOLATED == result) { 419 // channel count is not yet known 420 numChannels = 0; 421 } else { 422 assert(SL_RESULT_SUCCESS == result); 423 } 424 } else { 425 numChannels = 0; 426 } 427 return numChannels; 428 } 429 430 // expose the volume APIs to Java for one of the 3 players 431 432 static SLVolumeItf getVolume() 433 { 434 if (uriPlayerVolume != NULL) 435 return uriPlayerVolume; 436 else if (fdPlayerVolume != NULL) 437 return fdPlayerVolume; 438 else 439 return bqPlayerVolume; 440 } 441 442 void Java_com_example_nativeaudio_NativeAudio_setVolumeUriAudioPlayer(JNIEnv* env, jclass clazz, 443 jint millibel) 444 { 445 SLresult result; 446 SLVolumeItf volumeItf = getVolume(); 447 if (NULL != volumeItf) { 448 result = (*volumeItf)->SetVolumeLevel(volumeItf, millibel); 449 assert(SL_RESULT_SUCCESS == result); 450 (void)result; 451 } 452 } 453 454 void Java_com_example_nativeaudio_NativeAudio_setMuteUriAudioPlayer(JNIEnv* env, jclass clazz, 455 jboolean mute) 456 { 457 SLresult result; 458 SLVolumeItf volumeItf = getVolume(); 459 if (NULL != volumeItf) { 460 result = (*volumeItf)->SetMute(volumeItf, mute); 461 assert(SL_RESULT_SUCCESS == result); 462 (void)result; 463 } 464 } 465 466 void Java_com_example_nativeaudio_NativeAudio_enableStereoPositionUriAudioPlayer(JNIEnv* env, 467 jclass clazz, jboolean enable) 468 { 469 SLresult result; 470 SLVolumeItf volumeItf = getVolume(); 471 if (NULL != volumeItf) { 472 result = (*volumeItf)->EnableStereoPosition(volumeItf, enable); 473 assert(SL_RESULT_SUCCESS == result); 474 (void)result; 475 } 476 } 477 478 void Java_com_example_nativeaudio_NativeAudio_setStereoPositionUriAudioPlayer(JNIEnv* env, 479 jclass clazz, jint permille) 480 { 481 SLresult result; 482 SLVolumeItf volumeItf = getVolume(); 483 if (NULL != volumeItf) { 484 result = (*volumeItf)->SetStereoPosition(volumeItf, permille); 485 assert(SL_RESULT_SUCCESS == result); 486 (void)result; 487 } 488 } 489 490 // enable reverb on the buffer queue player 491 jboolean Java_com_example_nativeaudio_NativeAudio_enableReverb(JNIEnv* env, jclass clazz, 492 jboolean enabled) 493 { 494 SLresult result; 495 496 // we might not have been able to add environmental reverb to the output mix 497 if (NULL == outputMixEnvironmentalReverb) { 498 return JNI_FALSE; 499 } 500 501 result = (*bqPlayerEffectSend)->EnableEffectSend(bqPlayerEffectSend, 502 outputMixEnvironmentalReverb, (SLboolean) enabled, (SLmillibel) 0); 503 // and even if environmental reverb was present, it might no longer be available 504 if (SL_RESULT_SUCCESS != result) { 505 return JNI_FALSE; 506 } 507 508 return JNI_TRUE; 509 } 510 511 512 // select the desired clip and play count, and enqueue the first buffer if idle 513 jboolean Java_com_example_nativeaudio_NativeAudio_selectClip(JNIEnv* env, jclass clazz, jint which, 514 jint count) 515 { 516 switch (which) { 517 case 0: // CLIP_NONE 518 nextBuffer = (short *) NULL; 519 nextSize = 0; 520 break; 521 case 1: // CLIP_HELLO 522 nextBuffer = (short *) hello; 523 nextSize = sizeof(hello); 524 break; 525 case 2: // CLIP_ANDROID 526 nextBuffer = (short *) android; 527 nextSize = sizeof(android); 528 break; 529 case 3: // CLIP_SAWTOOTH 530 nextBuffer = sawtoothBuffer; 531 nextSize = sizeof(sawtoothBuffer); 532 break; 533 case 4: // CLIP_PLAYBACK 534 // we recorded at 16 kHz, but are playing buffers at 8 Khz, so do a primitive down-sample 535 if (recorderSR == SL_SAMPLINGRATE_16) { 536 unsigned i; 537 for (i = 0; i < recorderSize; i += 2 * sizeof(short)) { 538 recorderBuffer[i >> 2] = recorderBuffer[i >> 1]; 539 } 540 recorderSR = SL_SAMPLINGRATE_8; 541 recorderSize >>= 1; 542 } 543 nextBuffer = recorderBuffer; 544 nextSize = recorderSize; 545 break; 546 default: 547 nextBuffer = NULL; 548 nextSize = 0; 549 break; 550 } 551 nextCount = count; 552 if (nextSize > 0) { 553 // here we only enqueue one buffer because it is a long clip, 554 // but for streaming playback we would typically enqueue at least 2 buffers to start 555 SLresult result; 556 result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize); 557 if (SL_RESULT_SUCCESS != result) { 558 return JNI_FALSE; 559 } 560 } 561 562 return JNI_TRUE; 563 } 564 565 566 // create asset audio player 567 jboolean Java_com_example_nativeaudio_NativeAudio_createAssetAudioPlayer(JNIEnv* env, jclass clazz, 568 jobject assetManager, jstring filename) 569 { 570 SLresult result; 571 572 // convert Java string to UTF-8 573 const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL); 574 assert(NULL != utf8); 575 576 // use asset manager to open asset by filename 577 AAssetManager* mgr = AAssetManager_fromJava(env, assetManager); 578 assert(NULL != mgr); 579 AAsset* asset = AAssetManager_open(mgr, utf8, AASSET_MODE_UNKNOWN); 580 581 // release the Java string and UTF-8 582 (*env)->ReleaseStringUTFChars(env, filename, utf8); 583 584 // the asset might not be found 585 if (NULL == asset) { 586 return JNI_FALSE; 587 } 588 589 // open asset as file descriptor 590 off_t start, length; 591 int fd = AAsset_openFileDescriptor(asset, &start, &length); 592 assert(0 <= fd); 593 AAsset_close(asset); 594 595 // configure audio source 596 SLDataLocator_AndroidFD loc_fd = {SL_DATALOCATOR_ANDROIDFD, fd, start, length}; 597 SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; 598 SLDataSource audioSrc = {&loc_fd, &format_mime}; 599 600 // configure audio sink 601 SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; 602 SLDataSink audioSnk = {&loc_outmix, NULL}; 603 604 // create audio player 605 const SLInterfaceID ids[3] = {SL_IID_SEEK, SL_IID_MUTESOLO, SL_IID_VOLUME}; 606 const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 607 result = (*engineEngine)->CreateAudioPlayer(engineEngine, &fdPlayerObject, &audioSrc, &audioSnk, 608 3, ids, req); 609 assert(SL_RESULT_SUCCESS == result); 610 (void)result; 611 612 // realize the player 613 result = (*fdPlayerObject)->Realize(fdPlayerObject, SL_BOOLEAN_FALSE); 614 assert(SL_RESULT_SUCCESS == result); 615 (void)result; 616 617 // get the play interface 618 result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_PLAY, &fdPlayerPlay); 619 assert(SL_RESULT_SUCCESS == result); 620 (void)result; 621 622 // get the seek interface 623 result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_SEEK, &fdPlayerSeek); 624 assert(SL_RESULT_SUCCESS == result); 625 (void)result; 626 627 // get the mute/solo interface 628 result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_MUTESOLO, &fdPlayerMuteSolo); 629 assert(SL_RESULT_SUCCESS == result); 630 (void)result; 631 632 // get the volume interface 633 result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_VOLUME, &fdPlayerVolume); 634 assert(SL_RESULT_SUCCESS == result); 635 (void)result; 636 637 // enable whole file looping 638 result = (*fdPlayerSeek)->SetLoop(fdPlayerSeek, SL_BOOLEAN_TRUE, 0, SL_TIME_UNKNOWN); 639 assert(SL_RESULT_SUCCESS == result); 640 (void)result; 641 642 return JNI_TRUE; 643 } 644 645 646 // set the playing state for the asset audio player 647 void Java_com_example_nativeaudio_NativeAudio_setPlayingAssetAudioPlayer(JNIEnv* env, 648 jclass clazz, jboolean isPlaying) 649 { 650 SLresult result; 651 652 // make sure the asset audio player was created 653 if (NULL != fdPlayerPlay) { 654 655 // set the player's state 656 result = (*fdPlayerPlay)->SetPlayState(fdPlayerPlay, isPlaying ? 657 SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED); 658 assert(SL_RESULT_SUCCESS == result); 659 (void)result; 660 } 661 662 } 663 664 665 // create audio recorder 666 jboolean Java_com_example_nativeaudio_NativeAudio_createAudioRecorder(JNIEnv* env, jclass clazz) 667 { 668 SLresult result; 669 670 // configure audio source 671 SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, 672 SL_DEFAULTDEVICEID_AUDIOINPUT, NULL}; 673 SLDataSource audioSrc = {&loc_dev, NULL}; 674 675 // configure audio sink 676 SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; 677 SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_16, 678 SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, 679 SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN}; 680 SLDataSink audioSnk = {&loc_bq, &format_pcm}; 681 682 // create audio recorder 683 // (requires the RECORD_AUDIO permission) 684 const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; 685 const SLboolean req[1] = {SL_BOOLEAN_TRUE}; 686 result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audioSrc, 687 &audioSnk, 1, id, req); 688 if (SL_RESULT_SUCCESS != result) { 689 return JNI_FALSE; 690 } 691 692 // realize the audio recorder 693 result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE); 694 if (SL_RESULT_SUCCESS != result) { 695 return JNI_FALSE; 696 } 697 698 // get the record interface 699 result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord); 700 assert(SL_RESULT_SUCCESS == result); 701 (void)result; 702 703 // get the buffer queue interface 704 result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 705 &recorderBufferQueue); 706 assert(SL_RESULT_SUCCESS == result); 707 (void)result; 708 709 // register callback on the buffer queue 710 result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback, 711 NULL); 712 assert(SL_RESULT_SUCCESS == result); 713 (void)result; 714 715 return JNI_TRUE; 716 } 717 718 719 // set the recording state for the audio recorder 720 void Java_com_example_nativeaudio_NativeAudio_startRecording(JNIEnv* env, jclass clazz) 721 { 722 SLresult result; 723 724 // in case already recording, stop recording and clear buffer queue 725 result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED); 726 assert(SL_RESULT_SUCCESS == result); 727 (void)result; 728 result = (*recorderBufferQueue)->Clear(recorderBufferQueue); 729 assert(SL_RESULT_SUCCESS == result); 730 (void)result; 731 732 // the buffer is not valid for playback yet 733 recorderSize = 0; 734 735 // enqueue an empty buffer to be filled by the recorder 736 // (for streaming recording, we would enqueue at least 2 empty buffers to start things off) 737 result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, recorderBuffer, 738 RECORDER_FRAMES * sizeof(short)); 739 // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT, 740 // which for this code example would indicate a programming error 741 assert(SL_RESULT_SUCCESS == result); 742 (void)result; 743 744 // start recording 745 result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING); 746 assert(SL_RESULT_SUCCESS == result); 747 (void)result; 748 } 749 750 751 // shut down the native audio system 752 void Java_com_example_nativeaudio_NativeAudio_shutdown(JNIEnv* env, jclass clazz) 753 { 754 755 // destroy buffer queue audio player object, and invalidate all associated interfaces 756 if (bqPlayerObject != NULL) { 757 (*bqPlayerObject)->Destroy(bqPlayerObject); 758 bqPlayerObject = NULL; 759 bqPlayerPlay = NULL; 760 bqPlayerBufferQueue = NULL; 761 bqPlayerEffectSend = NULL; 762 bqPlayerMuteSolo = NULL; 763 bqPlayerVolume = NULL; 764 } 765 766 // destroy file descriptor audio player object, and invalidate all associated interfaces 767 if (fdPlayerObject != NULL) { 768 (*fdPlayerObject)->Destroy(fdPlayerObject); 769 fdPlayerObject = NULL; 770 fdPlayerPlay = NULL; 771 fdPlayerSeek = NULL; 772 fdPlayerMuteSolo = NULL; 773 fdPlayerVolume = NULL; 774 } 775 776 // destroy URI audio player object, and invalidate all associated interfaces 777 if (uriPlayerObject != NULL) { 778 (*uriPlayerObject)->Destroy(uriPlayerObject); 779 uriPlayerObject = NULL; 780 uriPlayerPlay = NULL; 781 uriPlayerSeek = NULL; 782 uriPlayerMuteSolo = NULL; 783 uriPlayerVolume = NULL; 784 } 785 786 // destroy audio recorder object, and invalidate all associated interfaces 787 if (recorderObject != NULL) { 788 (*recorderObject)->Destroy(recorderObject); 789 recorderObject = NULL; 790 recorderRecord = NULL; 791 recorderBufferQueue = NULL; 792 } 793 794 // destroy output mix object, and invalidate all associated interfaces 795 if (outputMixObject != NULL) { 796 (*outputMixObject)->Destroy(outputMixObject); 797 outputMixObject = NULL; 798 outputMixEnvironmentalReverb = NULL; 799 } 800 801 // destroy engine object, and invalidate all associated interfaces 802 if (engineObject != NULL) { 803 (*engineObject)->Destroy(engineObject); 804 engineObject = NULL; 805 engineEngine = NULL; 806 } 807 808 } 809