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/* Engine implementation */ 18 19#include "sles_allinclusive.h" 20 21 22static SLresult IEngine_CreateLEDDevice(SLEngineItf self, SLObjectItf *pDevice, SLuint32 deviceID, 23 SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 24{ 25 SL_ENTER_INTERFACE 26 27#if USE_PROFILES & USE_PROFILES_OPTIONAL 28 if ((NULL == pDevice) || (SL_DEFAULTDEVICEID_LED != deviceID)) { 29 result = SL_RESULT_PARAMETER_INVALID; 30 } else { 31 *pDevice = NULL; 32 unsigned exposedMask; 33 const ClassTable *pCLEDDevice_class = objectIDtoClass(SL_OBJECTID_LEDDEVICE); 34 if (NULL == pCLEDDevice_class) { 35 result = SL_RESULT_FEATURE_UNSUPPORTED; 36 } else { 37 result = checkInterfaces(pCLEDDevice_class, numInterfaces, pInterfaceIds, 38 pInterfaceRequired, &exposedMask); 39 } 40 if (SL_RESULT_SUCCESS == result) { 41 CLEDDevice *this = (CLEDDevice *) construct(pCLEDDevice_class, exposedMask, self); 42 if (NULL == this) { 43 result = SL_RESULT_MEMORY_FAILURE; 44 } else { 45 this->mDeviceID = deviceID; 46 IObject_Publish(&this->mObject); 47 // return the new LED object 48 *pDevice = &this->mObject.mItf; 49 } 50 } 51 } 52#else 53 result = SL_RESULT_FEATURE_UNSUPPORTED; 54#endif 55 56 SL_LEAVE_INTERFACE 57} 58 59 60static SLresult IEngine_CreateVibraDevice(SLEngineItf self, SLObjectItf *pDevice, SLuint32 deviceID, 61 SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 62{ 63 SL_ENTER_INTERFACE 64 65#if USE_PROFILES & USE_PROFILES_OPTIONAL 66 if ((NULL == pDevice) || (SL_DEFAULTDEVICEID_VIBRA != deviceID)) { 67 result = SL_RESULT_PARAMETER_INVALID; 68 } else { 69 *pDevice = NULL; 70 unsigned exposedMask; 71 const ClassTable *pCVibraDevice_class = objectIDtoClass(SL_OBJECTID_VIBRADEVICE); 72 if (NULL == pCVibraDevice_class) { 73 result = SL_RESULT_FEATURE_UNSUPPORTED; 74 } else { 75 result = checkInterfaces(pCVibraDevice_class, numInterfaces, 76 pInterfaceIds, pInterfaceRequired, &exposedMask); 77 } 78 if (SL_RESULT_SUCCESS == result) { 79 CVibraDevice *this = (CVibraDevice *) construct(pCVibraDevice_class, exposedMask, self); 80 if (NULL == this) { 81 result = SL_RESULT_MEMORY_FAILURE; 82 } else { 83 this->mDeviceID = deviceID; 84 IObject_Publish(&this->mObject); 85 // return the new vibra object 86 *pDevice = &this->mObject.mItf; 87 } 88 } 89 } 90#else 91 result = SL_RESULT_FEATURE_UNSUPPORTED; 92#endif 93 94 SL_LEAVE_INTERFACE 95} 96 97 98static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer, 99 SLDataSource *pAudioSrc, SLDataSink *pAudioSnk, SLuint32 numInterfaces, 100 const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 101{ 102 SL_ENTER_INTERFACE 103 104 if (NULL == pPlayer) { 105 result = SL_RESULT_PARAMETER_INVALID; 106 } else { 107 *pPlayer = NULL; 108 unsigned exposedMask; 109 const ClassTable *pCAudioPlayer_class = objectIDtoClass(SL_OBJECTID_AUDIOPLAYER); 110 assert(NULL != pCAudioPlayer_class); 111 result = checkInterfaces(pCAudioPlayer_class, numInterfaces, 112 pInterfaceIds, pInterfaceRequired, &exposedMask); 113 if (SL_RESULT_SUCCESS == result) { 114 115 // Construct our new AudioPlayer instance 116 CAudioPlayer *this = (CAudioPlayer *) construct(pCAudioPlayer_class, exposedMask, self); 117 if (NULL == this) { 118 result = SL_RESULT_MEMORY_FAILURE; 119 } else { 120 121 do { 122 123 // Initialize private fields not associated with an interface 124 125 // Default data source in case of failure in checkDataSource 126 this->mDataSource.mLocator.mLocatorType = SL_DATALOCATOR_NULL; 127 this->mDataSource.mFormat.mFormatType = SL_DATAFORMAT_NULL; 128 129 // Default data sink in case of failure in checkDataSink 130 this->mDataSink.mLocator.mLocatorType = SL_DATALOCATOR_NULL; 131 this->mDataSink.mFormat.mFormatType = SL_DATAFORMAT_NULL; 132 133 // Default is no per-channel mute or solo 134 this->mMuteMask = 0; 135 this->mSoloMask = 0; 136 137 // Will be set soon for PCM buffer queues, or later by platform-specific code 138 // during Realize or Prefetch 139 this->mNumChannels = 0; 140 this->mSampleRateMilliHz = 0; 141 142 // More default values, in case destructor needs to be called early 143 this->mDirectLevel = 0; 144#ifdef USE_OUTPUTMIXEXT 145 this->mTrack = NULL; 146 this->mGains[0] = 1.0f; 147 this->mGains[1] = 1.0f; 148 this->mDestroyRequested = SL_BOOLEAN_FALSE; 149#endif 150#ifdef USE_SNDFILE 151 this->mSndFile.mPathname = NULL; 152 this->mSndFile.mSNDFILE = NULL; 153 memset(&this->mSndFile.mSfInfo, 0, sizeof(SF_INFO)); 154 memset(&this->mSndFile.mMutex, 0, sizeof(pthread_mutex_t)); 155 this->mSndFile.mEOF = SL_BOOLEAN_FALSE; 156 this->mSndFile.mWhich = 0; 157 memset(this->mSndFile.mBuffer, 0, sizeof(this->mSndFile.mBuffer)); 158#endif 159#ifdef ANDROID 160 // extra safe initializations of pointers, in case of incomplete construction 161 this->mpLock = NULL; 162 this->mAudioTrack = NULL; 163 // placement new (explicit constructor) 164 (void) new (&this->mSfPlayer) android::sp<android::SfPlayer>(); 165 (void) new (&this->mAuxEffect) android::sp<android::AudioEffect>(); 166#endif 167 168 // Check the source and sink parameters against generic constraints, 169 // and make a local copy of all parameters in case other application threads 170 // change memory concurrently. 171 172 result = checkDataSource(pAudioSrc, &this->mDataSource); 173 if (SL_RESULT_SUCCESS != result) { 174 break; 175 } 176 177 result = checkDataSink(pAudioSnk, &this->mDataSink, SL_OBJECTID_AUDIOPLAYER); 178 if (SL_RESULT_SUCCESS != result) { 179 break; 180 } 181 182 // It would be unsafe to ever refer to the application pointers again 183 pAudioSrc = NULL; 184 pAudioSnk = NULL; 185 186 // Check that the requested interfaces are compatible with the data source 187 result = checkSourceFormatVsInterfacesCompatibility(&this->mDataSource, 188 pCAudioPlayer_class, exposedMask); 189 if (SL_RESULT_SUCCESS != result) { 190 break; 191 } 192 193 // copy the buffer queue count from source locator to the buffer queue interface 194 // we have already range-checked the value down to a smaller width 195 196 switch (this->mDataSource.mLocator.mLocatorType) { 197 case SL_DATALOCATOR_BUFFERQUEUE: 198#ifdef ANDROID 199 case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: 200#endif 201 this->mBufferQueue.mNumBuffers = 202 (SLuint16) this->mDataSource.mLocator.mBufferQueue.numBuffers; 203 assert(SL_DATAFORMAT_PCM == this->mDataSource.mFormat.mFormatType); 204 this->mNumChannels = this->mDataSource.mFormat.mPCM.numChannels; 205 this->mSampleRateMilliHz = this->mDataSource.mFormat.mPCM.samplesPerSec; 206 break; 207 default: 208 this->mBufferQueue.mNumBuffers = 0; 209 break; 210 } 211 212 // check the audio source and sink parameters against platform support 213#ifdef ANDROID 214 result = android_audioPlayer_checkSourceSink(this); 215 if (SL_RESULT_SUCCESS != result) { 216 break; 217 } 218#endif 219 220#ifdef USE_SNDFILE 221 result = SndFile_checkAudioPlayerSourceSink(this); 222 if (SL_RESULT_SUCCESS != result) { 223 break; 224 } 225#endif 226 227#ifdef USE_OUTPUTMIXEXT 228 result = IOutputMixExt_checkAudioPlayerSourceSink(this); 229 if (SL_RESULT_SUCCESS != result) { 230 break; 231 } 232#endif 233 234 // FIXME move to dedicated function 235 // Allocate memory for buffer queue 236 237 //if (0 != this->mBufferQueue.mNumBuffers) { 238 // inline allocation of circular mArray, up to a typical max 239 if (BUFFER_HEADER_TYPICAL >= this->mBufferQueue.mNumBuffers) { 240 this->mBufferQueue.mArray = this->mBufferQueue.mTypical; 241 } else { 242 // Avoid possible integer overflow during multiplication; this arbitrary 243 // maximum is big enough to not interfere with real applications, but 244 // small enough to not overflow. 245 if (this->mBufferQueue.mNumBuffers >= 256) { 246 result = SL_RESULT_MEMORY_FAILURE; 247 break; 248 } 249 this->mBufferQueue.mArray = (BufferHeader *) malloc((this->mBufferQueue. 250 mNumBuffers + 1) * sizeof(BufferHeader)); 251 if (NULL == this->mBufferQueue.mArray) { 252 result = SL_RESULT_MEMORY_FAILURE; 253 break; 254 } 255 } 256 this->mBufferQueue.mFront = this->mBufferQueue.mArray; 257 this->mBufferQueue.mRear = this->mBufferQueue.mArray; 258 //} 259 260 // used to store the data source of our audio player 261 this->mDynamicSource.mDataSource = &this->mDataSource.u.mSource; 262 263 // platform-specific initialization 264#ifdef ANDROID 265 android_audioPlayer_create(this); 266#endif 267 268 } while (0); 269 270 if (SL_RESULT_SUCCESS != result) { 271 IObject_Destroy(&this->mObject.mItf); 272 } else { 273 IObject_Publish(&this->mObject); 274 // return the new audio player object 275 *pPlayer = &this->mObject.mItf; 276 } 277 278 } 279 } 280 281 } 282 283 SL_LEAVE_INTERFACE 284} 285 286 287static SLresult IEngine_CreateAudioRecorder(SLEngineItf self, SLObjectItf *pRecorder, 288 SLDataSource *pAudioSrc, SLDataSink *pAudioSnk, SLuint32 numInterfaces, 289 const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 290{ 291 SL_ENTER_INTERFACE 292 293#if (USE_PROFILES & USE_PROFILES_OPTIONAL) || defined(ANDROID) 294 if (NULL == pRecorder) { 295 result = SL_RESULT_PARAMETER_INVALID; 296 } else { 297 *pRecorder = NULL; 298 unsigned exposedMask; 299 const ClassTable *pCAudioRecorder_class = objectIDtoClass(SL_OBJECTID_AUDIORECORDER); 300 if (NULL == pCAudioRecorder_class) { 301 result = SL_RESULT_FEATURE_UNSUPPORTED; 302 } else { 303 result = checkInterfaces(pCAudioRecorder_class, numInterfaces, 304 pInterfaceIds, pInterfaceRequired, &exposedMask); 305 } 306 307 if (SL_RESULT_SUCCESS == result) { 308 309 // Construct our new AudioRecorder instance 310 CAudioRecorder *this = (CAudioRecorder *) construct(pCAudioRecorder_class, exposedMask, 311 self); 312 if (NULL == this) { 313 result = SL_RESULT_MEMORY_FAILURE; 314 } else { 315 316 do { 317 318 // Initialize fields not associated with any interface 319 320 // Default data source in case of failure in checkDataSource 321 this->mDataSource.mLocator.mLocatorType = SL_DATALOCATOR_NULL; 322 this->mDataSource.mFormat.mFormatType = SL_DATAFORMAT_NULL; 323 324 // Default data sink in case of failure in checkDataSink 325 this->mDataSink.mLocator.mLocatorType = SL_DATALOCATOR_NULL; 326 this->mDataSink.mFormat.mFormatType = SL_DATAFORMAT_NULL; 327 328 // These fields are set to real values by 329 // android_audioRecorder_checkSourceSinkSupport. Note that the data sink is 330 // always PCM buffer queue, so we know the channel count and sample rate early. 331 this->mNumChannels = 0; 332 this->mSampleRateMilliHz = 0; 333#ifdef ANDROID 334 this->mAudioRecord = NULL; 335 this->mRecordSource = android::AUDIO_SOURCE_DEFAULT; 336#endif 337 338 // Check the source and sink parameters, and make a local copy of all parameters 339 result = checkDataSource(pAudioSrc, &this->mDataSource); 340 if (SL_RESULT_SUCCESS != result) { 341 break; 342 } 343 result = checkDataSink(pAudioSnk, &this->mDataSink, SL_OBJECTID_AUDIORECORDER); 344 if (SL_RESULT_SUCCESS != result) { 345 break; 346 } 347 348 // It would be unsafe to ever refer to the application pointers again 349 pAudioSrc = NULL; 350 pAudioSnk = NULL; 351 352 // check the audio source and sink parameters against platform support 353#ifdef ANDROID 354 result = android_audioRecorder_checkSourceSinkSupport(this); 355 if (SL_RESULT_SUCCESS != result) { 356 SL_LOGE("Cannot create AudioRecorder: invalid source or sink"); 357 break; 358 } 359#endif 360 361#ifdef ANDROID 362 // Allocate memory for buffer queue 363 SLuint32 locatorType = this->mDataSink.mLocator.mLocatorType; 364 if (locatorType == SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE) { 365 this->mBufferQueue.mNumBuffers = 366 this->mDataSink.mLocator.mBufferQueue.numBuffers; 367 // inline allocation of circular Buffer Queue mArray, up to a typical max 368 if (BUFFER_HEADER_TYPICAL >= this->mBufferQueue.mNumBuffers) { 369 this->mBufferQueue.mArray = this->mBufferQueue.mTypical; 370 } else { 371 // Avoid possible integer overflow during multiplication; this arbitrary 372 // maximum is big enough to not interfere with real applications, but 373 // small enough to not overflow. 374 if (this->mBufferQueue.mNumBuffers >= 256) { 375 result = SL_RESULT_MEMORY_FAILURE; 376 break; 377 } 378 this->mBufferQueue.mArray = (BufferHeader *) malloc((this->mBufferQueue. 379 mNumBuffers + 1) * sizeof(BufferHeader)); 380 if (NULL == this->mBufferQueue.mArray) { 381 result = SL_RESULT_MEMORY_FAILURE; 382 break; 383 } 384 } 385 this->mBufferQueue.mFront = this->mBufferQueue.mArray; 386 this->mBufferQueue.mRear = this->mBufferQueue.mArray; 387 } 388#endif 389 390 // platform-specific initialization 391#ifdef ANDROID 392 android_audioRecorder_create(this); 393#endif 394 395 } while (0); 396 397 if (SL_RESULT_SUCCESS != result) { 398 IObject_Destroy(&this->mObject.mItf); 399 } else { 400 IObject_Publish(&this->mObject); 401 // return the new audio recorder object 402 *pRecorder = &this->mObject.mItf; 403 } 404 } 405 406 } 407 408 } 409#else 410 result = SL_RESULT_FEATURE_UNSUPPORTED; 411#endif 412 413 SL_LEAVE_INTERFACE 414} 415 416 417static SLresult IEngine_CreateMidiPlayer(SLEngineItf self, SLObjectItf *pPlayer, 418 SLDataSource *pMIDISrc, SLDataSource *pBankSrc, SLDataSink *pAudioOutput, 419 SLDataSink *pVibra, SLDataSink *pLEDArray, SLuint32 numInterfaces, 420 const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 421{ 422 SL_ENTER_INTERFACE 423 424#if USE_PROFILES & (USE_PROFILES_GAME | USE_PROFILES_PHONE) 425 if ((NULL == pPlayer) || (NULL == pMIDISrc) || (NULL == pAudioOutput)) { 426 result = SL_RESULT_PARAMETER_INVALID; 427 } else { 428 *pPlayer = NULL; 429 unsigned exposedMask; 430 const ClassTable *pCMidiPlayer_class = objectIDtoClass(SL_OBJECTID_MIDIPLAYER); 431 if (NULL == pCMidiPlayer_class) { 432 result = SL_RESULT_FEATURE_UNSUPPORTED; 433 } else { 434 result = checkInterfaces(pCMidiPlayer_class, numInterfaces, 435 pInterfaceIds, pInterfaceRequired, &exposedMask); 436 } 437 if (SL_RESULT_SUCCESS == result) { 438 CMidiPlayer *this = (CMidiPlayer *) construct(pCMidiPlayer_class, exposedMask, self); 439 if (NULL == this) { 440 result = SL_RESULT_MEMORY_FAILURE; 441 } else { 442 // FIXME a fake value - why not use value from IPlay_init? what does CT check for? 443 this->mPlay.mDuration = 0; 444 IObject_Publish(&this->mObject); 445 // return the new MIDI player object 446 *pPlayer = &this->mObject.mItf; 447 } 448 } 449 } 450#else 451 result = SL_RESULT_FEATURE_UNSUPPORTED; 452#endif 453 454 SL_LEAVE_INTERFACE 455} 456 457 458static SLresult IEngine_CreateListener(SLEngineItf self, SLObjectItf *pListener, 459 SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 460{ 461 SL_ENTER_INTERFACE 462 463#if USE_PROFILES & USE_PROFILES_GAME 464 if (NULL == pListener) { 465 result = SL_RESULT_PARAMETER_INVALID; 466 } else { 467 *pListener = NULL; 468 unsigned exposedMask; 469 const ClassTable *pCListener_class = objectIDtoClass(SL_OBJECTID_LISTENER); 470 if (NULL == pCListener_class) { 471 result = SL_RESULT_FEATURE_UNSUPPORTED; 472 } else { 473 result = checkInterfaces(pCListener_class, numInterfaces, 474 pInterfaceIds, pInterfaceRequired, &exposedMask); 475 } 476 if (SL_RESULT_SUCCESS == result) { 477 CListener *this = (CListener *) construct(pCListener_class, exposedMask, self); 478 if (NULL == this) { 479 result = SL_RESULT_MEMORY_FAILURE; 480 } else { 481 IObject_Publish(&this->mObject); 482 // return the new 3D listener object 483 *pListener = &this->mObject.mItf; 484 } 485 } 486 } 487#else 488 result = SL_RESULT_FEATURE_UNSUPPORTED; 489#endif 490 491 SL_LEAVE_INTERFACE 492} 493 494 495static SLresult IEngine_Create3DGroup(SLEngineItf self, SLObjectItf *pGroup, SLuint32 numInterfaces, 496 const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 497{ 498 SL_ENTER_INTERFACE 499 500#if USE_PROFILES & USE_PROFILES_GAME 501 if (NULL == pGroup) { 502 result = SL_RESULT_PARAMETER_INVALID; 503 } else { 504 *pGroup = NULL; 505 unsigned exposedMask; 506 const ClassTable *pC3DGroup_class = objectIDtoClass(SL_OBJECTID_3DGROUP); 507 if (NULL == pC3DGroup_class) { 508 result = SL_RESULT_FEATURE_UNSUPPORTED; 509 } else { 510 result = checkInterfaces(pC3DGroup_class, numInterfaces, 511 pInterfaceIds, pInterfaceRequired, &exposedMask); 512 } 513 if (SL_RESULT_SUCCESS == result) { 514 C3DGroup *this = (C3DGroup *) construct(pC3DGroup_class, exposedMask, self); 515 if (NULL == this) { 516 result = SL_RESULT_MEMORY_FAILURE; 517 } else { 518 this->mMemberMask = 0; 519 IObject_Publish(&this->mObject); 520 // return the new 3D group object 521 *pGroup = &this->mObject.mItf; 522 } 523 } 524 } 525#else 526 result = SL_RESULT_FEATURE_UNSUPPORTED; 527#endif 528 529 SL_LEAVE_INTERFACE 530} 531 532 533static SLresult IEngine_CreateOutputMix(SLEngineItf self, SLObjectItf *pMix, SLuint32 numInterfaces, 534 const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 535{ 536 SL_ENTER_INTERFACE 537 538 if (NULL == pMix) { 539 result = SL_RESULT_PARAMETER_INVALID; 540 } else { 541 *pMix = NULL; 542 unsigned exposedMask; 543 const ClassTable *pCOutputMix_class = objectIDtoClass(SL_OBJECTID_OUTPUTMIX); 544 assert(NULL != pCOutputMix_class); 545 result = checkInterfaces(pCOutputMix_class, numInterfaces, 546 pInterfaceIds, pInterfaceRequired, &exposedMask); 547 if (SL_RESULT_SUCCESS == result) { 548 COutputMix *this = (COutputMix *) construct(pCOutputMix_class, exposedMask, self); 549 if (NULL == this) { 550 result = SL_RESULT_MEMORY_FAILURE; 551 } else { 552#ifdef ANDROID 553 android_outputMix_create(this); 554#endif 555#ifdef USE_SDL 556 IEngine *thisEngine = this->mObject.mEngine; 557 interface_lock_exclusive(thisEngine); 558 bool unpause = false; 559 if (NULL == thisEngine->mOutputMix) { 560 thisEngine->mOutputMix = this; 561 unpause = true; 562 } 563 interface_unlock_exclusive(thisEngine); 564#endif 565 IObject_Publish(&this->mObject); 566#ifdef USE_SDL 567 if (unpause) { 568 // Enable SDL_callback to be called periodically by SDL's internal thread 569 SDL_PauseAudio(0); 570 } 571#endif 572 // return the new output mix object 573 *pMix = &this->mObject.mItf; 574 } 575 } 576 } 577 578 SL_LEAVE_INTERFACE 579} 580 581 582static SLresult IEngine_CreateMetadataExtractor(SLEngineItf self, SLObjectItf *pMetadataExtractor, 583 SLDataSource *pDataSource, SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, 584 const SLboolean *pInterfaceRequired) 585{ 586 SL_ENTER_INTERFACE 587 588#if USE_PROFILES & (USE_PROFILES_GAME | USE_PROFILES_MUSIC) 589 if (NULL == pMetadataExtractor) { 590 result = SL_RESULT_PARAMETER_INVALID; 591 } else { 592 *pMetadataExtractor = NULL; 593 unsigned exposedMask; 594 const ClassTable *pCMetadataExtractor_class = 595 objectIDtoClass(SL_OBJECTID_METADATAEXTRACTOR); 596 if (NULL == pCMetadataExtractor_class) { 597 result = SL_RESULT_FEATURE_UNSUPPORTED; 598 } else { 599 result = checkInterfaces(pCMetadataExtractor_class, numInterfaces, 600 pInterfaceIds, pInterfaceRequired, &exposedMask); 601 } 602 if (SL_RESULT_SUCCESS == result) { 603 CMetadataExtractor *this = (CMetadataExtractor *) 604 construct(pCMetadataExtractor_class, exposedMask, self); 605 if (NULL == this) { 606 result = SL_RESULT_MEMORY_FAILURE; 607 } else { 608 IObject_Publish(&this->mObject); 609 // return the new metadata extractor object 610 *pMetadataExtractor = &this->mObject.mItf; 611 result = SL_RESULT_SUCCESS; 612 } 613 } 614 } 615#else 616 result = SL_RESULT_FEATURE_UNSUPPORTED; 617#endif 618 619 SL_LEAVE_INTERFACE 620} 621 622 623static SLresult IEngine_CreateExtensionObject(SLEngineItf self, SLObjectItf *pObject, 624 void *pParameters, SLuint32 objectID, SLuint32 numInterfaces, 625 const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 626{ 627 SL_ENTER_INTERFACE 628 629 if (NULL == pObject) { 630 result = SL_RESULT_PARAMETER_INVALID; 631 } else { 632 *pObject = NULL; 633 result = SL_RESULT_FEATURE_UNSUPPORTED; 634 } 635 636 SL_LEAVE_INTERFACE 637} 638 639 640static SLresult IEngine_QueryNumSupportedInterfaces(SLEngineItf self, 641 SLuint32 objectID, SLuint32 *pNumSupportedInterfaces) 642{ 643 SL_ENTER_INTERFACE 644 645 if (NULL == pNumSupportedInterfaces) { 646 result = SL_RESULT_PARAMETER_INVALID; 647 } else { 648 const ClassTable *class__ = objectIDtoClass(objectID); 649 if (NULL == class__) { 650 result = SL_RESULT_FEATURE_UNSUPPORTED; 651 } else { 652 SLuint32 count = 0; 653 SLuint32 i; 654 for (i = 0; i < class__->mInterfaceCount; ++i) { 655 switch (class__->mInterfaces[i].mInterface) { 656 case INTERFACE_IMPLICIT: 657 case INTERFACE_IMPLICIT_PREREALIZE: 658 case INTERFACE_EXPLICIT: 659 case INTERFACE_EXPLICIT_PREREALIZE: 660 case INTERFACE_DYNAMIC: 661 ++count; 662 break; 663 case INTERFACE_UNAVAILABLE: 664 break; 665 default: 666 assert(false); 667 break; 668 } 669 } 670 *pNumSupportedInterfaces = count; 671 result = SL_RESULT_SUCCESS; 672 } 673 } 674 675 SL_LEAVE_INTERFACE; 676} 677 678 679static SLresult IEngine_QuerySupportedInterfaces(SLEngineItf self, 680 SLuint32 objectID, SLuint32 index, SLInterfaceID *pInterfaceId) 681{ 682 SL_ENTER_INTERFACE 683 684 if (NULL == pInterfaceId) { 685 result = SL_RESULT_PARAMETER_INVALID; 686 } else { 687 *pInterfaceId = NULL; 688 const ClassTable *class__ = objectIDtoClass(objectID); 689 if (NULL == class__) { 690 result = SL_RESULT_FEATURE_UNSUPPORTED; 691 } else { 692 result = SL_RESULT_PARAMETER_INVALID; // will be reset later 693 SLuint32 i; 694 for (i = 0; i < class__->mInterfaceCount; ++i) { 695 switch (class__->mInterfaces[i].mInterface) { 696 case INTERFACE_IMPLICIT: 697 case INTERFACE_IMPLICIT_PREREALIZE: 698 case INTERFACE_EXPLICIT: 699 case INTERFACE_EXPLICIT_PREREALIZE: 700 case INTERFACE_DYNAMIC: 701 break; 702 case INTERFACE_UNAVAILABLE: 703 continue; 704 default: 705 assert(false); 706 break; 707 } 708 if (index == 0) { 709 *pInterfaceId = &SL_IID_array[class__->mInterfaces[i].mMPH]; 710 result = SL_RESULT_SUCCESS; 711 break; 712 } 713 --index; 714 } 715 } 716 } 717 718 SL_LEAVE_INTERFACE 719}; 720 721 722static const char * const extensionNames[] = { 723#ifdef ANDROID 724 "ANDROID_SDK_LEVEL_9", // Android 2.3 aka "Gingerbread" 725 // in the future, add more entries for each SDK level here, and 726 // don't delete the entries for previous SDK levels unless support is removed 727#else 728 "WILHELM_DESKTOP", 729#endif 730}; 731 732 733static SLresult IEngine_QueryNumSupportedExtensions(SLEngineItf self, SLuint32 *pNumExtensions) 734{ 735 SL_ENTER_INTERFACE 736 737 if (NULL == pNumExtensions) { 738 result = SL_RESULT_PARAMETER_INVALID; 739 } else { 740 *pNumExtensions = sizeof(extensionNames) / sizeof(extensionNames[0]); 741 result = SL_RESULT_SUCCESS; 742 } 743 744 SL_LEAVE_INTERFACE 745} 746 747 748static SLresult IEngine_QuerySupportedExtension(SLEngineItf self, 749 SLuint32 index, SLchar *pExtensionName, SLint16 *pNameLength) 750{ 751 SL_ENTER_INTERFACE 752 753 if (NULL == pNameLength) { 754 result = SL_RESULT_PARAMETER_INVALID; 755 } else { 756 size_t actualNameLength; 757 unsigned numExtensions = sizeof(extensionNames) / sizeof(extensionNames[0]); 758 if (index >= numExtensions) { 759 actualNameLength = 0; 760 result = SL_RESULT_PARAMETER_INVALID; 761 } else { 762 const char *extensionName = extensionNames[index]; 763 actualNameLength = strlen(extensionName) + 1; 764 if (NULL == pExtensionName) { 765 // application is querying the name length in order to allocate a buffer 766 result = SL_RESULT_SUCCESS; 767 } else { 768 SLint16 availableNameLength = *pNameLength; 769 if (0 >= availableNameLength) { 770 // there is not even room for the terminating NUL 771 result = SL_RESULT_BUFFER_INSUFFICIENT; 772 } else if (actualNameLength > (size_t) availableNameLength) { 773 // "no invalid strings are written. That is, the null-terminator always exists" 774 memcpy(pExtensionName, extensionName, (size_t) availableNameLength - 1); 775 pExtensionName[(size_t) availableNameLength - 1] = '\0'; 776 result = SL_RESULT_BUFFER_INSUFFICIENT; 777 } else { 778 memcpy(pExtensionName, extensionName, actualNameLength); 779 result = SL_RESULT_SUCCESS; 780 } 781 } 782 } 783 *pNameLength = actualNameLength; 784 } 785 786 SL_LEAVE_INTERFACE 787} 788 789 790static SLresult IEngine_IsExtensionSupported(SLEngineItf self, 791 const SLchar *pExtensionName, SLboolean *pSupported) 792{ 793 SL_ENTER_INTERFACE 794 795 if (NULL == pSupported) { 796 result = SL_RESULT_PARAMETER_INVALID; 797 } else { 798 SLboolean isSupported = SL_BOOLEAN_FALSE; 799 if (NULL == pExtensionName) { 800 result = SL_RESULT_PARAMETER_INVALID; 801 } else { 802 unsigned numExtensions = sizeof(extensionNames) / sizeof(extensionNames[0]); 803 unsigned i; 804 for (i = 0; i < numExtensions; ++i) { 805 if (!strcmp((const char *) pExtensionName, extensionNames[i])) { 806 isSupported = SL_BOOLEAN_TRUE; 807 break; 808 } 809 } 810 result = SL_RESULT_SUCCESS; 811 } 812 *pSupported = isSupported; 813 } 814 815 SL_LEAVE_INTERFACE 816} 817 818 819static const struct SLEngineItf_ IEngine_Itf = { 820 IEngine_CreateLEDDevice, 821 IEngine_CreateVibraDevice, 822 IEngine_CreateAudioPlayer, 823 IEngine_CreateAudioRecorder, 824 IEngine_CreateMidiPlayer, 825 IEngine_CreateListener, 826 IEngine_Create3DGroup, 827 IEngine_CreateOutputMix, 828 IEngine_CreateMetadataExtractor, 829 IEngine_CreateExtensionObject, 830 IEngine_QueryNumSupportedInterfaces, 831 IEngine_QuerySupportedInterfaces, 832 IEngine_QueryNumSupportedExtensions, 833 IEngine_QuerySupportedExtension, 834 IEngine_IsExtensionSupported 835}; 836 837void IEngine_init(void *self) 838{ 839 IEngine *this = (IEngine *) self; 840 this->mItf = &IEngine_Itf; 841 // mLossOfControlGlobal is initialized in slCreateEngine 842#ifdef USE_SDL 843 this->mOutputMix = NULL; 844#endif 845 this->mInstanceCount = 1; // ourself 846 this->mInstanceMask = 0; 847 this->mChangedMask = 0; 848 unsigned i; 849 for (i = 0; i < MAX_INSTANCE; ++i) { 850 this->mInstances[i] = NULL; 851 } 852 this->mShutdown = SL_BOOLEAN_FALSE; 853 this->mShutdownAck = SL_BOOLEAN_FALSE; 854 // mThreadPool is initialized in CEngine_Realize 855 memset(&this->mThreadPool, 0, sizeof(ThreadPool)); 856#if defined(ANDROID) && !defined(USE_BACKPORT) 857 this->mEqNumPresets = 0; 858 this->mEqPresetNames = NULL; 859#endif 860} 861 862void IEngine_deinit(void *self) 863{ 864#if defined(ANDROID) && !defined(USE_BACKPORT) 865 IEngine *this = (IEngine *) self; 866 // free equalizer preset names 867 if (NULL != this->mEqPresetNames) { 868 for (unsigned i = 0; i < this->mEqNumPresets; ++i) { 869 if (NULL != this->mEqPresetNames[i]) { 870 delete[] this->mEqPresetNames[i]; 871 this->mEqPresetNames[i] = NULL; 872 } 873 } 874 delete[] this->mEqPresetNames; 875 this->mEqPresetNames = NULL; 876 } 877 this->mEqNumPresets = 0; 878#endif 879} 880