summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--opensles/libopensles/CAudioPlayer.c7
-rw-r--r--opensles/libopensles/IEngine.c44
-rw-r--r--opensles/libopensles/IMuteSolo.c68
-rw-r--r--opensles/libopensles/IObject.c5
-rw-r--r--opensles/libopensles/sles.c7
-rw-r--r--opensles/tests/listening/slesTest_playMuteSolo.cpp9
-rw-r--r--opensles/tests/sandbox/intbufq.c24
7 files changed, 126 insertions, 38 deletions
diff --git a/opensles/libopensles/CAudioPlayer.c b/opensles/libopensles/CAudioPlayer.c
index d27f15b5..c70f204d 100644
--- a/opensles/libopensles/CAudioPlayer.c
+++ b/opensles/libopensles/CAudioPlayer.c
@@ -26,9 +26,6 @@ SLresult CAudioPlayer_Realize(void *self, SLboolean async)
CAudioPlayer *this = (CAudioPlayer *) self;
SLresult result = SL_RESULT_SUCCESS;
- // initialize cached data, to be overwritten by platform-specific initialization
- this->mNumChannels = 0;
-
#ifdef ANDROID
result = android_audioPlayer_realize(this, async);
#endif
@@ -37,6 +34,10 @@ SLresult CAudioPlayer_Realize(void *self, SLboolean async)
result = SndFile_Realize(this);
#endif
+ // At this point the channel count and sample rate might still be unknown,
+ // depending on the data source and the platform implementation.
+ // If they are unknown here, then they will be determined during prefetch.
+
return result;
}
diff --git a/opensles/libopensles/IEngine.c b/opensles/libopensles/IEngine.c
index 865da4de..3352346b 100644
--- a/opensles/libopensles/IEngine.c
+++ b/opensles/libopensles/IEngine.c
@@ -123,7 +123,8 @@ static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer
// Initialize private fields not associated with an interface
this->mMuteMask = 0;
this->mSoloMask = 0;
- // const, will be set later by the containing AudioPlayer or MidiPlayer
+ // Will be set soon for PCM buffer queues, or later by platform-specific code
+ // during Realize or Prefetch
this->mNumChannels = 0;
this->mSampleRateMilliHz = 0;
@@ -136,13 +137,18 @@ static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer
break;
}
- result = checkSourceFormatVsInterfacesCompatibility(&this->mDataSource,
- numInterfaces, pInterfaceIds, pInterfaceRequired);
+ result = checkDataSink(pAudioSnk, &this->mDataSink, SL_OBJECTID_AUDIOPLAYER);
if (SL_RESULT_SUCCESS != result) {
break;
}
- result = checkDataSink(pAudioSnk, &this->mDataSink, SL_OBJECTID_AUDIOPLAYER);
+ // It would be unsafe to ever refer to the application pointers again
+ pAudioSrc = NULL;
+ pAudioSnk = NULL;
+
+ // Check that the requested interfaces are compatible with the data source
+ result = checkSourceFormatVsInterfacesCompatibility(&this->mDataSource,
+ numInterfaces, pInterfaceIds, pInterfaceRequired);
if (SL_RESULT_SUCCESS != result) {
break;
}
@@ -150,13 +156,16 @@ static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer
// copy the buffer queue count from source locator to the buffer queue interface
// we have already range-checked the value down to a smaller width
- switch (*(SLuint32 *) pAudioSrc->pLocator) {
+ switch (this->mDataSource.mLocator.mLocatorType) {
case SL_DATALOCATOR_BUFFERQUEUE:
#ifdef ANDROID
case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
#endif
- this->mBufferQueue.mNumBuffers = (SLuint16) ((SLDataLocator_BufferQueue *)
- pAudioSrc->pLocator)->numBuffers;
+ this->mBufferQueue.mNumBuffers =
+ (SLuint16) this->mDataSource.mLocator.mBufferQueue.numBuffers;
+ assert(SL_DATAFORMAT_PCM == this->mDataSource.mFormat.mFormatType);
+ this->mNumChannels = this->mDataSource.mFormat.mPCM.numChannels;
+ this->mSampleRateMilliHz = this->mDataSource.mFormat.mPCM.samplesPerSec;
break;
default:
this->mBufferQueue.mNumBuffers = 0;
@@ -268,9 +277,18 @@ static SLresult IEngine_CreateAudioRecorder(SLEngineItf self, SLObjectItf *pReco
} else {
do {
- // const, will be set later by the containing AudioRecorder
+
+ // Initialize fields not associated with any interface
+
+ // These fields are set to real values by
+ // android_audioRecorder_checkSourceSinkSupport. Note that the data sink is
+ // always PCM buffer queue, so we know the channel count and sample rate early.
this->mNumChannels = 0;
this->mSampleRateMilliHz = 0;
+#ifdef ANDROID
+ this->mAudioRecord = NULL;
+ this->mRecordSource = android::AUDIO_SOURCE_DEFAULT;
+#endif
// Check the source and sink parameters, and make a local copy of all parameters
result = checkDataSource(pAudioSrc, &this->mDataSource);
@@ -282,6 +300,10 @@ static SLresult IEngine_CreateAudioRecorder(SLEngineItf self, SLObjectItf *pReco
break;
}
+ // It would be unsafe to ever refer to the application pointers again
+ pAudioSrc = NULL;
+ pAudioSnk = NULL;
+
// check the audio source and sink parameters against platform support
#ifdef ANDROID
result = android_audioRecorder_checkSourceSinkSupport(this);
@@ -293,10 +315,10 @@ static SLresult IEngine_CreateAudioRecorder(SLEngineItf self, SLObjectItf *pReco
#ifdef ANDROID
// FIXME move to dedicated function
- SLuint32 locatorType = *(SLuint32 *) pAudioSnk->pLocator;
+ SLuint32 locatorType = this->mDataSink.mLocator.mLocatorType;
if (locatorType == SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE) {
- this->mBufferQueue.mNumBuffers = ((SLDataLocator_BufferQueue *)
- pAudioSnk->pLocator)->numBuffers;
+ this->mBufferQueue.mNumBuffers =
+ this->mDataSink.mLocator.mBufferQueue.numBuffers;
// inline allocation of circular Buffer Queue mArray, up to a typical max
if (BUFFER_HEADER_TYPICAL >= this->mBufferQueue.mNumBuffers) {
this->mBufferQueue.mArray = this->mBufferQueue.mTypical;
diff --git a/opensles/libopensles/IMuteSolo.c b/opensles/libopensles/IMuteSolo.c
index 5a6f4641..2811a715 100644
--- a/opensles/libopensles/IMuteSolo.c
+++ b/opensles/libopensles/IMuteSolo.c
@@ -29,16 +29,22 @@ static SLresult IMuteSolo_SetChannelMute(SLMuteSoloItf self, SLuint8 chan, SLboo
result = SL_RESULT_FEATURE_UNSUPPORTED;
} else {
CAudioPlayer *ap = (CAudioPlayer *) thisObject;
- if (ap->mNumChannels <= chan) {
+ interface_lock_exclusive(this);
+ SLuint8 numChannels = ap->mNumChannels;
+ if (1 >= numChannels) {
+ interface_unlock_exclusive(this);
+ result = SL_RESULT_FEATURE_UNSUPPORTED;
+ } else if (numChannels <= chan) {
+ interface_unlock_exclusive(this);
result = SL_RESULT_PARAMETER_INVALID;
} else {
SLuint8 mask = 1 << chan;
- interface_lock_exclusive(this);
SLuint8 oldMuteMask = ap->mMuteMask;
- if (mute)
+ if (mute) {
ap->mMuteMask |= mask;
- else
+ } else {
ap->mMuteMask &= ~mask;
+ }
interface_unlock_exclusive_attributes(this, oldMuteMask != ap->mMuteMask ? ATTR_GAIN :
ATTR_NONE);
result = SL_RESULT_SUCCESS;
@@ -62,15 +68,22 @@ static SLresult IMuteSolo_GetChannelMute(SLMuteSoloItf self, SLuint8 chan, SLboo
result = SL_RESULT_FEATURE_UNSUPPORTED;
} else {
CAudioPlayer *ap = (CAudioPlayer *) thisObject;
- if (ap->mNumChannels <= chan) {
+ SLboolean mute;
+ interface_lock_shared(this);
+ SLuint8 numChannels = ap->mNumChannels;
+ if (1 >= numChannels) {
+ mute = SL_BOOLEAN_FALSE;
+ result = SL_RESULT_FEATURE_UNSUPPORTED;
+ } else if (numChannels <= chan) {
+ mute = SL_BOOLEAN_FALSE;
result = SL_RESULT_PARAMETER_INVALID;
} else {
- interface_lock_peek(this);
SLuint8 mask = ap->mMuteMask;
- interface_unlock_peek(this);
- *pMute = (mask >> chan) & 1;
+ mute = (SLboolean) ((mask >> chan) & 1);
result = SL_RESULT_SUCCESS;
}
+ interface_unlock_shared(this);
+ *pMute = mute;
}
}
@@ -88,16 +101,22 @@ static SLresult IMuteSolo_SetChannelSolo(SLMuteSoloItf self, SLuint8 chan, SLboo
result = SL_RESULT_FEATURE_UNSUPPORTED;
} else {
CAudioPlayer *ap = (CAudioPlayer *) thisObject;
- if (ap->mNumChannels <= chan)
+ interface_lock_exclusive(this);
+ SLuint8 numChannels = ap->mNumChannels;
+ if (1 >= numChannels) {
+ interface_unlock_exclusive(this);
+ result = SL_RESULT_FEATURE_UNSUPPORTED;
+ } else if (numChannels <= chan) {
+ interface_unlock_exclusive(this);
result = SL_RESULT_PARAMETER_INVALID;
- else {
+ } else {
SLuint8 mask = 1 << chan;
- interface_lock_exclusive(this);
SLuint8 oldSoloMask = ap->mSoloMask;
- if (solo)
+ if (solo) {
ap->mSoloMask |= mask;
- else
+ } else {
ap->mSoloMask &= ~mask;
+ }
interface_unlock_exclusive_attributes(this, oldSoloMask != ap->mSoloMask ? ATTR_GAIN :
ATTR_NONE);
result = SL_RESULT_SUCCESS;
@@ -121,15 +140,22 @@ static SLresult IMuteSolo_GetChannelSolo(SLMuteSoloItf self, SLuint8 chan, SLboo
result = SL_RESULT_FEATURE_UNSUPPORTED;
} else {
CAudioPlayer *ap = (CAudioPlayer *) thisObject;
- if (ap->mNumChannels <= chan) {
+ SLboolean solo;
+ interface_lock_shared(this);
+ SLuint8 numChannels = ap->mNumChannels;
+ if (1 >= numChannels) {
+ solo = SL_BOOLEAN_FALSE;
+ result = SL_RESULT_FEATURE_UNSUPPORTED;
+ } else if (numChannels <= chan) {
+ solo = SL_BOOLEAN_FALSE;
result = SL_RESULT_PARAMETER_INVALID;
} else {
- interface_lock_peek(this);
SLuint8 mask = ap->mSoloMask;
- interface_unlock_peek(this);
- *pSolo = (mask >> chan) & 1;
+ solo = (SLboolean) ((mask >> chan) & 1);
result = SL_RESULT_SUCCESS;
}
+ interface_unlock_shared(this);
+ *pSolo = solo;
}
}
@@ -150,9 +176,11 @@ static SLresult IMuteSolo_GetNumChannels(SLMuteSoloItf self, SLuint8 *pNumChanne
result = SL_RESULT_FEATURE_UNSUPPORTED;
} else {
CAudioPlayer *ap = (CAudioPlayer *) thisObject;
- // no lock needed as mNumChannels is const
- *pNumChannels = ap->mNumChannels;
- result = SL_RESULT_SUCCESS;
+ object_lock_shared(thisObject);
+ SLuint8 numChannels = ap->mNumChannels;
+ object_unlock_shared(thisObject);
+ *pNumChannels = numChannels;
+ result = 0 < numChannels ? SL_RESULT_SUCCESS : SL_RESULT_PRECONDITIONS_VIOLATED;
}
}
diff --git a/opensles/libopensles/IObject.c b/opensles/libopensles/IObject.c
index e7c47b31..e06e1f5c 100644
--- a/opensles/libopensles/IObject.c
+++ b/opensles/libopensles/IObject.c
@@ -335,6 +335,11 @@ static SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid,
// Can't get interface on a suspended/suspending/resuming object
// unless this is an explicit pre-realize interface
result = SL_RESULT_PRECONDITIONS_VIOLATED;
+ } else if ((MPH_MUTESOLO == MPH) && (SL_OBJECTID_AUDIOPLAYER == class__->mObjectID)
+ && (1 == ((CAudioPlayer *) this)->mNumChannels)) {
+ // Can't get the MuteSolo interface of an audio player if the channel count is
+ // mono, but _can_ get the MuteSolo interface if the channel count is unknown
+ result = SL_RESULT_FEATURE_UNSUPPORTED;
} else {
switch (this->mInterfaceStates[index]) {
case INTERFACE_EXPOSED:
diff --git a/opensles/libopensles/sles.c b/opensles/libopensles/sles.c
index 4c038be5..686fe605 100644
--- a/opensles/libopensles/sles.c
+++ b/opensles/libopensles/sles.c
@@ -666,6 +666,12 @@ SLresult checkSourceFormatVsInterfacesCompatibility(const DataLocatorFormat *pDa
SL_LOGE("can't request SL_IID_SEEK with a buffer queue data source");
return SL_RESULT_FEATURE_UNSUPPORTED;
}
+ if (pInterfaceRequired[i] && (SL_IID_MUTESOLO == pInterfaceIds[i]) &&
+ (SL_DATAFORMAT_PCM == pDataLocatorFormat->mFormat.mFormatType) &&
+ (1 == pDataLocatorFormat->mFormat.mPCM.numChannels)) {
+ SL_LOGE("can't request SL_IID_MUTESOLO with a mono buffer queue data source");
+ return SL_RESULT_FEATURE_UNSUPPORTED;
+ }
}
break;
default:
@@ -992,6 +998,7 @@ extern void
IObject *construct(const ClassTable *class__, unsigned exposedMask, SLEngineItf engine)
{
IObject *this;
+ // Do not change this to malloc; we depend on the object being memset to zero
this = (IObject *) calloc(1, class__->mSize);
if (NULL != this) {
unsigned lossOfControlMask = 0;
diff --git a/opensles/tests/listening/slesTest_playMuteSolo.cpp b/opensles/tests/listening/slesTest_playMuteSolo.cpp
index 7ef101ba..d142cf4b 100644
--- a/opensles/tests/listening/slesTest_playMuteSolo.cpp
+++ b/opensles/tests/listening/slesTest_playMuteSolo.cpp
@@ -212,6 +212,13 @@ void TestPlayUri( SLObjectItf sl, const char* path)
result = (*player)->GetInterface(player, SL_IID_MUTESOLO, (void*)&muteSoloItf);
ExitOnError(result);
+ // Attempt to get the channel count before it is necessarily known.
+ // This may fail depending on the platform.
+ SLuint8 numChannels = 123;
+ result = (*muteSoloItf)->GetNumChannels(muteSoloItf, &numChannels);
+ printf("GetNumChannels after Realize but before pre-fetch: result=%lu, numChannels=%u\n",
+ result, numChannels);
+
/* Initialize a context for use by the callback */
Context context;
context.playItf = playItf;
@@ -243,7 +250,7 @@ void TestPlayUri( SLObjectItf sl, const char* path)
}
/* Query the number of channels */
- SLuint8 numChannels = 0;
+ numChannels = 123;
result = (*muteSoloItf)->GetNumChannels(muteSoloItf, &numChannels);
ExitOnError(result);
fprintf(stdout, "Content has %d channel(s)\n", numChannels);
diff --git a/opensles/tests/sandbox/intbufq.c b/opensles/tests/sandbox/intbufq.c
index f8a22b45..99289301 100644
--- a/opensles/tests/sandbox/intbufq.c
+++ b/opensles/tests/sandbox/intbufq.c
@@ -20,6 +20,7 @@
#define USE_ANDROID_SIMPLE_BUFFER_QUEUE // change to #undef for compatibility testing
#endif
+#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
@@ -59,6 +60,9 @@ frame_t square[SQUARE_FRAMES];
#define SAWTOOTH_FRAMES (44100*5)
frame_t sawtooth[SAWTOOTH_FRAMES];
+#define HALF_FRAMES (44100*5)
+frame_t half[HALF_FRAMES];
+
BufferQueueItf expectedCaller = NULL;
void *expectedContext = NULL;
@@ -115,10 +119,10 @@ int main(int argc, char **argv)
audiosnk.pLocator = &locator_outputmix;
audiosnk.pFormat = NULL;
SLObjectItf playerObject;
- SLInterfaceID ids[1] = {IID_BUFFERQUEUE};
- SLboolean flags[1] = {SL_BOOLEAN_TRUE};
+ SLInterfaceID ids[2] = {IID_BUFFERQUEUE, SL_IID_MUTESOLO};
+ SLboolean flags[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audiosrc, &audiosnk,
- 1, ids, flags);
+ 2, ids, flags);
checkResult(result);
result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
checkResult(result);
@@ -128,6 +132,12 @@ int main(int argc, char **argv)
BufferQueueItf playerBufferqueue;
result = (*playerObject)->GetInterface(playerObject, IID_BUFFERQUEUE, &playerBufferqueue);
checkResult(result);
+ SLMuteSoloItf playerMuteSolo;
+ result = (*playerObject)->GetInterface(playerObject, SL_IID_MUTESOLO, &playerMuteSolo);
+ checkResult(result);
+ SLuint8 numChannels = 123;
+ result = (*playerMuteSolo)->GetNumChannels(playerMuteSolo, &numChannels);
+ assert(2 == numChannels);
SLuint32 state;
state = SL_PLAYSTATE_PLAYING;
result = (*playerPlay)->SetPlayState(playerPlay, state);
@@ -149,6 +159,10 @@ int main(int argc, char **argv)
sawtooth[i].left = ((((int) (i % (unsigned) (sr / hz))) - 50) / 100.0) * 60000.0 - 30000.0;
sawtooth[i].right = sawtooth[i].left;
}
+ for (i = 0; i < HALF_FRAMES; ++i) {
+ half[i].left = sine[i].left;
+ half[i].right = sawtooth[i].right / 2;
+ }
set_conio_terminal_mode();
int in_count = 0;
@@ -177,6 +191,10 @@ int main(int argc, char **argv)
buffer = square;
size = sizeof(square);
goto enqueue;
+ case 'h':
+ buffer = half;
+ size = sizeof(half);
+ goto enqueue;
case 'r':
if (in_count) {
expectedCaller = playerBufferqueue;