Improve resource recovery.
Better cleanup in AudioPlayer.Destroy.
Avoid mallocs in LEDArray and Equalizer.
Line length 100.
Change-Id: I2d22880b27ccf7e9038b398cae9287781fd82253
Continued work on threading.
Lay the groundwork for true asynchronous realize.
Call all callbacks with mutex unlocked.
C volatile is meaningless.
Start adding support for suspend/resume on interfaces.
Line length 100.
Change-Id: I631cb4f123143e4ef79c6c491d12b1e559857cab
diff --git a/libopensles/CAudioPlayer.c b/libopensles/CAudioPlayer.c
index 1208aa7..dd78033 100644
--- a/libopensles/CAudioPlayer.c
+++ b/libopensles/CAudioPlayer.c
@@ -67,12 +67,14 @@
void CAudioPlayer_Destroy(void *self)
{
CAudioPlayer *this = (CAudioPlayer *) self;
+ freeDataLocatorFormat(&this->mDataSource);
+ freeDataLocatorFormat(&this->mDataSink);
// FIXME stop the player in a way that app can't restart it
// Free the buffer queue, if it was larger than typical
if (NULL != this->mBufferQueue.mArray &&
this->mBufferQueue.mArray != this->mBufferQueue.mTypical) {
- free(this->mBufferQueue.mArray);
- this->mBufferQueue.mArray = NULL;
+ free(this->mBufferQueue.mArray);
+ this->mBufferQueue.mArray = NULL;
}
#ifdef USE_SNDFILE
if (NULL != this->mSndFile.mSNDFILE) {
diff --git a/libopensles/IBufferQueue.c b/libopensles/IBufferQueue.c
index 9596050..70366cf 100644
--- a/libopensles/IBufferQueue.c
+++ b/libopensles/IBufferQueue.c
@@ -84,7 +84,6 @@
slBufferQueueCallback callback, void *pContext)
{
IBufferQueue *this = (IBufferQueue *) self;
- // FIXME This could be a poke lock, if we had atomic double-word load/store
interface_lock_exclusive(this);
this->mCallback = callback;
this->mContext = pContext;
diff --git a/libopensles/IDynamicInterfaceManagement.c b/libopensles/IDynamicInterfaceManagement.c
index d7a7f55..166eb0b 100644
--- a/libopensles/IDynamicInterfaceManagement.c
+++ b/libopensles/IDynamicInterfaceManagement.c
@@ -18,9 +18,8 @@
#include "sles_allinclusive.h"
-static SLresult IDynamicInterfaceManagement_AddInterface(
- SLDynamicInterfaceManagementItf self, const SLInterfaceID iid,
- SLboolean async)
+static SLresult IDynamicInterfaceManagement_AddInterface(SLDynamicInterfaceManagementItf self,
+ const SLInterfaceID iid, SLboolean async)
{
if (NULL == iid)
return SL_RESULT_PARAMETER_INVALID;
@@ -39,27 +38,33 @@
size_t size = ((SLuint32) (index + 1) == class__->mInterfaceCount ?
class__->mSize : x[1].mOffset) - offset;
unsigned mask = 1 << index;
+ slDynamicInterfaceManagementCallback callback = NULL;
+ void *context = NULL;
// Lock the object rather than the DIM interface, because
// we modify both the object (exposed) and interface (added)
object_lock_exclusive(thisObject);
if (thisObject->mExposedMask & mask) {
result = SL_RESULT_PRECONDITIONS_VIOLATED;
} else {
- // FIXME Currently do initialization here, but might be asynchronous
+ // FIXME Currently all initialization is done here, even if requested to be asynchronous
memset(thisItf, 0, size);
((void **) thisItf)[1] = thisObject;
if (NULL != init)
(*init)(thisItf);
thisObject->mExposedMask |= mask;
+ assert(!(this->mAddedMask & mask));
this->mAddedMask |= mask;
+ assert(!(this->mSuspendedMask & mask));
result = SL_RESULT_SUCCESS;
- if (async && (NULL != this->mCallback)) {
- // FIXME Callback runs with mutex locked
- (*this->mCallback)(self, this->mContext,
- SL_DYNAMIC_ITF_EVENT_RESOURCES_AVAILABLE, result, iid);
+ // Make a copy of these, so we can call the callback with mutex unlocked
+ if (async) {
+ callback = this->mCallback;
+ context = this->mContext;
}
}
object_unlock_exclusive(thisObject);
+ if (NULL != callback)
+ (*callback)(self, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
return result;
}
@@ -92,6 +97,7 @@
if (!(this->mAddedMask & mask)) {
result = SL_RESULT_PRECONDITIONS_VIOLATED;
} else {
+ // FIXME When async resume is implemented, a pending async resume should be cancelled
if (NULL != deinit)
(*deinit)(thisItf);
#ifndef NDEBUG
@@ -99,13 +105,13 @@
#endif
thisObject->mExposedMask &= ~mask;
this->mAddedMask &= ~mask;
+ this->mSuspendedMask &= ~mask;
}
object_unlock_exclusive(thisObject);
return result;
}
-static SLresult IDynamicInterfaceManagement_ResumeInterface(
- SLDynamicInterfaceManagementItf self,
+static SLresult IDynamicInterfaceManagement_ResumeInterface(SLDynamicInterfaceManagementItf self,
const SLInterfaceID iid, SLboolean async)
{
if (NULL == iid)
@@ -119,24 +125,38 @@
int index = class__->mMPH_to_index[MPH];
if (0 > index)
return SL_RESULT_PRECONDITIONS_VIOLATED;
- SLresult result = SL_RESULT_SUCCESS;
+ SLresult result;
unsigned mask = 1 << index;
+ slDynamicInterfaceManagementCallback callback = NULL;
+ void *context = NULL;
// FIXME Change to exclusive when resume hook implemented
object_lock_shared(thisObject);
- if (!(this->mAddedMask & mask))
+ if (!(this->mSuspendedMask & mask))
result = SL_RESULT_PRECONDITIONS_VIOLATED;
+ else {
+ assert(this->mAddedMask & mask);
+ assert(thisObject->mExposedMask & mask);
+ // FIXME Currently the resume is done here, even if requested to be asynchronous
+ this->mSuspendedMask &= ~mask;
+ result = SL_RESULT_SUCCESS;
+ // Make a copy of these, so we can call the callback with mutex unlocked
+ if (async) {
+ callback = this->mCallback;
+ context = this->mContext;
+ }
+ }
// FIXME Call a resume hook on the interface, if suspended
object_unlock_shared(thisObject);
+ if (NULL != callback)
+ (*callback)(self, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
return result;
}
-static SLresult IDynamicInterfaceManagement_RegisterCallback(
- SLDynamicInterfaceManagementItf self,
+static SLresult IDynamicInterfaceManagement_RegisterCallback(SLDynamicInterfaceManagementItf self,
slDynamicInterfaceManagementCallback callback, void *pContext)
{
IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
IObject *thisObject = this->mThis;
- // FIXME This could be a poke lock, if we had atomic double-word load/store
object_lock_exclusive(thisObject);
this->mCallback = callback;
this->mContext = pContext;
@@ -156,6 +176,7 @@
IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
this->mItf = &IDynamicInterfaceManagement_Itf;
this->mAddedMask = 0;
+ this->mSuspendedMask = 0;
this->mCallback = NULL;
this->mContext = NULL;
}
diff --git a/libopensles/IEngine.c b/libopensles/IEngine.c
index 9601601..22ffc8a 100644
--- a/libopensles/IEngine.c
+++ b/libopensles/IEngine.c
@@ -33,16 +33,6 @@
CLEDDevice *this = (CLEDDevice *) construct(pCLEDDevice_class, exposedMask, self);
if (NULL == this)
return SL_RESULT_MEMORY_FAILURE;
- SLHSL *color = (SLHSL *) malloc(sizeof(SLHSL) * this->mLEDArray.mCount);
- assert(NULL != this->mLEDArray.mColor);
- this->mLEDArray.mColor = color;
- unsigned i;
- for (i = 0; i < this->mLEDArray.mCount; ++i) {
- // per specification 1.0.1 pg. 259: "Default color is undefined."
- color->hue = 0;
- color->saturation = 1000;
- color->lightness = 1000;
- }
this->mDeviceID = deviceID;
*pDevice = &this->mObject.mItf;
return SL_RESULT_SUCCESS;
@@ -157,12 +147,7 @@
return SL_RESULT_SUCCESS;
abort:
- freeDataLocatorFormat(&this->mDataSource);
- freeDataLocatorFormat(&this->mDataSink);
- if ((NULL != this->mBufferQueue.mArray) &&
- (this->mBufferQueue.mTypical != this->mBufferQueue.mArray)) {
- free(this->mBufferQueue.mArray);
- }
+ CAudioPlayer_Destroy(this);
free(this);
return result;
}
diff --git a/libopensles/IEqualizer.c b/libopensles/IEqualizer.c
index 4664ee4..4628190 100644
--- a/libopensles/IEqualizer.c
+++ b/libopensles/IEqualizer.c
@@ -18,28 +18,26 @@
#include "sles_allinclusive.h"
-// FIXME move
+// FIXME move to platform-specific configuration
-const struct EqualizerBand EqualizerBands[] = {
+#define MAX_EQ_PRESETS 3
+
+static const struct EqualizerBand EqualizerBands[MAX_EQ_BANDS] = {
{1000, 1500, 2000},
{2000, 3000, 4000},
{4000, 5500, 7000},
{7000, 8000, 9000}
};
-#define MAX_BANDS (sizeof(EqualizerBands)/sizeof(EqualizerBands[0]))
-
-const struct EqualizerPreset {
- const SLchar *mName;
- SLmillibel mLevels[MAX_BANDS];
-} EqualizerPresets[] = {
- {(const SLchar *) "Default", {0, 0, 0, 0}},
- {(const SLchar *) "Bass", {500, 200, 100, 0}},
- {(const SLchar *) "Treble", {0, 100, 200, 500}}
+static const struct EqualizerPreset {
+ const char *mName;
+ SLmillibel mLevels[MAX_EQ_BANDS];
+} EqualizerPresets[MAX_EQ_PRESETS] = {
+ {"Default", {0, 0, 0, 0}},
+ {"Bass", {500, 200, 100, 0}},
+ {"Treble", {0, 100, 200, 500}}
};
-#define MAX_PRESETS (sizeof(EqualizerPresets)/sizeof(EqualizerPresets[0]))
-
static SLresult IEqualizer_SetEnabled(SLEqualizerItf self, SLboolean enabled)
{
IEqualizer *this = (IEqualizer *) self;
@@ -61,8 +59,7 @@
return SL_RESULT_SUCCESS;
}
-static SLresult IEqualizer_GetNumberOfBands(SLEqualizerItf self,
- SLuint16 *pNumBands)
+static SLresult IEqualizer_GetNumberOfBands(SLEqualizerItf self, SLuint16 *pNumBands)
{
if (NULL == pNumBands)
return SL_RESULT_PARAMETER_INVALID;
@@ -86,8 +83,7 @@
return SL_RESULT_SUCCESS;
}
-static SLresult IEqualizer_SetBandLevel(SLEqualizerItf self, SLuint16 band,
- SLmillibel level)
+static SLresult IEqualizer_SetBandLevel(SLEqualizerItf self, SLuint16 band, SLmillibel level)
{
IEqualizer *this = (IEqualizer *) self;
if (band >= this->mNumBands)
@@ -114,8 +110,7 @@
return SL_RESULT_SUCCESS;
}
-static SLresult IEqualizer_GetCenterFreq(SLEqualizerItf self, SLuint16 band,
- SLmilliHertz *pCenter)
+static SLresult IEqualizer_GetCenterFreq(SLEqualizerItf self, SLuint16 band, SLmilliHertz *pCenter)
{
if (NULL == pCenter)
return SL_RESULT_PARAMETER_INVALID;
@@ -143,8 +138,7 @@
return SL_RESULT_SUCCESS;
}
-static SLresult IEqualizer_GetBand(SLEqualizerItf self, SLmilliHertz frequency,
- SLuint16 *pBand)
+static SLresult IEqualizer_GetBand(SLEqualizerItf self, SLmilliHertz frequency, SLuint16 *pBand)
{
if (NULL == pBand)
return SL_RESULT_PARAMETER_INVALID;
@@ -219,7 +213,7 @@
IEqualizer *this = (IEqualizer *) self;
if (index >= this->mNumPresets)
return SL_RESULT_PARAMETER_INVALID;
- *ppName = this->mPresetNames[index];
+ *ppName = (SLchar *) this->mPresets[index].mName;
return SL_RESULT_SUCCESS;
}
@@ -244,15 +238,15 @@
IEqualizer *this = (IEqualizer *) self;
this->mItf = &IEqualizer_Itf;
this->mEnabled = SL_BOOLEAN_FALSE;
- this->mNumBands = MAX_BANDS;
+ this->mPreset = SL_EQUALIZER_UNDEFINED;
+ unsigned band;
+ for (band = 0; band < MAX_EQ_BANDS; ++band)
+ this->mLevels[band] = 0;
+ // const fields
+ this->mNumPresets = MAX_EQ_PRESETS;
+ this->mNumBands = MAX_EQ_BANDS;
+ this->mBands = EqualizerBands;
+ this->mPresets = EqualizerPresets;
this->mBandLevelRangeMin = 0;
this->mBandLevelRangeMax = 1000;
- this->mBands = EqualizerBands;
- SLmillibel *levels;
- levels = (SLmillibel *) malloc(sizeof(SLmillibel) * MAX_BANDS);
- assert(NULL != levels);
- unsigned band;
- for (band = 0; band < this->mNumBands; ++band)
- this->mLevels[band] = 0;
- this->mPreset = SL_EQUALIZER_UNDEFINED;
}
diff --git a/libopensles/ILEDArray.c b/libopensles/ILEDArray.c
index 3d13304..e9136e7 100644
--- a/libopensles/ILEDArray.c
+++ b/libopensles/ILEDArray.c
@@ -18,8 +18,7 @@
#include "sles_allinclusive.h"
-static SLresult ILEDArray_ActivateLEDArray(SLLEDArrayItf self,
- SLuint32 lightMask)
+static SLresult ILEDArray_ActivateLEDArray(SLLEDArrayItf self, SLuint32 lightMask)
{
ILEDArray *this = (ILEDArray *) self;
interface_lock_poke(this);
@@ -28,8 +27,7 @@
return SL_RESULT_SUCCESS;
}
-static SLresult ILEDArray_IsLEDArrayActivated(SLLEDArrayItf self,
- SLuint32 *pLightMask)
+static SLresult ILEDArray_IsLEDArrayActivated(SLLEDArrayItf self, SLuint32 *pLightMask)
{
if (NULL == pLightMask)
return SL_RESULT_PARAMETER_INVALID;
@@ -41,8 +39,7 @@
return SL_RESULT_SUCCESS;
}
-static SLresult ILEDArray_SetColor(SLLEDArrayItf self, SLuint8 index,
- const SLHSL *pColor)
+static SLresult ILEDArray_SetColor(SLLEDArrayItf self, SLuint8 index, const SLHSL *pColor)
{
if (NULL == pColor)
return SL_RESULT_PARAMETER_INVALID;
@@ -54,21 +51,22 @@
if (!(0 <= color.lightness && color.lightness <= 1000))
return SL_RESULT_PARAMETER_INVALID;
ILEDArray *this = (ILEDArray *) self;
- interface_lock_poke(this);
- this->mColor[index] = color;
- interface_unlock_poke(this);
+ // can't use poke because struct copy might not be atomic
+ interface_lock_exclusive(this);
+ this->mColors[index] = color;
+ interface_unlock_exclusive(this);
return SL_RESULT_SUCCESS;
}
static SLresult ILEDArray_GetColor(SLLEDArrayItf self, SLuint8 index,
- SLHSL *pColor)
-{
+ SLHSL *pColor) {
if (NULL == pColor)
return SL_RESULT_PARAMETER_INVALID;
ILEDArray *this = (ILEDArray *) self;
- interface_lock_peek(this);
- SLHSL color = this->mColor[index];
- interface_unlock_peek(this);
+ // can't use peek because struct copy might not be atomic
+ interface_lock_shared(this);
+ SLHSL color = this->mColors[index];
+ interface_unlock_shared(this);
*pColor = color;
return SL_RESULT_SUCCESS;
}
@@ -84,19 +82,14 @@
{
ILEDArray *this = (ILEDArray *) self;
this->mItf = &ILEDArray_Itf;
-#ifndef NDEBUG
this->mLightMask = 0;
- this->mColor = NULL;
-#endif
- this->mCount = 8; // FIXME wrong place
- SLHSL *color;
- color = (SLHSL *) malloc(sizeof(SLHSL) * this->mCount);
- assert(NULL != color);
- this->mColor = color;
+ SLHSL *color = this->mColors;
SLuint8 index;
- for (index = 0; index < this->mCount; ++index, ++color) {
- color->hue = 0; // red
+ for (index = 0; index < MAX_LED_COUNT; ++index, ++color) {
+ color->hue = 0; // red, but per specification 1.0.1 pg. 259: "Default color is undefined."
color->saturation = 1000;
color->lightness = 1000;
}
+ // const
+ this->mCount = MAX_LED_COUNT;
}
diff --git a/libopensles/IObject.c b/libopensles/IObject.c
index 168e5eb..efda65a 100644
--- a/libopensles/IObject.c
+++ b/libopensles/IObject.c
@@ -23,22 +23,28 @@
IObject *this = (IObject *) self;
const ClassTable *class__ = this->mClass;
AsyncHook realize = class__->mRealize;
- SLresult result = SL_RESULT_SUCCESS;
+ SLresult result;
+ slObjectCallback callback = NULL;
+ void *context = NULL;
+ SLuint32 state = 0;
object_lock_exclusive(this);
- // FIXME The realize hook and callback should be asynchronous if requested
if (SL_OBJECT_STATE_UNREALIZED != this->mState) {
result = SL_RESULT_PRECONDITIONS_VIOLATED;
} else {
- if (NULL != realize)
- result = (*realize)(this, async);
+ // FIXME The realize hook and callback should be asynchronous if requested
+ result = NULL != realize ? (*realize)(this, async) : SL_RESULT_SUCCESS;
if (SL_RESULT_SUCCESS == result)
this->mState = SL_OBJECT_STATE_REALIZED;
- // FIXME callback should not run with mutex lock
- if (async && (NULL != this->mCallback))
- (*this->mCallback)(self, this->mContext,
- SL_OBJECT_EVENT_ASYNC_TERMINATION, result, this->mState, NULL);
+ // Make a copy of these, so we can call the callback with mutex unlocked
+ if (async) {
+ callback = this->mCallback;
+ context = this->mContext;
+ state = this->mState;
+ }
}
object_unlock_exclusive(this);
+ if (NULL != callback)
+ (*callback)(self, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL);
return result;
}
@@ -46,23 +52,29 @@
{
IObject *this = (IObject *) self;
const ClassTable *class__ = this->mClass;
- AsyncHook resume = class__->mResume;
- SLresult result = SL_RESULT_SUCCESS;
+ StatusHook resume = class__->mResume;
+ SLresult result;
+ slObjectCallback callback = NULL;
+ void *context = NULL;
+ SLuint32 state = 0;
object_lock_exclusive(this);
- // FIXME The resume hook and callback should be asynchronous if requested
if (SL_OBJECT_STATE_SUSPENDED != this->mState) {
result = SL_RESULT_PRECONDITIONS_VIOLATED;
} else {
- if (NULL != resume)
- result = (*resume)(this, async);
+ // FIXME The resume hook and callback should be asynchronous if requested
+ result = NULL != resume ? (*resume)(this) : SL_RESULT_SUCCESS;
if (SL_RESULT_SUCCESS == result)
this->mState = SL_OBJECT_STATE_REALIZED;
- // FIXME callback should not run with mutex lock
- if (async && (NULL != this->mCallback))
- (*this->mCallback)(self, this->mContext,
- SL_OBJECT_EVENT_ASYNC_TERMINATION, result, this->mState, NULL);
+ // Make a copy of these, so we can call the callback with mutex unlocked
+ if (async) {
+ callback = this->mCallback;
+ context = this->mContext;
+ state = this->mState;
+ }
}
object_unlock_exclusive(this);
+ if (NULL != callback)
+ (*callback)(self, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL);
return result;
}
@@ -71,16 +83,15 @@
if (NULL == pState)
return SL_RESULT_PARAMETER_INVALID;
IObject *this = (IObject *) self;
- // FIXME Investigate what it would take to change to a peek lock
- object_lock_shared(this);
+ // Note that the state is immediately obsolete, so a peek lock is safe
+ object_lock_peek(this);
SLuint32 state = this->mState;
- object_unlock_shared(this);
+ object_unlock_peek(this);
*pState = state;
return SL_RESULT_SUCCESS;
}
-static SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid,
- void *pInterface)
+static SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid, void *pInterface)
{
if (NULL == pInterface)
return SL_RESULT_PARAMETER_INVALID;
@@ -120,7 +131,6 @@
slObjectCallback callback, void *pContext)
{
IObject *this = (IObject *) self;
- // FIXME This could be a poke lock, if we had atomic double-word load/store
object_lock_exclusive(this);
this->mCallback = callback;
this->mContext = pContext;
@@ -135,6 +145,7 @@
static void IObject_Destroy(SLObjectItf self)
{
+ // FIXME The abort should be atomic w.r.t. destroy, so another async can't be started in window
IObject_AbortAsyncOperation(self);
IObject *this = (IObject *) self;
const ClassTable *class__ = this->mClass;
@@ -161,8 +172,7 @@
free(this);
}
-static SLresult IObject_SetPriority(SLObjectItf self, SLint32 priority,
- SLboolean preemptable)
+static SLresult IObject_SetPriority(SLObjectItf self, SLint32 priority, SLboolean preemptable)
{
IObject *this = (IObject *) self;
object_lock_exclusive(this);
@@ -172,8 +182,7 @@
return SL_RESULT_SUCCESS;
}
-static SLresult IObject_GetPriority(SLObjectItf self, SLint32 *pPriority,
- SLboolean *pPreemptable)
+static SLresult IObject_GetPriority(SLObjectItf self, SLint32 *pPriority, SLboolean *pPreemptable)
{
if (NULL == pPriority || NULL == pPreemptable)
return SL_RESULT_PARAMETER_INVALID;
diff --git a/libopensles/IOutputMixExt.c b/libopensles/IOutputMixExt.c
index 64dbb46..b5b1e35 100644
--- a/libopensles/IOutputMixExt.c
+++ b/libopensles/IOutputMixExt.c
@@ -50,8 +50,8 @@
void *dstWriter = pBuffer;
unsigned desired = size;
SLboolean trackContributedToMix = SL_BOOLEAN_FALSE;
+ IBufferQueue *bufferQueue = track->mBufferQueue;
while (desired > 0) {
- IBufferQueue *bufferQueue;
const struct BufferHeader *oldFront, *newFront, *rear;
unsigned actual = desired;
if (track->mAvail < actual)
@@ -82,8 +82,8 @@
track->mReader = (char *) track->mReader + actual;
track->mAvail -= actual;
if (track->mAvail == 0) {
- bufferQueue = track->mBufferQueue;
if (NULL != bufferQueue) {
+ interface_lock_exclusive(bufferQueue);
oldFront = bufferQueue->mFront;
rear = bufferQueue->mRear;
assert(oldFront != rear);
@@ -95,6 +95,7 @@
--bufferQueue->mState.count;
// FIXME here or in Enqueue?
++bufferQueue->mState.playIndex;
+ interface_unlock_exclusive(bufferQueue);
// FIXME a good time to do an early warning
// callback depending on buffer count
}
@@ -102,8 +103,8 @@
continue;
}
// actual == 0
- bufferQueue = track->mBufferQueue;
if (NULL != bufferQueue) {
+ interface_lock_shared(bufferQueue);
oldFront = bufferQueue->mFront;
rear = bufferQueue->mRear;
if (oldFront != rear) {
@@ -111,17 +112,22 @@
assert(0 < bufferQueue->mState.count);
track->mReader = oldFront->mBuffer;
track->mAvail = oldFront->mSize;
+ interface_unlock_shared(bufferQueue);
continue;
}
// FIXME should be able to configure when to
// kick off the callback e.g. high/low water-marks etc.
// need data but none available, attempt a desperate callback
slBufferQueueCallback callback = bufferQueue->mCallback;
+ void *context = bufferQueue->mContext;
+ interface_unlock_shared(bufferQueue);
if (NULL != callback) {
- (*callback)((SLBufferQueueItf) bufferQueue, bufferQueue->mContext);
+ (*callback)((SLBufferQueueItf) bufferQueue, context);
// if lucky, the callback enqueued a buffer
+ interface_lock_shared(bufferQueue);
if (rear != bufferQueue->mRear)
goto got_one;
+ interface_unlock_shared(bufferQueue);
// unlucky, queue still empty, the callback failed
}
// here on underflow due to no callback, or failed callback
diff --git a/libopensles/IPlay.c b/libopensles/IPlay.c
index 51bcc0f..e7ba632 100644
--- a/libopensles/IPlay.c
+++ b/libopensles/IPlay.c
@@ -101,7 +101,6 @@
void *pContext)
{
IPlay *this = (IPlay *) self;
- // FIXME This could be a poke lock, if we had atomic double-word load/store
interface_lock_exclusive(this);
this->mCallback = callback;
this->mContext = pContext;
diff --git a/libopensles/classes.c b/libopensles/classes.c
index 1433afe..c671f0e 100644
--- a/libopensles/classes.c
+++ b/libopensles/classes.c
@@ -105,9 +105,6 @@
offsetof(CAudioPlayer, mVisualization)}
};
-extern SLresult CAudioPlayer_Realize(void *self, SLboolean async);
-extern void CAudioPlayer_Destroy(void *self);
-
static const ClassTable CAudioPlayer_class = {
AudioPlayer_interfaces,
sizeof(AudioPlayer_interfaces)/sizeof(AudioPlayer_interfaces[0]),
diff --git a/libopensles/locks.h b/libopensles/locks.h
index e0eb93e..04a8017 100644
--- a/libopensles/locks.h
+++ b/libopensles/locks.h
@@ -35,6 +35,8 @@
// Peek and poke are an optimization for small atomic fields that don't "matter"
+#define object_lock_peek(this) /* object_lock_shared(this) */
+#define object_unlock_peek(this) /* object_unlock_shared(this) */
#define interface_lock_poke(this) /* interface_lock_exclusive(this) */
#define interface_unlock_poke(this) /* interface_unlock_exclusive(this) */
#define interface_lock_peek(this) /* interface_lock_shared(this) */
diff --git a/libopensles/sles_allinclusive.h b/libopensles/sles_allinclusive.h
index d2df099..e405108 100644
--- a/libopensles/sles_allinclusive.h
+++ b/libopensles/sles_allinclusive.h
@@ -95,7 +95,7 @@
size_t mSize;
SLuint32 mObjectID;
AsyncHook mRealize;
- AsyncHook mResume;
+ StatusHook mResume;
VoidHook mDestroy;
// append per-class data here
} ClassTable;
@@ -178,7 +178,7 @@
// but look for lingering code that assumes it is here before deleting
struct Object_interface *mThis;
const ClassTable *mClass;
- volatile SLuint32 mState;
+ SLuint32 mState;
slObjectCallback mCallback;
void *mContext;
unsigned mExposedMask; // exposed interfaces
@@ -356,7 +356,7 @@
typedef struct BufferQueue_interface {
const struct SLBufferQueueItf_ *mItf;
IObject *mThis;
- volatile SLBufferQueueState mState;
+ SLBufferQueueState mState;
slBufferQueueCallback mCallback;
void *mContext;
SLuint32 mNumBuffers;
@@ -377,7 +377,8 @@
typedef struct {
const struct SLDynamicInterfaceManagementItf_ *mItf;
IObject *mThis;
- unsigned mAddedMask; // added interfaces, a subset of exposed interfaces
+ unsigned mAddedMask; // added interfaces, a subset of exposed interfaces
+ unsigned mSuspendedMask; // suspended interfaces, a subset of added interfaces
slDynamicInterfaceManagementCallback mCallback;
void *mContext;
} IDynamicInterfaceManagement;
@@ -450,26 +451,30 @@
SLmilliHertz mMax;
};
+#define MAX_EQ_BANDS 4 // compile-time limit, runtime limit may be smaller
+
typedef struct {
const struct SLEqualizerItf_ *mItf;
IObject *mThis;
SLboolean mEnabled;
SLuint16 mPreset;
- SLmillibel *mLevels;
- // const
+ SLmillibel mLevels[MAX_EQ_BANDS];
+ // const to end of struct
SLuint16 mNumPresets;
SLuint16 mNumBands;
const struct EqualizerBand *mBands;
- const SLchar * const *mPresetNames;
+ const struct EqualizerPreset *mPresets;
SLmillibel mBandLevelRangeMin;
SLmillibel mBandLevelRangeMax;
} IEqualizer;
+#define MAX_LED_COUNT 32
+
typedef struct {
const struct SLLEDArrayItf_ *mItf;
IObject *mThis;
SLuint32 mLightMask;
- SLHSL *mColor;
+ SLHSL mColors[MAX_LED_COUNT];
// const
SLuint8 mCount;
} ILEDArray;
@@ -573,7 +578,7 @@
typedef struct Play_interface {
const struct SLPlayItf_ *mItf;
IObject *mThis;
- volatile SLuint32 mState;
+ SLuint32 mState;
SLmillisecond mDuration;
SLmillisecond mPosition;
// unsigned mPositionSamples; // position in sample units
@@ -768,8 +773,6 @@
android::AudioTrack *mAudioTrack;
android::MediaPlayer *mMediaPlayer;
};
- char* mUri;// FIXME temporary storage before we handle that correctly
- pthread_t mThread;
#endif
} /*CAudioPlayer*/;
@@ -918,3 +921,5 @@
extern SLresult checkDataSource(const SLDataSource *pDataSrc, DataLocatorFormat *myDataSourceLocator);
extern SLresult checkDataSink(const SLDataSink *pDataSink, DataLocatorFormat *myDataSinkLocator);
extern void freeDataLocatorFormat(DataLocatorFormat *dlf);
+extern SLresult CAudioPlayer_Realize(void *self, SLboolean async);
+extern void CAudioPlayer_Destroy(void *self);
diff --git a/libopensles/sles_to_android.cpp b/libopensles/sles_to_android.cpp
index 3622def..ede374b 100644
--- a/libopensles/sles_to_android.cpp
+++ b/libopensles/sles_to_android.cpp
@@ -279,10 +279,10 @@
case (android::AudioTrack::EVENT_MORE_DATA) : {
//fprintf(stdout, "received event EVENT_MORE_DATA from AudioTrack\n");
+ slBufferQueueCallback callback = NULL;
android::AudioTrack::Buffer* pBuff = (android::AudioTrack::Buffer*)info;
// retrieve data from the buffer queue
interface_lock_exclusive(&pAudioPlayer->mBufferQueue);
- slBufferQueueCallback callback = NULL;
if (pAudioPlayer->mBufferQueue.mState.count != 0) {
//fprintf(stderr, "nbBuffers in queue = %lu\n",pAudioPlayer->mBufferQueue.mState.count);
assert(pAudioPlayer->mBufferQueue.mFront != pAudioPlayer->mBufferQueue.mRear);
@@ -298,6 +298,7 @@
pAudioPlayer->mBufferQueue.mSizeConsumed += pBuff->size;
// leave pBuff->size untouched
// consume data
+ // FIXME can we avoid holding the lock during the copy?
memcpy (pBuff->i16, pSrc, pBuff->size);
} else {
// finish consuming the buffer or consume the buffer in one shot
@@ -315,15 +316,14 @@
pAudioPlayer->mBufferQueue.mState.playIndex++;
// consume data
+ // FIXME can we avoid holding the lock during the copy?
memcpy (pBuff->i16, pSrc, pBuff->size);
// data has been consumed, and the buffer queue state has been updated
// we can notify the client if applicable
callback = pAudioPlayer->mBufferQueue.mCallback;
- if (NULL != callback) {
- // save callback data
- callbackPContext = pAudioPlayer->mBufferQueue.mContext;
- }
+ // save callback data
+ callbackPContext = pAudioPlayer->mBufferQueue.mContext;
}
} else {
// no data available
@@ -369,8 +369,9 @@
interface_lock_shared(&pAudioPlayer->mPlay);
callback = pAudioPlayer->mPlay.mCallback;
callbackPContext = pAudioPlayer->mPlay.mContext;
+ bool headStalled = (pAudioPlayer->mPlay.mEventFlags & SL_PLAYEVENT_HEADSTALLED) != 0;
interface_unlock_shared(&pAudioPlayer->mPlay);
- if ((NULL != callback) && (pAudioPlayer->mPlay.mEventFlags & SL_PLAYEVENT_HEADSTALLED)) {
+ if ((NULL != callback) && headStalled) {
(*callback)(&pAudioPlayer->mPlay.mItf, callbackPContext, SL_PLAYEVENT_HEADSTALLED);
}
}
@@ -423,13 +424,8 @@
break;
// -----------------------------------
// URI to MediaPlayer
- case SL_DATALOCATOR_URI: {
+ case SL_DATALOCATOR_URI:
pAudioPlayer->mAndroidObjType = MEDIAPLAYER;
- // save URI
- SLDataLocator_URI *dl_uri = (SLDataLocator_URI *) pAudioSrc->pLocator;
- pAudioPlayer->mUri = (char*) malloc(1 + sizeof(SLchar)*strlen((char*)dl_uri->URI));
- strcpy(pAudioPlayer->mUri, (char*)dl_uri->URI);
- }
break;
default:
pAudioPlayer->mAndroidObjType = INVALID_TYPE;
@@ -483,7 +479,7 @@
break;
}
pAudioPlayer->mMediaPlayer->setAudioStreamType(ANDROID_DEFAULT_OUTPUT_STREAM_TYPE);
- if (pAudioPlayer->mMediaPlayer->setDataSource(android::String8(pAudioPlayer->mUri), NULL)
+ if (pAudioPlayer->mMediaPlayer->setDataSource(android::String8((const char *) pAudioPlayer->mDataSource.mLocator.mURI.URI), NULL)
!= android::NO_ERROR) {
result = SL_RESULT_CONTENT_UNSUPPORTED;
break;
@@ -494,7 +490,7 @@
if (async == SL_BOOLEAN_FALSE) {
if (pAudioPlayer->mMediaPlayer->prepare() != android::NO_ERROR) {
fprintf(stderr, "Failed to prepare() MediaPlayer in synchronous mode for %s\n",
- pAudioPlayer->mUri);
+ pAudioPlayer->mDataSource.mLocator.mURI.URI);
result = SL_RESULT_CONTENT_UNSUPPORTED;
}
} else {
@@ -537,7 +533,6 @@
fprintf(stderr, "FIXME destroy MediaPlayer\n");
//delete pAudioPlayer->mMediaPlayer;
pAudioPlayer->mMediaPlayer = NULL;
- free(pAudioPlayer->mUri);
}
break;
default: