From 8fa790e5cc00bf3f3f0ad57fecdb63a9857a8d93 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Mon, 10 Jan 2011 17:49:43 -0800 Subject: [PATCH] Shared engine between OpenSL ES and OpenMAX AL Change-Id: Idaee7eeb37be1c00ab8c0cf7976163831eb0fb23 --- opensles/libopensles/C3DGroup.c | 6 +-- opensles/libopensles/CAudioPlayer.c | 14 +++--- opensles/libopensles/CAudioRecorder.c | 4 +- opensles/libopensles/CEngine.c | 29 ++++++++++-- opensles/libopensles/CMediaPlayer.c | 4 +- opensles/libopensles/COutputMix.c | 6 +-- opensles/libopensles/IObject.c | 36 ++++++++++++--- opensles/libopensles/android_Player.cpp | 1 + opensles/libopensles/entry.c | 77 +++++++++++++++++++++++++------- opensles/libopensles/sles_allinclusive.h | 22 ++++++--- opensles/tests/sandbox/Android.mk | 29 ++++++++++++ opensles/tests/sandbox/dual.c | 75 +++++++++++++++++++++++++++++++ opensles/tests/sandbox/engine.c | 4 +- opensles/tests/sandbox/xa.c | 27 +++++++++++ 14 files changed, 285 insertions(+), 49 deletions(-) create mode 100644 opensles/tests/sandbox/dual.c diff --git a/opensles/libopensles/C3DGroup.c b/opensles/libopensles/C3DGroup.c index 9c7a38ac..d13f30d4 100644 --- a/opensles/libopensles/C3DGroup.c +++ b/opensles/libopensles/C3DGroup.c @@ -21,13 +21,13 @@ /** \brief Hook called by Object::Destroy before a 3D group is about to be destroyed */ -bool C3DGroup_PreDestroy(void *self) +predestroy_t C3DGroup_PreDestroy(void *self) { C3DGroup *this = (C3DGroup *) self; // See design document for explanation if (0 == this->mMemberMask) { - return true; + return predestroy_ok; } SL_LOGE("Object::Destroy(%p) for 3DGroup ignored; mMemberMask=0x%x", this, this->mMemberMask); - return false; + return predestroy_error; } diff --git a/opensles/libopensles/CAudioPlayer.c b/opensles/libopensles/CAudioPlayer.c index 3bcb7b12..9cd795f9 100644 --- a/opensles/libopensles/CAudioPlayer.c +++ b/opensles/libopensles/CAudioPlayer.c @@ -68,17 +68,19 @@ void CAudioPlayer_Destroy(void *self) /** \brief Hook called by Object::Destroy before an audio player is about to be destroyed */ -bool CAudioPlayer_PreDestroy(void *self) +predestroy_t CAudioPlayer_PreDestroy(void *self) { #ifdef USE_OUTPUTMIXEXT CAudioPlayer *this = (CAudioPlayer *) self; // Safe to proceed immediately if a track has not yet been assigned Track *track = this->mTrack; - if (NULL == track) - return true; + if (NULL == track) { + return predestroy_ok; + } CAudioPlayer *audioPlayer = track->mAudioPlayer; - if (NULL == audioPlayer) - return true; + if (NULL == audioPlayer) { + return predestroy_ok; + } assert(audioPlayer == this); // Request the mixer thread to unlink this audio player's track this->mDestroyRequested = true; @@ -87,7 +89,7 @@ bool CAudioPlayer_PreDestroy(void *self) } // Mixer thread has acknowledged the request #endif - return true; + return predestroy_ok; } diff --git a/opensles/libopensles/CAudioRecorder.c b/opensles/libopensles/CAudioRecorder.c index 4171e5fe..75b69e9d 100644 --- a/opensles/libopensles/CAudioRecorder.c +++ b/opensles/libopensles/CAudioRecorder.c @@ -57,7 +57,7 @@ void CAudioRecorder_Destroy(void *self) /** \brief Hook called by Object::Destroy before an audio recorder is about to be destroyed */ -bool CAudioRecorder_PreDestroy(void *self) +predestroy_t CAudioRecorder_PreDestroy(void *self) { - return true; + return predestroy_ok; } diff --git a/opensles/libopensles/CEngine.c b/opensles/libopensles/CEngine.c index 2e5beab3..0dad30a5 100644 --- a/opensles/libopensles/CEngine.c +++ b/opensles/libopensles/CEngine.c @@ -19,10 +19,12 @@ #include "sles_allinclusive.h" -/* This implementation supports at most one engine */ +/* This implementation supports at most one engine, identical for both OpenSL ES and OpenMAX AL */ CEngine *theOneTrueEngine = NULL; pthread_mutex_t theOneTrueMutex = PTHREAD_MUTEX_INITIALIZER; +unsigned theOneTrueRefCount = 0; +// incremented by slCreateEngine or xaCreateEngine, decremented by Object::Destroy on engine /** \brief Called by dlopen when .so is loaded */ @@ -36,7 +38,7 @@ __attribute__((constructor)) static void onDlOpen(void) __attribute__((destructor)) static void onDlClose(void) { - if (NULL != theOneTrueEngine) { + if ((NULL != theOneTrueEngine) || (0 < theOneTrueRefCount)) { SL_LOGE("Object::Destroy omitted for engine %p", theOneTrueEngine); } } @@ -141,9 +143,26 @@ void CEngine_Destroy(void *self) /** \brief Hook called by Object::Destroy before an engine is about to be destroyed */ -bool CEngine_PreDestroy(void *self) +predestroy_t CEngine_PreDestroy(void *self) { - return true; + predestroy_t ret; + (void) pthread_mutex_lock(&theOneTrueMutex); + assert(self == theOneTrueEngine); + switch (theOneTrueRefCount) { + case 0: + assert(false); + ret = predestroy_error; + break; + case 1: + ret = predestroy_ok; + break; + default: + --theOneTrueRefCount; + ret = predestroy_again; + break; + } + (void) pthread_mutex_unlock(&theOneTrueMutex); + return ret; } @@ -158,6 +177,8 @@ void CEngine_Destroyed(CEngine *self) assert(0 == ok); assert(self == theOneTrueEngine); theOneTrueEngine = NULL; + assert(1 == theOneTrueRefCount); + theOneTrueRefCount = 0; ok = pthread_mutex_unlock(&theOneTrueMutex); assert(0 == ok); } diff --git a/opensles/libopensles/CMediaPlayer.c b/opensles/libopensles/CMediaPlayer.c index a0953da2..644e3e3e 100644 --- a/opensles/libopensles/CMediaPlayer.c +++ b/opensles/libopensles/CMediaPlayer.c @@ -89,7 +89,7 @@ void CMediaPlayer_Destroy(void *self) } -bool CMediaPlayer_PreDestroy(void *self) +predestroy_t CMediaPlayer_PreDestroy(void *self) { - return true; + return predestroy_ok; } diff --git a/opensles/libopensles/COutputMix.c b/opensles/libopensles/COutputMix.c index 971acaaa..e1890152 100644 --- a/opensles/libopensles/COutputMix.c +++ b/opensles/libopensles/COutputMix.c @@ -55,7 +55,7 @@ void COutputMix_Destroy(void *self) /** \brief Hook called by Object::Destroy before an output mix is about to be destroyed */ -bool COutputMix_PreDestroy(void *self) +predestroy_t COutputMix_PreDestroy(void *self) { // Ignore destroy requests if there are any players attached to this output mix COutputMix *outputMix = (COutputMix *) self; @@ -83,9 +83,9 @@ bool COutputMix_PreDestroy(void *self) #endif } #endif - return true; + return predestroy_ok; } SL_LOGE("Object::Destroy(%p) for OutputMix ignored; %u players attached", outputMix, outputMix->mObject.mStrongRefCount); - return false; + return predestroy_error; } diff --git a/opensles/libopensles/IObject.c b/opensles/libopensles/IObject.c index 1be0d81b..4ca150a7 100644 --- a/opensles/libopensles/IObject.c +++ b/opensles/libopensles/IObject.c @@ -89,12 +89,27 @@ static SLresult IObject_Realize(SLObjectItf self, SLboolean async) IObject *this = (IObject *) self; SLuint8 state; const ClassTable *class__ = this->mClass; + bool isSharedEngine = false; object_lock_exclusive(this); + // note that SL_OBJECTID_ENGINE and XA_OBJECTID_ENGINE map to same class + if (class__ == objectIDtoClass(SL_OBJECTID_ENGINE)) { + // important: the lock order is engine followed by theOneTrueMutex + int ok = pthread_mutex_lock(&theOneTrueMutex); + assert(0 == ok); + isSharedEngine = 1 < theOneTrueRefCount; + ok = pthread_mutex_unlock(&theOneTrueMutex); + assert(0 == ok); + } state = this->mState; - // Reject redundant calls to Realize + // Reject redundant calls to Realize, except on a shared engine if (SL_OBJECT_STATE_UNREALIZED != state) { object_unlock_exclusive(this); - result = SL_RESULT_PRECONDITIONS_VIOLATED; + // redundant realize on the shared engine is permitted + if (isSharedEngine && (SL_OBJECT_STATE_REALIZED == state)) { + result = SL_RESULT_SUCCESS; + } else { + result = SL_RESULT_PRECONDITIONS_VIOLATED; + } } else { // Asynchronous: mark operation pending and cancellable if (async && (SL_OBJECTID_ENGINE != class__->mSLObjectID)) { @@ -509,17 +524,26 @@ void IObject_Destroy(SLObjectItf self) Abort_internal(this); // mutex is locked const ClassTable *class__ = this->mClass; - BoolHook preDestroy = class__->mPreDestroy; + PreDestroyHook preDestroy = class__->mPreDestroy; // The pre-destroy hook is called with mutex locked, and should block until it is safe to // destroy. It is OK to unlock the mutex temporarily, as it long as it re-locks the mutex // before returning. if (NULL != preDestroy) { - bool okToDestroy = (*preDestroy)(this); - if (!okToDestroy) { + predestroy_t okToDestroy = (*preDestroy)(this); + switch (okToDestroy) { + case predestroy_ok: + break; + case predestroy_error: + SL_LOGE("Object::Destroy(%p) not allowed", this); + // fall through + case predestroy_again: object_unlock_exclusive(this); // unfortunately Destroy doesn't return a result - SL_LOGE("Object::Destroy(%p) not allowed", this); SL_LEAVE_INTERFACE_VOID + // unreachable + default: + assert(false); + break; } } this->mState = SL_OBJECT_STATE_DESTROYING; diff --git a/opensles/libopensles/android_Player.cpp b/opensles/libopensles/android_Player.cpp index b96abe87..cdff7083 100644 --- a/opensles/libopensles/android_Player.cpp +++ b/opensles/libopensles/android_Player.cpp @@ -61,6 +61,7 @@ XAresult android_Player_create(CMediaPlayer *mp) { SLuint32 sourceLocator = *(SLuint32 *)pDataSrc->pLocator; switch(sourceLocator) { + // FIXME This should be Android simple buffer queue case XA_DATALOCATOR_ANDROIDBUFFERQUEUE: mp->mAndroidObjType = AV_PLR_TS_ABQ; break; diff --git a/opensles/libopensles/entry.c b/opensles/libopensles/entry.c index 6ae421eb..10301568 100644 --- a/opensles/libopensles/entry.c +++ b/opensles/libopensles/entry.c @@ -31,26 +31,16 @@ static SLresult liCreateEngine(SLObjectItf *pEngine, SLuint32 numOptions, int ok; ok = pthread_mutex_lock(&theOneTrueMutex); assert(0 == ok); + bool needToUnlockTheOneTrueMutex = true; do { -#ifdef ANDROID - android::ProcessState::self()->startThreadPool(); - android::DataSource::RegisterDefaultSniffers(); -#endif - if (NULL == pEngine) { result = SL_RESULT_PARAMETER_INVALID; break; } *pEngine = NULL; - if (NULL != theOneTrueEngine) { - SL_LOGE("slCreateEngine while another engine %p is active", theOneTrueEngine); - result = SL_RESULT_RESOURCE_ERROR; - break; - } - if ((0 < numOptions) && (NULL == pEngineOptions)) { SL_LOGE("numOptions=%lu and pEngineOptions=NULL", numOptions); result = SL_RESULT_PARAMETER_INVALID; @@ -85,7 +75,6 @@ static SLresult liCreateEngine(SLObjectItf *pEngine, SLuint32 numOptions, } unsigned exposedMask; - // const ClassTable *pCEngine_class = objectIDtoClass(SL_OBJECTID_ENGINE); assert(NULL != pCEngine_class); result = checkInterfaces(pCEngine_class, numInterfaces, pInterfaceIds, pInterfaceRequired, &exposedMask); @@ -93,7 +82,61 @@ static SLresult liCreateEngine(SLObjectItf *pEngine, SLuint32 numOptions, break; } - CEngine *this = (CEngine *) construct(pCEngine_class, exposedMask, NULL); + // if an engine already exists, then increment its ref count + CEngine *this = theOneTrueEngine; + if (NULL != this) { + assert(0 < theOneTrueRefCount); + ++theOneTrueRefCount; + + // In order to update the engine object, we need to lock it, + // but that would violate the lock order and potentially deadlock. + // So we unlock now and note that it should not be unlocked later. + ok = pthread_mutex_unlock(&theOneTrueMutex); + assert(0 == ok); + needToUnlockTheOneTrueMutex = false; + object_lock_exclusive(&this->mObject); + + // now expose additional interfaces not requested by the earlier engine create + const struct iid_vtable *x = pCEngine_class->mInterfaces; + SLuint8 *interfaceStateP = this->mObject.mInterfaceStates; + SLuint32 index; + for (index = 0; index < pCEngine_class->mInterfaceCount; ++index, ++x, + exposedMask >>= 1, ++interfaceStateP) { + switch (*interfaceStateP) { + case INTERFACE_EXPOSED: // previously exposed + break; + case INTERFACE_INITIALIZED: // not exposed during the earlier create + if (exposedMask & 1) { + const struct MPH_init *mi = &MPH_init_table[x->mMPH]; + BoolHook expose = mi->mExpose; + if ((NULL == expose) || (*expose)((char *) this + x->mOffset)) { + *interfaceStateP = INTERFACE_EXPOSED; + } + // FIXME log or report to application that expose hook failed + } + break; + case INTERFACE_UNINITIALIZED: // no init hook + break; + default: // impossible + assert(false); + break; + } + } + object_unlock_exclusive(&this->mObject); + // return the shared engine object + *pEngine = &this->mObject.mItf; + break; + } + + // here when creating the first engine reference + assert(0 == theOneTrueRefCount); + +#ifdef ANDROID + android::ProcessState::self()->startThreadPool(); + android::DataSource::RegisterDefaultSniffers(); +#endif + + this = (CEngine *) construct(pCEngine_class, exposedMask, NULL); if (NULL == this) { result = SL_RESULT_MEMORY_FAILURE; break; @@ -113,13 +156,17 @@ static SLresult liCreateEngine(SLObjectItf *pEngine, SLuint32 numOptions, this->mEngineCapabilities.mThreadSafe = threadSafe; IObject_Publish(&this->mObject); theOneTrueEngine = this; + theOneTrueRefCount = 1; // return the new engine object *pEngine = &this->mObject.mItf; } while(0); - ok = pthread_mutex_unlock(&theOneTrueMutex); - assert(0 == ok); + if (needToUnlockTheOneTrueMutex) { + ok = pthread_mutex_unlock(&theOneTrueMutex); + assert(0 == ok); + needToUnlockTheOneTrueMutex = false; + } return result; } diff --git a/opensles/libopensles/sles_allinclusive.h b/opensles/libopensles/sles_allinclusive.h index b260e267..5bff5412 100644 --- a/opensles/libopensles/sles_allinclusive.h +++ b/opensles/libopensles/sles_allinclusive.h @@ -108,12 +108,19 @@ typedef struct COutputMix_struct COutputMix; #include "sllog.h" +typedef enum { + predestroy_error, // Application should not be calling destroy now + predestroy_ok, // OK to destroy object now + predestroy_again // Application did nothing wrong, but should destroy again to be effective +} predestroy_t; + // Hook functions typedef void (*VoidHook)(void *self); //typedef SLresult (*ResultHook)(void *self); typedef SLresult (*AsyncHook)(void *self, SLboolean async); typedef bool (*BoolHook)(void *self); +typedef predestroy_t (*PreDestroyHook)(void *self); // Describes how an interface is related to a given class, used in iid_vtable::mInterface @@ -214,7 +221,7 @@ typedef struct { AsyncHook mRealize; AsyncHook mResume; VoidHook mDestroy; - BoolHook mPreDestroy; + PreDestroyHook mPreDestroy; } ClassTable; // BufferHeader describes each element of a BufferQueue, other than the data @@ -306,33 +313,33 @@ extern void IObject_Destroy(SLObjectItf self); #include "android_AudioPlayer.h" #endif -extern bool C3DGroup_PreDestroy(void *self); +extern predestroy_t C3DGroup_PreDestroy(void *self); extern SLresult CAudioPlayer_Realize(void *self, SLboolean async); extern SLresult CAudioPlayer_Resume(void *self, SLboolean async); extern void CAudioPlayer_Destroy(void *self); -extern bool CAudioPlayer_PreDestroy(void *self); +extern predestroy_t CAudioPlayer_PreDestroy(void *self); extern SLresult CAudioRecorder_Realize(void *self, SLboolean async); extern SLresult CAudioRecorder_Resume(void *self, SLboolean async); extern void CAudioRecorder_Destroy(void *self); -extern bool CAudioRecorder_PreDestroy(void *self); +extern predestroy_t CAudioRecorder_PreDestroy(void *self); extern SLresult CEngine_Realize(void *self, SLboolean async); extern SLresult CEngine_Resume(void *self, SLboolean async); extern void CEngine_Destroy(void *self); -extern bool CEngine_PreDestroy(void *self); +extern predestroy_t CEngine_PreDestroy(void *self); extern void CEngine_Destroyed(CEngine *self); extern SLresult COutputMix_Realize(void *self, SLboolean async); extern SLresult COutputMix_Resume(void *self, SLboolean async); extern void COutputMix_Destroy(void *self); -extern bool COutputMix_PreDestroy(void *self); +extern predestroy_t COutputMix_PreDestroy(void *self); extern SLresult CMediaPlayer_Realize(void *self, SLboolean async); extern SLresult CMediaPlayer_Resume(void *self, SLboolean async); extern void CMediaPlayer_Destroy(void *self); -extern bool CMediaPlayer_PreDestroy(void *self); +extern predestroy_t CMediaPlayer_PreDestroy(void *self); #ifdef USE_SDL extern void SDL_open(IEngine *thisEngine); @@ -392,3 +399,4 @@ extern SLresult IEngineCapabilities_QueryVibraCapabilities(SLEngineCapabilitiesI extern CEngine *theOneTrueEngine; extern pthread_mutex_t theOneTrueMutex; +extern unsigned theOneTrueRefCount; diff --git a/opensles/tests/sandbox/Android.mk b/opensles/tests/sandbox/Android.mk index 25b7652e..f3d0c1cf 100644 --- a/opensles/tests/sandbox/Android.mk +++ b/opensles/tests/sandbox/Android.mk @@ -403,3 +403,32 @@ LOCAL_CFLAGS += -UNDEBUG LOCAL_MODULE:= slesTest_xa include $(BUILD_EXECUTABLE) + +# dual + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_C_INCLUDES:= \ + system/media/opensles/include + +LOCAL_SRC_FILES:= \ + dual.c + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libOpenSLES + +LOCAL_STATIC_LIBRARIES := \ + libOpenSLESUT + +ifeq ($(TARGET_OS),linux) + LOCAL_CFLAGS += -DXP_UNIX +endif + +LOCAL_CFLAGS += -UNDEBUG + +LOCAL_MODULE:= slesTest_dual + +include $(BUILD_EXECUTABLE) diff --git a/opensles/tests/sandbox/dual.c b/opensles/tests/sandbox/dual.c new file mode 100644 index 00000000..c7abf11c --- /dev/null +++ b/opensles/tests/sandbox/dual.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Dual engine test + +#include +#include +#include +#include "SLES/OpenSLES.h" +#include "OMXAL/OpenMAXAL.h" + +int main(int argc, char **argv) +{ + XAresult xaResult; + XAObjectItf xaEngineObject; + + SLresult slResult; + SLObjectItf slEngineObject; + + printf("xaCreateEngine\n"); + xaResult = xaCreateEngine(&xaEngineObject, 0, NULL, 0, NULL, NULL); + printf("xaResult = %ld\n", xaResult); + assert(XA_RESULT_SUCCESS == xaResult); + printf("xaEngineObject = %p\n", xaEngineObject); + + printf("realize xaEngineObject\n"); + xaResult = (*xaEngineObject)->Realize(xaEngineObject, XA_BOOLEAN_FALSE); + printf("xaResult = %ld\n", xaResult); + + printf("GetInterface for XA_IID_ENGINE\n"); + XAEngineItf xaEngineEngine; + xaResult = (*xaEngineObject)->GetInterface(xaEngineObject, XA_IID_ENGINE, &xaEngineEngine); + printf("xaResult = %ld\n", xaResult); + printf("xaEngineEngine = %p\n", xaEngineEngine); + assert(XA_RESULT_SUCCESS == xaResult); + + printf("slCreateEngine\n"); + slResult = slCreateEngine(&slEngineObject, 0, NULL, 0, NULL, NULL); + printf("slResult = %ld\n", slResult); + assert(SL_RESULT_SUCCESS == slResult); + printf("slEngineObject = %p\n", slEngineObject); + + printf("realize slEngineObject\n"); + slResult = (*slEngineObject)->Realize(slEngineObject, SL_BOOLEAN_FALSE); + printf("slResult = %ld\n", slResult); + + printf("GetInterface for SL_IID_ENGINE\n"); + SLEngineItf slEngineEngine; + slResult = (*slEngineObject)->GetInterface(slEngineObject, SL_IID_ENGINE, &slEngineEngine); + printf("slResult = %ld\n", slResult); + printf("slEngineEngine = %p\n", slEngineEngine); + assert(SL_RESULT_SUCCESS == slResult); + + printf("destroying xaEngineObject\n"); + (*xaEngineObject)->Destroy(xaEngineObject); + + printf("destroying slEngineObject\n"); + (*slEngineObject)->Destroy(slEngineObject); + + printf("exit\n"); + return EXIT_SUCCESS; +} diff --git a/opensles/tests/sandbox/engine.c b/opensles/tests/sandbox/engine.c index edc25b83..b582485d 100644 --- a/opensles/tests/sandbox/engine.c +++ b/opensles/tests/sandbox/engine.c @@ -150,11 +150,13 @@ int main(int argc, char **argv) assert(interface_again == interface); } - printf("Create too many engines\n"); SLObjectItf engineObject2; +#if 0 + printf("Create too many engines\n"); result = slCreateEngine(&engineObject2, 0, NULL, 0, NULL, NULL); assert(SL_RESULT_RESOURCE_ERROR == result); assert(NULL == engineObject2); +#endif printf("Destroy engine\n"); (*engineObject)->Destroy(engineObject); diff --git a/opensles/tests/sandbox/xa.c b/opensles/tests/sandbox/xa.c index cf3f431c..90023ed9 100644 --- a/opensles/tests/sandbox/xa.c +++ b/opensles/tests/sandbox/xa.c @@ -1,7 +1,24 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include #include #include #include "OMXAL/OpenMAXAL.h" +#include "OMXAL/OpenMAXAL_Android.h" int main(int argc, char **argv) { @@ -51,15 +68,25 @@ int main(int argc, char **argv) printf("CreateMediaPlayer\n"); XAObjectItf playerObject; +#if 1 + XADataLocator_AndroidBufferQueue locABQ; + memset(&locABQ, 0, sizeof(locABQ)); + locABQ.locatorType = XA_DATALOCATOR_ANDROIDBUFFERQUEUE; +#else XADataLocator_URI locUri; locUri.locatorType = XA_DATALOCATOR_URI; locUri.URI = (XAchar *) "/sdcard/hello.wav"; +#endif XADataFormat_MIME fmtMime; fmtMime.formatType = XA_DATAFORMAT_MIME; fmtMime.mimeType = NULL; fmtMime.containerType = XA_CONTAINERTYPE_UNSPECIFIED; XADataSource dataSrc; +#if 1 + dataSrc.pLocator = &locABQ; +#else dataSrc.pLocator = &locUri; +#endif dataSrc.pFormat = &fmtMime; XADataSink audioSnk; XADataLocator_OutputMix locOM; -- 2.11.0