IEngine.c revision c869defb7c0dd6f4e45ad26abb0f8ccc960152de
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", pAudioSrc, &this->mDataSource, 173 DATALOCATOR_MASK_URI | DATALOCATOR_MASK_ADDRESS | 174 DATALOCATOR_MASK_BUFFERQUEUE 175#ifdef ANDROID 176 | DATALOCATOR_MASK_ANDROIDFD | DATALOCATOR_MASK_ANDROIDSIMPLEBUFFERQUEUE 177 | DATALOCATOR_MASK_ANDROIDBUFFERQUEUE 178#endif 179 , DATAFORMAT_MASK_MIME | DATAFORMAT_MASK_PCM); 180 181 if (SL_RESULT_SUCCESS != result) { 182 break; 183 } 184 185 result = checkDataSink("pAudioSnk", pAudioSnk, &this->mDataSink, 186 DATALOCATOR_MASK_OUTPUTMIX, DATAFORMAT_MASK_NULL); 187 if (SL_RESULT_SUCCESS != result) { 188 break; 189 } 190 191 // It would be unsafe to ever refer to the application pointers again 192 pAudioSrc = NULL; 193 pAudioSnk = NULL; 194 195 // Check that the requested interfaces are compatible with the data source 196 result = checkSourceFormatVsInterfacesCompatibility(&this->mDataSource, 197 pCAudioPlayer_class, exposedMask); 198 if (SL_RESULT_SUCCESS != result) { 199 break; 200 } 201 202 // copy the buffer queue count from source locator to the buffer queue interface 203 // we have already range-checked the value down to a smaller width 204 205 switch (this->mDataSource.mLocator.mLocatorType) { 206 case SL_DATALOCATOR_BUFFERQUEUE: 207#ifdef ANDROID 208 case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: 209#endif 210 this->mBufferQueue.mNumBuffers = 211 (SLuint16) this->mDataSource.mLocator.mBufferQueue.numBuffers; 212 assert(SL_DATAFORMAT_PCM == this->mDataSource.mFormat.mFormatType); 213 this->mNumChannels = this->mDataSource.mFormat.mPCM.numChannels; 214 this->mSampleRateMilliHz = this->mDataSource.mFormat.mPCM.samplesPerSec; 215 break; 216 default: 217 this->mBufferQueue.mNumBuffers = 0; 218 break; 219 } 220 221 // check the audio source and sink parameters against platform support 222#ifdef ANDROID 223 result = android_audioPlayer_checkSourceSink(this); 224 if (SL_RESULT_SUCCESS != result) { 225 break; 226 } 227#endif 228 229#ifdef USE_SNDFILE 230 result = SndFile_checkAudioPlayerSourceSink(this); 231 if (SL_RESULT_SUCCESS != result) { 232 break; 233 } 234#endif 235 236#ifdef USE_OUTPUTMIXEXT 237 result = IOutputMixExt_checkAudioPlayerSourceSink(this); 238 if (SL_RESULT_SUCCESS != result) { 239 break; 240 } 241#endif 242 243 // FIXME move to dedicated function 244 // Allocate memory for buffer queue 245 246 //if (0 != this->mBufferQueue.mNumBuffers) { 247 // inline allocation of circular mArray, up to a typical max 248 if (BUFFER_HEADER_TYPICAL >= this->mBufferQueue.mNumBuffers) { 249 this->mBufferQueue.mArray = this->mBufferQueue.mTypical; 250 } else { 251 // Avoid possible integer overflow during multiplication; this arbitrary 252 // maximum is big enough to not interfere with real applications, but 253 // small enough to not overflow. 254 if (this->mBufferQueue.mNumBuffers >= 256) { 255 result = SL_RESULT_MEMORY_FAILURE; 256 break; 257 } 258 this->mBufferQueue.mArray = (BufferHeader *) malloc((this->mBufferQueue. 259 mNumBuffers + 1) * sizeof(BufferHeader)); 260 if (NULL == this->mBufferQueue.mArray) { 261 result = SL_RESULT_MEMORY_FAILURE; 262 break; 263 } 264 } 265 this->mBufferQueue.mFront = this->mBufferQueue.mArray; 266 this->mBufferQueue.mRear = this->mBufferQueue.mArray; 267 //} 268 269 // used to store the data source of our audio player 270 this->mDynamicSource.mDataSource = &this->mDataSource.u.mSource; 271 272 // platform-specific initialization 273#ifdef ANDROID 274 android_audioPlayer_create(this); 275#endif 276 277 } while (0); 278 279 if (SL_RESULT_SUCCESS != result) { 280 IObject_Destroy(&this->mObject.mItf); 281 } else { 282 IObject_Publish(&this->mObject); 283 // return the new audio player object 284 *pPlayer = &this->mObject.mItf; 285 } 286 287 } 288 } 289 290 } 291 292 SL_LEAVE_INTERFACE 293} 294 295 296static SLresult IEngine_CreateAudioRecorder(SLEngineItf self, SLObjectItf *pRecorder, 297 SLDataSource *pAudioSrc, SLDataSink *pAudioSnk, SLuint32 numInterfaces, 298 const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 299{ 300 SL_ENTER_INTERFACE 301 302#if (USE_PROFILES & USE_PROFILES_OPTIONAL) || defined(ANDROID) 303 if (NULL == pRecorder) { 304 result = SL_RESULT_PARAMETER_INVALID; 305 } else { 306 *pRecorder = NULL; 307 unsigned exposedMask; 308 const ClassTable *pCAudioRecorder_class = objectIDtoClass(SL_OBJECTID_AUDIORECORDER); 309 if (NULL == pCAudioRecorder_class) { 310 result = SL_RESULT_FEATURE_UNSUPPORTED; 311 } else { 312 result = checkInterfaces(pCAudioRecorder_class, numInterfaces, 313 pInterfaceIds, pInterfaceRequired, &exposedMask); 314 } 315 316 if (SL_RESULT_SUCCESS == result) { 317 318 // Construct our new AudioRecorder instance 319 CAudioRecorder *this = (CAudioRecorder *) construct(pCAudioRecorder_class, exposedMask, 320 self); 321 if (NULL == this) { 322 result = SL_RESULT_MEMORY_FAILURE; 323 } else { 324 325 do { 326 327 // Initialize fields not associated with any interface 328 329 // Default data source in case of failure in checkDataSource 330 this->mDataSource.mLocator.mLocatorType = SL_DATALOCATOR_NULL; 331 this->mDataSource.mFormat.mFormatType = SL_DATAFORMAT_NULL; 332 333 // Default data sink in case of failure in checkDataSink 334 this->mDataSink.mLocator.mLocatorType = SL_DATALOCATOR_NULL; 335 this->mDataSink.mFormat.mFormatType = SL_DATAFORMAT_NULL; 336 337 // These fields are set to real values by 338 // android_audioRecorder_checkSourceSinkSupport. Note that the data sink is 339 // always PCM buffer queue, so we know the channel count and sample rate early. 340 this->mNumChannels = 0; 341 this->mSampleRateMilliHz = 0; 342#ifdef ANDROID 343 this->mAudioRecord = NULL; 344 this->mRecordSource = android::AUDIO_SOURCE_DEFAULT; 345#endif 346 347 // Check the source and sink parameters, and make a local copy of all parameters 348 result = checkDataSource("pAudioSrc", pAudioSrc, &this->mDataSource, 349 DATALOCATOR_MASK_IODEVICE, DATAFORMAT_MASK_NULL); 350 if (SL_RESULT_SUCCESS != result) { 351 break; 352 } 353 result = checkDataSink("pAudioSnk", pAudioSnk, &this->mDataSink, 354 DATALOCATOR_MASK_URI 355#ifdef ANDROID 356 | DATALOCATOR_MASK_ANDROIDSIMPLEBUFFERQUEUE 357#endif 358 , DATAFORMAT_MASK_MIME | DATAFORMAT_MASK_PCM 359 ); 360 if (SL_RESULT_SUCCESS != result) { 361 break; 362 } 363 364 // It would be unsafe to ever refer to the application pointers again 365 pAudioSrc = NULL; 366 pAudioSnk = NULL; 367 368 // check the audio source and sink parameters against platform support 369#ifdef ANDROID 370 result = android_audioRecorder_checkSourceSinkSupport(this); 371 if (SL_RESULT_SUCCESS != result) { 372 SL_LOGE("Cannot create AudioRecorder: invalid source or sink"); 373 break; 374 } 375#endif 376 377#ifdef ANDROID 378 // Allocate memory for buffer queue 379 SLuint32 locatorType = this->mDataSink.mLocator.mLocatorType; 380 if (locatorType == SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE) { 381 this->mBufferQueue.mNumBuffers = 382 this->mDataSink.mLocator.mBufferQueue.numBuffers; 383 // inline allocation of circular Buffer Queue mArray, up to a typical max 384 if (BUFFER_HEADER_TYPICAL >= this->mBufferQueue.mNumBuffers) { 385 this->mBufferQueue.mArray = this->mBufferQueue.mTypical; 386 } else { 387 // Avoid possible integer overflow during multiplication; this arbitrary 388 // maximum is big enough to not interfere with real applications, but 389 // small enough to not overflow. 390 if (this->mBufferQueue.mNumBuffers >= 256) { 391 result = SL_RESULT_MEMORY_FAILURE; 392 break; 393 } 394 this->mBufferQueue.mArray = (BufferHeader *) malloc((this->mBufferQueue. 395 mNumBuffers + 1) * sizeof(BufferHeader)); 396 if (NULL == this->mBufferQueue.mArray) { 397 result = SL_RESULT_MEMORY_FAILURE; 398 break; 399 } 400 } 401 this->mBufferQueue.mFront = this->mBufferQueue.mArray; 402 this->mBufferQueue.mRear = this->mBufferQueue.mArray; 403 } 404#endif 405 406 // platform-specific initialization 407#ifdef ANDROID 408 android_audioRecorder_create(this); 409#endif 410 411 } while (0); 412 413 if (SL_RESULT_SUCCESS != result) { 414 IObject_Destroy(&this->mObject.mItf); 415 } else { 416 IObject_Publish(&this->mObject); 417 // return the new audio recorder object 418 *pRecorder = &this->mObject.mItf; 419 } 420 } 421 422 } 423 424 } 425#else 426 result = SL_RESULT_FEATURE_UNSUPPORTED; 427#endif 428 429 SL_LEAVE_INTERFACE 430} 431 432 433static SLresult IEngine_CreateMidiPlayer(SLEngineItf self, SLObjectItf *pPlayer, 434 SLDataSource *pMIDISrc, SLDataSource *pBankSrc, SLDataSink *pAudioOutput, 435 SLDataSink *pVibra, SLDataSink *pLEDArray, SLuint32 numInterfaces, 436 const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 437{ 438 SL_ENTER_INTERFACE 439 440#if USE_PROFILES & (USE_PROFILES_GAME | USE_PROFILES_PHONE) 441 if ((NULL == pPlayer) || (NULL == pMIDISrc) || (NULL == pAudioOutput)) { 442 result = SL_RESULT_PARAMETER_INVALID; 443 } else { 444 *pPlayer = NULL; 445 unsigned exposedMask; 446 const ClassTable *pCMidiPlayer_class = objectIDtoClass(SL_OBJECTID_MIDIPLAYER); 447 if (NULL == pCMidiPlayer_class) { 448 result = SL_RESULT_FEATURE_UNSUPPORTED; 449 } else { 450 result = checkInterfaces(pCMidiPlayer_class, numInterfaces, 451 pInterfaceIds, pInterfaceRequired, &exposedMask); 452 } 453 if (SL_RESULT_SUCCESS == result) { 454 CMidiPlayer *this = (CMidiPlayer *) construct(pCMidiPlayer_class, exposedMask, self); 455 if (NULL == this) { 456 result = SL_RESULT_MEMORY_FAILURE; 457 } else { 458#if 0 459 "pMIDISrc", pMIDISrc, URI | MIDIBUFFERQUEUE, NONE 460 "pBankSrc", pBanksrc, NULL | URI | ADDRESS, NULL 461 "pAudioOutput", pAudioOutput, OUTPUTMIX, NULL 462 "pVibra", pVibra, NULL | IODEVICE, NULL 463 "pLEDArray", pLEDArray, NULL | IODEVICE, NULL 464#endif 465 // FIXME a fake value - why not use value from IPlay_init? what does CT check for? 466 this->mPlay.mDuration = 0; 467 IObject_Publish(&this->mObject); 468 // return the new MIDI player object 469 *pPlayer = &this->mObject.mItf; 470 } 471 } 472 } 473#else 474 result = SL_RESULT_FEATURE_UNSUPPORTED; 475#endif 476 477 SL_LEAVE_INTERFACE 478} 479 480 481static SLresult IEngine_CreateListener(SLEngineItf self, SLObjectItf *pListener, 482 SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 483{ 484 SL_ENTER_INTERFACE 485 486#if USE_PROFILES & USE_PROFILES_GAME 487 if (NULL == pListener) { 488 result = SL_RESULT_PARAMETER_INVALID; 489 } else { 490 *pListener = NULL; 491 unsigned exposedMask; 492 const ClassTable *pCListener_class = objectIDtoClass(SL_OBJECTID_LISTENER); 493 if (NULL == pCListener_class) { 494 result = SL_RESULT_FEATURE_UNSUPPORTED; 495 } else { 496 result = checkInterfaces(pCListener_class, numInterfaces, 497 pInterfaceIds, pInterfaceRequired, &exposedMask); 498 } 499 if (SL_RESULT_SUCCESS == result) { 500 CListener *this = (CListener *) construct(pCListener_class, exposedMask, self); 501 if (NULL == this) { 502 result = SL_RESULT_MEMORY_FAILURE; 503 } else { 504 IObject_Publish(&this->mObject); 505 // return the new 3D listener object 506 *pListener = &this->mObject.mItf; 507 } 508 } 509 } 510#else 511 result = SL_RESULT_FEATURE_UNSUPPORTED; 512#endif 513 514 SL_LEAVE_INTERFACE 515} 516 517 518static SLresult IEngine_Create3DGroup(SLEngineItf self, SLObjectItf *pGroup, SLuint32 numInterfaces, 519 const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 520{ 521 SL_ENTER_INTERFACE 522 523#if USE_PROFILES & USE_PROFILES_GAME 524 if (NULL == pGroup) { 525 result = SL_RESULT_PARAMETER_INVALID; 526 } else { 527 *pGroup = NULL; 528 unsigned exposedMask; 529 const ClassTable *pC3DGroup_class = objectIDtoClass(SL_OBJECTID_3DGROUP); 530 if (NULL == pC3DGroup_class) { 531 result = SL_RESULT_FEATURE_UNSUPPORTED; 532 } else { 533 result = checkInterfaces(pC3DGroup_class, numInterfaces, 534 pInterfaceIds, pInterfaceRequired, &exposedMask); 535 } 536 if (SL_RESULT_SUCCESS == result) { 537 C3DGroup *this = (C3DGroup *) construct(pC3DGroup_class, exposedMask, self); 538 if (NULL == this) { 539 result = SL_RESULT_MEMORY_FAILURE; 540 } else { 541 this->mMemberMask = 0; 542 IObject_Publish(&this->mObject); 543 // return the new 3D group object 544 *pGroup = &this->mObject.mItf; 545 } 546 } 547 } 548#else 549 result = SL_RESULT_FEATURE_UNSUPPORTED; 550#endif 551 552 SL_LEAVE_INTERFACE 553} 554 555 556static SLresult IEngine_CreateOutputMix(SLEngineItf self, SLObjectItf *pMix, SLuint32 numInterfaces, 557 const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 558{ 559 SL_ENTER_INTERFACE 560 561 if (NULL == pMix) { 562 result = SL_RESULT_PARAMETER_INVALID; 563 } else { 564 *pMix = NULL; 565 unsigned exposedMask; 566 const ClassTable *pCOutputMix_class = objectIDtoClass(SL_OBJECTID_OUTPUTMIX); 567 assert(NULL != pCOutputMix_class); 568 result = checkInterfaces(pCOutputMix_class, numInterfaces, 569 pInterfaceIds, pInterfaceRequired, &exposedMask); 570 if (SL_RESULT_SUCCESS == result) { 571 COutputMix *this = (COutputMix *) construct(pCOutputMix_class, exposedMask, self); 572 if (NULL == this) { 573 result = SL_RESULT_MEMORY_FAILURE; 574 } else { 575#ifdef ANDROID 576 android_outputMix_create(this); 577#endif 578#ifdef USE_SDL 579 IEngine *thisEngine = &this->mObject.mEngine->mEngine; 580 interface_lock_exclusive(thisEngine); 581 bool unpause = false; 582 if (NULL == thisEngine->mOutputMix) { 583 thisEngine->mOutputMix = this; 584 unpause = true; 585 } 586 interface_unlock_exclusive(thisEngine); 587#endif 588 IObject_Publish(&this->mObject); 589#ifdef USE_SDL 590 if (unpause) { 591 // Enable SDL_callback to be called periodically by SDL's internal thread 592 SDL_PauseAudio(0); 593 } 594#endif 595 // return the new output mix object 596 *pMix = &this->mObject.mItf; 597 } 598 } 599 } 600 601 SL_LEAVE_INTERFACE 602} 603 604 605static SLresult IEngine_CreateMetadataExtractor(SLEngineItf self, SLObjectItf *pMetadataExtractor, 606 SLDataSource *pDataSource, SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, 607 const SLboolean *pInterfaceRequired) 608{ 609 SL_ENTER_INTERFACE 610 611#if USE_PROFILES & (USE_PROFILES_GAME | USE_PROFILES_MUSIC) 612 if (NULL == pMetadataExtractor) { 613 result = SL_RESULT_PARAMETER_INVALID; 614 } else { 615 *pMetadataExtractor = NULL; 616 unsigned exposedMask; 617 const ClassTable *pCMetadataExtractor_class = 618 objectIDtoClass(SL_OBJECTID_METADATAEXTRACTOR); 619 if (NULL == pCMetadataExtractor_class) { 620 result = SL_RESULT_FEATURE_UNSUPPORTED; 621 } else { 622 result = checkInterfaces(pCMetadataExtractor_class, numInterfaces, 623 pInterfaceIds, pInterfaceRequired, &exposedMask); 624 } 625 if (SL_RESULT_SUCCESS == result) { 626 CMetadataExtractor *this = (CMetadataExtractor *) 627 construct(pCMetadataExtractor_class, exposedMask, self); 628 if (NULL == this) { 629 result = SL_RESULT_MEMORY_FAILURE; 630 } else { 631#if 0 632 "pDataSource", pDataSource, NONE, NONE 633#endif 634 IObject_Publish(&this->mObject); 635 // return the new metadata extractor object 636 *pMetadataExtractor = &this->mObject.mItf; 637 result = SL_RESULT_SUCCESS; 638 } 639 } 640 } 641#else 642 result = SL_RESULT_FEATURE_UNSUPPORTED; 643#endif 644 645 SL_LEAVE_INTERFACE 646} 647 648 649static SLresult IEngine_CreateExtensionObject(SLEngineItf self, SLObjectItf *pObject, 650 void *pParameters, SLuint32 objectID, SLuint32 numInterfaces, 651 const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) 652{ 653 SL_ENTER_INTERFACE 654 655 if (NULL == pObject) { 656 result = SL_RESULT_PARAMETER_INVALID; 657 } else { 658 *pObject = NULL; 659 result = SL_RESULT_FEATURE_UNSUPPORTED; 660 } 661 662 SL_LEAVE_INTERFACE 663} 664 665 666static SLresult IEngine_QueryNumSupportedInterfaces(SLEngineItf self, 667 SLuint32 objectID, SLuint32 *pNumSupportedInterfaces) 668{ 669 SL_ENTER_INTERFACE 670 671 if (NULL == pNumSupportedInterfaces) { 672 result = SL_RESULT_PARAMETER_INVALID; 673 } else { 674 const ClassTable *class__ = objectIDtoClass(objectID); 675 if (NULL == class__) { 676 result = SL_RESULT_FEATURE_UNSUPPORTED; 677 } else { 678 SLuint32 count = 0; 679 SLuint32 i; 680 for (i = 0; i < class__->mInterfaceCount; ++i) { 681 switch (class__->mInterfaces[i].mInterface) { 682 case INTERFACE_IMPLICIT: 683 case INTERFACE_IMPLICIT_PREREALIZE: 684 case INTERFACE_EXPLICIT: 685 case INTERFACE_EXPLICIT_PREREALIZE: 686 case INTERFACE_DYNAMIC: 687 ++count; 688 break; 689 case INTERFACE_UNAVAILABLE: 690 break; 691 default: 692 assert(false); 693 break; 694 } 695 } 696 *pNumSupportedInterfaces = count; 697 result = SL_RESULT_SUCCESS; 698 } 699 } 700 701 SL_LEAVE_INTERFACE; 702} 703 704 705static SLresult IEngine_QuerySupportedInterfaces(SLEngineItf self, 706 SLuint32 objectID, SLuint32 index, SLInterfaceID *pInterfaceId) 707{ 708 SL_ENTER_INTERFACE 709 710 if (NULL == pInterfaceId) { 711 result = SL_RESULT_PARAMETER_INVALID; 712 } else { 713 *pInterfaceId = NULL; 714 const ClassTable *class__ = objectIDtoClass(objectID); 715 if (NULL == class__) { 716 result = SL_RESULT_FEATURE_UNSUPPORTED; 717 } else { 718 result = SL_RESULT_PARAMETER_INVALID; // will be reset later 719 SLuint32 i; 720 for (i = 0; i < class__->mInterfaceCount; ++i) { 721 switch (class__->mInterfaces[i].mInterface) { 722 case INTERFACE_IMPLICIT: 723 case INTERFACE_IMPLICIT_PREREALIZE: 724 case INTERFACE_EXPLICIT: 725 case INTERFACE_EXPLICIT_PREREALIZE: 726 case INTERFACE_DYNAMIC: 727 break; 728 case INTERFACE_UNAVAILABLE: 729 continue; 730 default: 731 assert(false); 732 break; 733 } 734 if (index == 0) { 735 *pInterfaceId = &SL_IID_array[class__->mInterfaces[i].mMPH]; 736 result = SL_RESULT_SUCCESS; 737 break; 738 } 739 --index; 740 } 741 } 742 } 743 744 SL_LEAVE_INTERFACE 745}; 746 747 748static const char * const extensionNames[] = { 749#ifdef ANDROID 750 "ANDROID_SDK_LEVEL_9", // Android 2.3 aka "Gingerbread" 751 "ANDROID_SDK_LEVEL_10", // Android 3.0 aka "Honeycomb" 752 // in the future, add more entries for each SDK level here, and 753 // don't delete the entries for previous SDK levels unless support is removed 754#else 755 "WILHELM_DESKTOP", 756#endif 757}; 758 759 760static SLresult IEngine_QueryNumSupportedExtensions(SLEngineItf self, SLuint32 *pNumExtensions) 761{ 762 SL_ENTER_INTERFACE 763 764 if (NULL == pNumExtensions) { 765 result = SL_RESULT_PARAMETER_INVALID; 766 } else { 767 *pNumExtensions = sizeof(extensionNames) / sizeof(extensionNames[0]); 768 result = SL_RESULT_SUCCESS; 769 } 770 771 SL_LEAVE_INTERFACE 772} 773 774 775static SLresult IEngine_QuerySupportedExtension(SLEngineItf self, 776 SLuint32 index, SLchar *pExtensionName, SLint16 *pNameLength) 777{ 778 SL_ENTER_INTERFACE 779 780 if (NULL == pNameLength) { 781 result = SL_RESULT_PARAMETER_INVALID; 782 } else { 783 size_t actualNameLength; 784 unsigned numExtensions = sizeof(extensionNames) / sizeof(extensionNames[0]); 785 if (index >= numExtensions) { 786 actualNameLength = 0; 787 result = SL_RESULT_PARAMETER_INVALID; 788 } else { 789 const char *extensionName = extensionNames[index]; 790 actualNameLength = strlen(extensionName) + 1; 791 if (NULL == pExtensionName) { 792 // application is querying the name length in order to allocate a buffer 793 result = SL_RESULT_SUCCESS; 794 } else { 795 SLint16 availableNameLength = *pNameLength; 796 if (0 >= availableNameLength) { 797 // there is not even room for the terminating NUL 798 result = SL_RESULT_BUFFER_INSUFFICIENT; 799 } else if (actualNameLength > (size_t) availableNameLength) { 800 // "no invalid strings are written. That is, the null-terminator always exists" 801 memcpy(pExtensionName, extensionName, (size_t) availableNameLength - 1); 802 pExtensionName[(size_t) availableNameLength - 1] = '\0'; 803 result = SL_RESULT_BUFFER_INSUFFICIENT; 804 } else { 805 memcpy(pExtensionName, extensionName, actualNameLength); 806 result = SL_RESULT_SUCCESS; 807 } 808 } 809 } 810 *pNameLength = actualNameLength; 811 } 812 813 SL_LEAVE_INTERFACE 814} 815 816 817static SLresult IEngine_IsExtensionSupported(SLEngineItf self, 818 const SLchar *pExtensionName, SLboolean *pSupported) 819{ 820 SL_ENTER_INTERFACE 821 822 if (NULL == pSupported) { 823 result = SL_RESULT_PARAMETER_INVALID; 824 } else { 825 SLboolean isSupported = SL_BOOLEAN_FALSE; 826 if (NULL == pExtensionName) { 827 result = SL_RESULT_PARAMETER_INVALID; 828 } else { 829 unsigned numExtensions = sizeof(extensionNames) / sizeof(extensionNames[0]); 830 unsigned i; 831 for (i = 0; i < numExtensions; ++i) { 832 if (!strcmp((const char *) pExtensionName, extensionNames[i])) { 833 isSupported = SL_BOOLEAN_TRUE; 834 break; 835 } 836 } 837 result = SL_RESULT_SUCCESS; 838 } 839 *pSupported = isSupported; 840 } 841 842 SL_LEAVE_INTERFACE 843} 844 845 846static const struct SLEngineItf_ IEngine_Itf = { 847 IEngine_CreateLEDDevice, 848 IEngine_CreateVibraDevice, 849 IEngine_CreateAudioPlayer, 850 IEngine_CreateAudioRecorder, 851 IEngine_CreateMidiPlayer, 852 IEngine_CreateListener, 853 IEngine_Create3DGroup, 854 IEngine_CreateOutputMix, 855 IEngine_CreateMetadataExtractor, 856 IEngine_CreateExtensionObject, 857 IEngine_QueryNumSupportedInterfaces, 858 IEngine_QuerySupportedInterfaces, 859 IEngine_QueryNumSupportedExtensions, 860 IEngine_QuerySupportedExtension, 861 IEngine_IsExtensionSupported 862}; 863 864void IEngine_init(void *self) 865{ 866 IEngine *this = (IEngine *) self; 867 this->mItf = &IEngine_Itf; 868 // mLossOfControlGlobal is initialized in slCreateEngine 869#ifdef USE_SDL 870 this->mOutputMix = NULL; 871#endif 872 this->mInstanceCount = 1; // ourself 873 this->mInstanceMask = 0; 874 this->mChangedMask = 0; 875 unsigned i; 876 for (i = 0; i < MAX_INSTANCE; ++i) { 877 this->mInstances[i] = NULL; 878 } 879 this->mShutdown = SL_BOOLEAN_FALSE; 880 this->mShutdownAck = SL_BOOLEAN_FALSE; 881} 882 883void IEngine_deinit(void *self) 884{ 885} 886 887 888// OpenMAX AL Engine 889 890 891static XAresult IEngine_CreateCameraDevice(XAEngineItf self, XAObjectItf *pDevice, 892 XAuint32 deviceID, XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds, 893 const XAboolean *pInterfaceRequired) 894{ 895 XA_ENTER_INTERFACE 896 897 //IXAEngine *this = (IXAEngine *) self; 898 result = SL_RESULT_FEATURE_UNSUPPORTED; 899 900 XA_LEAVE_INTERFACE 901} 902 903 904static XAresult IEngine_CreateRadioDevice(XAEngineItf self, XAObjectItf *pDevice, 905 XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds, 906 const XAboolean *pInterfaceRequired) 907{ 908 XA_ENTER_INTERFACE 909 910 //IXAEngine *this = (IXAEngine *) self; 911 result = SL_RESULT_FEATURE_UNSUPPORTED; 912 913 XA_LEAVE_INTERFACE 914} 915 916 917static XAresult IXAEngine_CreateLEDDevice(XAEngineItf self, XAObjectItf *pDevice, XAuint32 deviceID, 918 XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds, 919 const XAboolean *pInterfaceRequired) 920{ 921 // forward to OpenSL ES 922 return IEngine_CreateLEDDevice(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf, 923 (SLObjectItf *) pDevice, deviceID, numInterfaces, (const SLInterfaceID *) pInterfaceIds, 924 (const SLboolean *) pInterfaceRequired); 925} 926 927 928static XAresult IXAEngine_CreateVibraDevice(XAEngineItf self, XAObjectItf *pDevice, 929 XAuint32 deviceID, XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds, 930 const XAboolean *pInterfaceRequired) 931{ 932 // forward to OpenSL ES 933 return IEngine_CreateVibraDevice(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf, 934 (SLObjectItf *) pDevice, deviceID, numInterfaces, (const SLInterfaceID *) pInterfaceIds, 935 (const SLboolean *) pInterfaceRequired); 936} 937 938 939static XAresult IEngine_CreateMediaPlayer(XAEngineItf self, XAObjectItf *pPlayer, 940 XADataSource *pDataSrc, XADataSource *pBankSrc, XADataSink *pAudioSnk, 941 XADataSink *pImageVideoSnk, XADataSink *pVibra, XADataSink *pLEDArray, 942 XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds, 943 const XAboolean *pInterfaceRequired) 944{ 945 XA_ENTER_INTERFACE 946 947 if (NULL == pPlayer) { 948 result = XA_RESULT_PARAMETER_INVALID; 949 } else { 950 *pPlayer = NULL; 951 unsigned exposedMask; 952 const ClassTable *pCMediaPlayer_class = objectIDtoClass(XA_OBJECTID_MEDIAPLAYER); 953 assert(NULL != pCMediaPlayer_class); 954 result = checkInterfaces(pCMediaPlayer_class, numInterfaces, 955 (const SLInterfaceID *) pInterfaceIds, pInterfaceRequired, &exposedMask); 956 if (XA_RESULT_SUCCESS == result) { 957 958 // Construct our new MediaPlayer instance 959 CMediaPlayer *this = (CMediaPlayer *) construct(pCMediaPlayer_class, exposedMask, 960 &((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf); 961 if (NULL == this) { 962 result = XA_RESULT_MEMORY_FAILURE; 963 } else { 964 965 do { 966 967 // Initialize private fields not associated with an interface 968 969 // (assume calloc or memset 0 during allocation) 970 // placement new 971 972 973 // Check the source and sink parameters against generic constraints 974 975 result = checkDataSource("pDataSrc", (const SLDataSource *) pDataSrc, 976 &this->mDataSource, DATALOCATOR_MASK_URI 977#ifdef ANDROID 978 | DATALOCATOR_MASK_ANDROIDFD 979 // FIXME | DATALOCATOR_MASK_ANDROIDBUFFERQUEUE ??? 980#endif 981 , DATAFORMAT_MASK_MIME); 982 if (XA_RESULT_SUCCESS != result) { 983 break; 984 } 985 986 result = checkDataSource("pBankSrc", (const SLDataSource *) pBankSrc, 987 &this->mBankSource, DATALOCATOR_MASK_NULL | DATALOCATOR_MASK_URI | 988 DATALOCATOR_MASK_ADDRESS, DATAFORMAT_MASK_NULL); 989 if (XA_RESULT_SUCCESS != result) { 990 break; 991 } 992 993 result = checkDataSink("pAudioSnk", (const SLDataSink *) pAudioSnk, 994 &this->mAudioSink, DATALOCATOR_MASK_OUTPUTMIX, DATAFORMAT_MASK_NULL); 995 if (XA_RESULT_SUCCESS != result) { 996 break; 997 } 998 999 result = checkDataSink("pImageVideoSnk", (const SLDataSink *) pImageVideoSnk, 1000 &this->mImageVideoSink, DATALOCATOR_MASK_NATIVEDISPLAY, 1001 DATAFORMAT_MASK_NULL); 1002 if (XA_RESULT_SUCCESS != result) { 1003 break; 1004 } 1005 1006 result = checkDataSink("pVibra", (const SLDataSink *) pVibra, &this->mVibraSink, 1007 DATALOCATOR_MASK_NULL | DATALOCATOR_MASK_IODEVICE, 1008 DATAFORMAT_MASK_NULL); 1009 if (XA_RESULT_SUCCESS != result) { 1010 break; 1011 } 1012 1013 result = checkDataSink("pLEDArray", (const SLDataSink *) pLEDArray, 1014 &this->mLEDArraySink, DATALOCATOR_MASK_NULL | DATALOCATOR_MASK_IODEVICE, 1015 DATAFORMAT_MASK_NULL); 1016 if (XA_RESULT_SUCCESS != result) { 1017 break; 1018 } 1019 1020 // Unsafe to ever refer to application pointers again 1021 pDataSrc = NULL; 1022 pBankSrc = NULL; 1023 pAudioSnk = NULL; 1024 pImageVideoSnk = NULL; 1025 pVibra = NULL; 1026 pLEDArray = NULL; 1027 1028 // Check that the requested interfaces are compatible with the data source 1029 // ... 1030 1031 // check the source and sink parameters against platform support 1032#ifdef ANDROID 1033 // result = android_mediaPlayer_checkSourceSink(this); 1034 if (XA_RESULT_SUCCESS != result) { 1035 break; 1036 } 1037#endif 1038 1039 // platform-specific initialization 1040#ifdef ANDROID 1041 // ... 1042#endif 1043 1044 } while (0); 1045 1046 if (XA_RESULT_SUCCESS != result) { 1047 IObject_Destroy(&this->mObject.mItf); 1048 } else { 1049 IObject_Publish(&this->mObject); 1050 // return the new media player object 1051 *pPlayer = (XAObjectItf) &this->mObject.mItf; 1052 } 1053 1054 } 1055 } 1056 1057 } 1058 1059 XA_LEAVE_INTERFACE 1060} 1061 1062 1063static XAresult IEngine_CreateMediaRecorder(XAEngineItf self, XAObjectItf *pRecorder, 1064 XADataSource *pAudioSrc, XADataSource *pImageVideoSrc, 1065 XADataSink *pDataSnk, XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds, 1066 const XAboolean *pInterfaceRequired) 1067{ 1068 XA_ENTER_INTERFACE 1069 1070 //IXAEngine *this = (IXAEngine *) self; 1071 result = SL_RESULT_FEATURE_UNSUPPORTED; 1072 1073#if 0 1074 "pAudioSrc", pAudioSrc, 1075 "pImageVideoSrc", pImageVideoSrc, 1076 "pDataSink", pDataSnk, 1077#endif 1078 1079 XA_LEAVE_INTERFACE 1080} 1081 1082 1083static XAresult IXAEngine_CreateOutputMix(XAEngineItf self, XAObjectItf *pMix, 1084 XAuint32 numInterfaces, const XAInterfaceID *pInterfaceIds, 1085 const XAboolean *pInterfaceRequired) 1086{ 1087 // forward to OpenSL ES 1088 return IEngine_CreateOutputMix(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf, 1089 (SLObjectItf *) pMix, numInterfaces, (const SLInterfaceID *) pInterfaceIds, 1090 (const SLboolean *) pInterfaceRequired); 1091} 1092 1093 1094static XAresult IXAEngine_CreateMetadataExtractor(XAEngineItf self, XAObjectItf *pMetadataExtractor, 1095 XADataSource *pDataSource, XAuint32 numInterfaces, 1096 const XAInterfaceID *pInterfaceIds, const XAboolean *pInterfaceRequired) 1097{ 1098 // forward to OpenSL ES 1099 return IEngine_CreateMetadataExtractor(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf, 1100 (SLObjectItf *) pMetadataExtractor, (SLDataSource *) pDataSource, numInterfaces, 1101 (const SLInterfaceID *) pInterfaceIds, (const SLboolean *) pInterfaceRequired); 1102} 1103 1104 1105static XAresult IXAEngine_CreateExtensionObject(XAEngineItf self, XAObjectItf *pObject, 1106 void *pParameters, XAuint32 objectID, XAuint32 numInterfaces, 1107 const XAInterfaceID *pInterfaceIds, const XAboolean *pInterfaceRequired) 1108{ 1109 // forward to OpenSL ES 1110 return IEngine_CreateExtensionObject(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf, 1111 (SLObjectItf *) pObject, pParameters, objectID, numInterfaces, 1112 (const SLInterfaceID *) pInterfaceIds, (const SLboolean *) pInterfaceRequired); 1113} 1114 1115 1116static XAresult IEngine_GetImplementationInfo(XAEngineItf self, XAuint32 *pMajor, XAuint32 *pMinor, 1117 XAuint32 *pStep, /* XAuint32 nImplementationTextSize, */ const XAchar *pImplementationText) 1118{ 1119 XA_ENTER_INTERFACE 1120 1121 //IXAEngine *this = (IXAEngine *) self; 1122 result = SL_RESULT_FEATURE_UNSUPPORTED; 1123 // FIXME 1124 1125 XA_LEAVE_INTERFACE 1126} 1127 1128 1129static XAresult IXAEngine_QuerySupportedProfiles(XAEngineItf self, XAint16 *pProfilesSupported) 1130{ 1131 XA_ENTER_INTERFACE 1132 1133 if (NULL == pProfilesSupported) { 1134 result = XA_RESULT_PARAMETER_INVALID; 1135 } else { 1136#if 1 1137 // FIXME 1138 *pProfilesSupported = 0; 1139 // FIXME the code below was copied from OpenSL ES and needs to be adapted for OpenMAX AL. 1140#else 1141 // The generic implementation doesn't implement any of the profiles, they shouldn't be 1142 // declared as supported. Also exclude the fake profiles BASE and OPTIONAL. 1143 *pProfilesSupported = USE_PROFILES & 1144 (USE_PROFILES_GAME | USE_PROFILES_MUSIC | USE_PROFILES_PHONE); 1145#endif 1146 result = XA_RESULT_SUCCESS; 1147 } 1148 1149 XA_LEAVE_INTERFACE 1150} 1151 1152 1153static XAresult IXAEngine_QueryNumSupportedInterfaces(XAEngineItf self, XAuint32 objectID, 1154 XAuint32 *pNumSupportedInterfaces) 1155{ 1156 // forward to OpenSL ES 1157 return IEngine_QueryNumSupportedInterfaces( 1158 &((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf, objectID, 1159 pNumSupportedInterfaces); 1160} 1161 1162 1163static XAresult IXAEngine_QuerySupportedInterfaces(XAEngineItf self, XAuint32 objectID, 1164 XAuint32 index, XAInterfaceID *pInterfaceId) 1165{ 1166 // forward to OpenSL ES 1167 return IEngine_QuerySupportedInterfaces( 1168 &((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf, objectID, index, 1169 (SLInterfaceID *) pInterfaceId); 1170} 1171 1172 1173static XAresult IXAEngine_QueryNumSupportedExtensions(XAEngineItf self, XAuint32 *pNumExtensions) 1174{ 1175 // forward to OpenSL ES 1176 return IEngine_QueryNumSupportedExtensions( 1177 &((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf, pNumExtensions); 1178} 1179 1180 1181static XAresult IXAEngine_QuerySupportedExtension(XAEngineItf self, XAuint32 index, 1182 XAchar *pExtensionName, XAint16 *pNameLength) 1183{ 1184 // forward to OpenSL ES 1185 return IEngine_QuerySupportedExtension(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf, 1186 index, pExtensionName, (SLint16 *) pNameLength); 1187} 1188 1189 1190static XAresult IXAEngine_IsExtensionSupported(XAEngineItf self, const XAchar *pExtensionName, 1191 XAboolean *pSupported) 1192{ 1193 // forward to OpenSL ES 1194 return IEngine_IsExtensionSupported(&((CEngine *) ((IXAEngine *) self)->mThis)->mEngine.mItf, 1195 pExtensionName, pSupported); 1196} 1197 1198 1199static XAresult IXAEngine_QueryLEDCapabilities(XAEngineItf self, XAuint32 *pIndex, 1200 XAuint32 *pLEDDeviceID, XALEDDescriptor *pDescriptor) 1201{ 1202 // forward to OpenSL ES EngineCapabilities 1203 return (XAresult) IEngineCapabilities_QueryLEDCapabilities( 1204 &((CEngine *) ((IXAEngine *) self)->mThis)->mEngineCapabilities.mItf, pIndex, 1205 pLEDDeviceID, (SLLEDDescriptor *) pDescriptor); 1206} 1207 1208 1209static XAresult IXAEngine_QueryVibraCapabilities(XAEngineItf self, XAuint32 *pIndex, 1210 XAuint32 *pVibraDeviceID, XAVibraDescriptor *pDescriptor) 1211{ 1212 // forward to OpenSL ES EngineCapabilities 1213 return (XAresult) IEngineCapabilities_QueryVibraCapabilities( 1214 &((CEngine *) ((IXAEngine *) self)->mThis)->mEngineCapabilities.mItf, pIndex, 1215 pVibraDeviceID, (SLVibraDescriptor *) pDescriptor); 1216} 1217 1218 1219// OpenMAX AL engine v-table 1220 1221static const struct XAEngineItf_ IXAEngine_Itf = { 1222 IEngine_CreateCameraDevice, 1223 IEngine_CreateRadioDevice, 1224 IXAEngine_CreateLEDDevice, 1225 IXAEngine_CreateVibraDevice, 1226 IEngine_CreateMediaPlayer, 1227 IEngine_CreateMediaRecorder, 1228 IXAEngine_CreateOutputMix, 1229 IXAEngine_CreateMetadataExtractor, 1230 IXAEngine_CreateExtensionObject, 1231 IEngine_GetImplementationInfo, 1232 IXAEngine_QuerySupportedProfiles, 1233 IXAEngine_QueryNumSupportedInterfaces, 1234 IXAEngine_QuerySupportedInterfaces, 1235 IXAEngine_QueryNumSupportedExtensions, 1236 IXAEngine_QuerySupportedExtension, 1237 IXAEngine_IsExtensionSupported, 1238 IXAEngine_QueryLEDCapabilities, 1239 IXAEngine_QueryVibraCapabilities 1240}; 1241 1242 1243void IXAEngine_init(void *self) 1244{ 1245 IXAEngine *this = (IXAEngine *) self; 1246 this->mItf = &IXAEngine_Itf; 1247} 1248