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