summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Kasten <gkasten@google.com>2010-10-13 09:52:53 -0700
committerGlenn Kasten <gkasten@google.com>2010-10-15 17:38:20 -0700
commit67829bfddb97775be06af15dd8181611b4af581e (patch)
treec2c8af8f4e8675d7e3d795066679a5492a1e981e
parent227b8b5fe36d5385bbb23d63198bc8e72bfda5d3 (diff)
downloadandroid_system_media-67829bfddb97775be06af15dd8181611b4af581e.tar.gz
android_system_media-67829bfddb97775be06af15dd8181611b4af581e.tar.bz2
android_system_media-67829bfddb97775be06af15dd8181611b4af581e.zip
Bug 3102561 - Tests and examples only
Note: the modifications in directory libopensles aid testing, but have no affect on production builds because they are related to tracing, which is is disabled by default. Update feedback test to be more reliable. Update slesTestPlayUri to exit on prefetch error. Clean up error and termination handling. Add comment to record test on how to use it. Reduce global symbol dependencies when trace is enabled. Split OpenSLESUT into two files: part that uses printf, and another part that doesn't. Add SL_RESULT_ prefix to result strings. slesutResultToString returns NULL for unknown value. Add multithread torture test. Compile stream test for non-Android as a no-op. Improve API test coverage. Enable assertion checks on test programs. Change-Id: I6b82026cfa19d2f08cda4c11137e0706e8ff4b8c
-rw-r--r--opensles/libopensles/Android.mk5
-rw-r--r--opensles/libopensles/OpenSLESUT.c32
-rw-r--r--opensles/libopensles/OpenSLESUT.h5
-rw-r--r--opensles/libopensles/slesutResult.c55
-rw-r--r--opensles/libopensles/trace.c22
-rw-r--r--opensles/tests/automated/BufferQueue_test.cpp6
-rw-r--r--opensles/tests/examples/Android.mk2
-rw-r--r--opensles/tests/examples/slesTestEffectCapabilities.cpp3
-rw-r--r--opensles/tests/examples/slesTestFeedback.cpp288
-rw-r--r--opensles/tests/examples/slesTestRecBuffQueue.cpp21
-rw-r--r--opensles/tests/mimeUri/slesTestPlayStreamType.cpp2
-rw-r--r--opensles/tests/mimeUri/slesTestPlayUri.cpp9
-rw-r--r--opensles/tests/sandbox/Android.mk37
-rw-r--r--opensles/tests/sandbox/engine.c71
-rw-r--r--opensles/tests/sandbox/multithread.c190
-rw-r--r--opensles/tests/sandbox/object.c116
-rw-r--r--opensles/tests/sandbox/outputmix.c3
17 files changed, 728 insertions, 139 deletions
diff --git a/opensles/libopensles/Android.mk b/opensles/libopensles/Android.mk
index 9af0dce7..608abd75 100644
--- a/opensles/libopensles/Android.mk
+++ b/opensles/libopensles/Android.mk
@@ -2,8 +2,9 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
- OpenSLESUT.c
+LOCAL_SRC_FILES := \
+ OpenSLESUT.c \
+ slesutResult.c
LOCAL_C_INCLUDES:= \
system/media/opensles/include
diff --git a/opensles/libopensles/OpenSLESUT.c b/opensles/libopensles/OpenSLESUT.c
index 2365f01b..b693489d 100644
--- a/opensles/libopensles/OpenSLESUT.c
+++ b/opensles/libopensles/OpenSLESUT.c
@@ -24,27 +24,6 @@
#include <stdio.h>
#include <string.h>
-/** \brief Array of strings correponding to each result code */
-
-const char * const slesutResultStrings[SLESUT_RESULT_MAX] = {
- "SUCCESS",
- "PRECONDITIONS_VIOLATED",
- "PARAMETER_INVALID",
- "MEMORY_FAILURE",
- "RESOURCE_ERROR",
- "RESOURCE_LOST",
- "IO_ERROR",
- "BUFFER_INSUFFICIENT",
- "CONTENT_CORRUPTED",
- "CONTENT_UNSUPPORTED",
- "CONTENT_NOT_FOUND",
- "PERMISSION_DENIED",
- "FEATURE_UNSUPPORTED",
- "INTERNAL_ERROR",
- "UNKNOWN_ERROR",
- "OPERATION_ABORTED",
- "CONTROL_LOST"
-};
/** \brief Maps an interface ID to its display name */
@@ -118,6 +97,7 @@ static Pair pairs[] = {
#endif
};
+
/** \brief Print an interface ID in human-readable format */
void slesutPrintIID(SLInterfaceID iid)
@@ -136,6 +116,7 @@ void slesutPrintIID(SLInterfaceID iid)
iid->node[0], iid->node[1], iid->node[2], iid->node[3], iid->node[4], iid->node[5]);
}
+
/** \brief Print an array of interface IDs in human-readable format,
* including whether they are required or optional
*/
@@ -152,15 +133,6 @@ void slesutPrintIIDs(SLInterfaceID *pInterfaceIds, SLboolean *pInterfaceRequired
}
-/** \brief Convert a result code to a string. */
-
-const char *slesutResultToString(SLresult result)
-{
- // note that SLresult is unsigned
- return result < SLESUT_RESULT_MAX ? slesutResultStrings[result] : "UNKNOWN";
-}
-
-
/** \brief Convert an object ID to a string or NULL. */
const char *slesutObjectIDToString(SLuint32 objectID)
diff --git a/opensles/libopensles/OpenSLESUT.h b/opensles/libopensles/OpenSLESUT.h
index 486b58fa..59f38ceb 100644
--- a/opensles/libopensles/OpenSLESUT.h
+++ b/opensles/libopensles/OpenSLESUT.h
@@ -16,15 +16,10 @@
/** \file OpenSLESUT.h OpenSL ES Utility Toolkit */
-/** \brief Maximum result return code */
-
-#define SLESUT_RESULT_MAX (SL_RESULT_CONTROL_LOST + 1)
-
#ifdef __cplusplus
extern "C" {
#endif
-extern const char * const slesutResultStrings[SLESUT_RESULT_MAX];
extern void slesutPrintIID(SLInterfaceID iid);
extern const char *slesutResultToString(SLresult result);
extern const char *slesutObjectIDToString(SLuint32 objectID);
diff --git a/opensles/libopensles/slesutResult.c b/opensles/libopensles/slesutResult.c
new file mode 100644
index 00000000..0aca8254
--- /dev/null
+++ b/opensles/libopensles/slesutResult.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 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 <stdlib.h>
+#include "SLES/OpenSLES.h"
+#include "OpenSLESUT.h"
+
+
+/** \brief Maximum result return code */
+
+#define SLESUT_RESULT_MAX (SL_RESULT_CONTROL_LOST + 1)
+
+/** \brief Array of strings correponding to each result code */
+
+static const char * const slesutResultStrings[SLESUT_RESULT_MAX] = {
+ "SL_RESULT_SUCCESS",
+ "SL_RESULT_PRECONDITIONS_VIOLATED",
+ "SL_RESULT_PARAMETER_INVALID",
+ "SL_RESULT_MEMORY_FAILURE",
+ "SL_RESULT_RESOURCE_ERROR",
+ "SL_RESULT_RESOURCE_LOST",
+ "SL_RESULT_IO_ERROR",
+ "SL_RESULT_BUFFER_INSUFFICIENT",
+ "SL_RESULT_CONTENT_CORRUPTED",
+ "SL_RESULT_CONTENT_UNSUPPORTED",
+ "SL_RESULT_CONTENT_NOT_FOUND",
+ "SL_RESULT_PERMISSION_DENIED",
+ "SL_RESULT_FEATURE_UNSUPPORTED",
+ "SL_RESULT_INTERNAL_ERROR",
+ "SL_RESULT_UNKNOWN_ERROR",
+ "SL_RESULT_OPERATION_ABORTED",
+ "SL_RESULT_CONTROL_LOST"
+};
+
+
+/** \brief Convert a result code to a string or NULL. */
+
+const char *slesutResultToString(SLresult result)
+{
+ // note that SLresult is unsigned
+ return result < SLESUT_RESULT_MAX ? slesutResultStrings[result] : NULL;
+}
diff --git a/opensles/libopensles/trace.c b/opensles/libopensles/trace.c
index c960113f..50f73a2b 100644
--- a/opensles/libopensles/trace.c
+++ b/opensles/libopensles/trace.c
@@ -46,10 +46,11 @@ void slTraceLeaveGlobal(const char *function, SLresult result)
}
} else {
if (SL_TRACE_LEAVE_FAILURE & slTraceEnabled) {
- if (SLESUT_RESULT_MAX > result) {
- SL_LOGW("Leaving %s (%s)", function, slesutResultStrings[result]);
+ const char *str = slesutResultToString(result);
+ if (NULL != str) {
+ SL_LOGW("Leaving %s (%s)", function, str);
} else {
- SL_LOGW("Leaving %s (0x%X)", function, (unsigned) result);
+ SL_LOGW("Leaving %s (0x%lX)", function, result);
}
}
}
@@ -108,19 +109,20 @@ void slTraceLeaveInterface(const char *function, SLresult result)
}
} else {
if (SL_TRACE_LEAVE_FAILURE & slTraceEnabled) {
+ const char *str = slesutResultToString(result);
if (*underscore == '_') {
- if (SLESUT_RESULT_MAX > result) {
+ if (NULL != str) {
SL_LOGW("Leaving %.*s::%s (%s)", (int) (underscore - function), function,
- &underscore[1], slesutResultStrings[result]);
+ &underscore[1], str);
} else {
- SL_LOGW("Leaving %.*s::%s (0x%X)", (int) (underscore - function), function,
- &underscore[1], (unsigned) result);
+ SL_LOGW("Leaving %.*s::%s (0x%lX)", (int) (underscore - function), function,
+ &underscore[1], result);
}
} else {
- if (SLESUT_RESULT_MAX > result) {
- SL_LOGW("Leaving %s (%s)", function, slesutResultStrings[result]);
+ if (NULL != str) {
+ SL_LOGW("Leaving %s (%s)", function, str);
} else {
- SL_LOGW("Leaving %s (0x%X)", function, (unsigned) result);
+ SL_LOGW("Leaving %s (0x%lX)", function, result);
}
}
}
diff --git a/opensles/tests/automated/BufferQueue_test.cpp b/opensles/tests/automated/BufferQueue_test.cpp
index f6292a07..aff85473 100644
--- a/opensles/tests/automated/BufferQueue_test.cpp
+++ b/opensles/tests/automated/BufferQueue_test.cpp
@@ -52,8 +52,10 @@ static const SLuint32 validNumBuffers[] = { 1, 2, 3, 4, 5, 6, 7, 8, 255 };
/* Checks for error. If any errors exit the application! */
void CheckErr(SLresult res) {
if (SL_RESULT_SUCCESS != res) {
- fprintf(stderr, "CheckErr failure: %s (0x%x), exiting\n", slesutResultToString(res),
- (unsigned) res);
+ const char *str = slesutResultToString(res);
+ if (NULL == str)
+ str = "unknown";
+ fprintf(stderr, "CheckErr failure: %s (0x%lx), exiting\n", str, res);
//Fail the test case
FAIL();
}
diff --git a/opensles/tests/examples/Android.mk b/opensles/tests/examples/Android.mk
index 0b9ba379..901861a5 100644
--- a/opensles/tests/examples/Android.mk
+++ b/opensles/tests/examples/Android.mk
@@ -69,6 +69,8 @@ ifeq ($(TARGET_OS),linux)
#LOCAL_SHARED_LIBRARIES += librt
endif
+LOCAL_CFLAGS += -UNDEBUG
+
LOCAL_MODULE:= slesTest_feedback
include $(BUILD_EXECUTABLE)
diff --git a/opensles/tests/examples/slesTestEffectCapabilities.cpp b/opensles/tests/examples/slesTestEffectCapabilities.cpp
index 9239f08e..6d55721b 100644
--- a/opensles/tests/examples/slesTestEffectCapabilities.cpp
+++ b/opensles/tests/examples/slesTestEffectCapabilities.cpp
@@ -142,7 +142,8 @@ void TestGenericFxCapabilities( )
guidToString(effectType, typeString);
guidToString(effectImplementation, implString);
effectName[FX_NAME_LENGTH - 1] = '\0';
- fprintf(stdout, " type=%s, impl=%s name=%.*s \n", typeString, implString, effectNameLength, effectName);
+ fprintf(stdout, " type=%s, impl=%s name=%.*s \n", typeString, implString, effectNameLength,
+ effectName);
}
/* Shutdown OpenSL ES */
diff --git a/opensles/tests/examples/slesTestFeedback.cpp b/opensles/tests/examples/slesTestFeedback.cpp
index bc7df6d3..db87e2c3 100644
--- a/opensles/tests/examples/slesTestFeedback.cpp
+++ b/opensles/tests/examples/slesTestFeedback.cpp
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-// Test program to record from default audio input and playback to default audio output
-
-#undef NDEBUG
+// Test program to record from default audio input and playback to default audio output.
+// It will generate feedback (Larsen effect) if played through on-device speakers,
+// or acts as a delay if played through headset.
#include "SLES/OpenSLES.h"
#include "SLES/OpenSLES_Android.h"
#include <assert.h>
+#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -35,86 +36,164 @@ static SLuint32 txBufCount = 2; // -t#
static SLuint32 bufSizeInFrames = 512; // -f#
static SLuint32 channels = 2; // -c#
static SLuint32 sampleRate = 44100; // -s#
-static SLuint32 appBufCount = 0; // -n#
+static SLuint32 exitAfterSeconds = 60; // -e#
+static SLuint32 freeBufCount = 0; // calculated
static SLuint32 bufSizeInBytes = 0; // calculated
-static SLboolean verbose = SL_BOOLEAN_FALSE;
-// Storage area for the buffers
-static char *buffers = NULL;
+// Storage area for the buffer queues
+static char **rxBuffers;
+static char **txBuffers;
+static char **freeBuffers;
-// Index of which buffer to enqueue next
-static SLuint32 whichRecord;
-static SLuint32 whichPlay;
+// Buffer indices
+static SLuint32 rxFront; // oldest recording
+static SLuint32 rxRear; // next to be recorded
+static SLuint32 txFront; // oldest playing
+static SLuint32 txRear; // next to be played
+static SLuint32 freeFront; // oldest free
+static SLuint32 freeRear; // next to be freed
-SLAndroidSimpleBufferQueueItf recorderBufferQueue;
-SLBufferQueueItf playerBufferQueue;
+static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
+static SLBufferQueueItf playerBufferQueue;
-// Compute maximum of two values
-static SLuint32 max(SLuint32 a, SLuint32 b)
-{
- return a >= b ? a : b;
-}
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-// Compute minimum of two values
-static SLuint32 min(SLuint32 a, SLuint32 b)
+// Called after audio recorder fills a buffer with data
+static void recorderCallback(SLAndroidSimpleBufferQueueItf caller, void *context)
{
- return a <= b ? a : b;
+ SLresult result;
+
+ pthread_mutex_lock(&mutex);
+
+ // We should only be called when a recording buffer is done
+ assert(rxFront <= rxBufCount);
+ assert(rxRear <= rxBufCount);
+ assert(rxFront != rxRear);
+ char *buffer = rxBuffers[rxFront];
+
+ // Remove buffer from record queue
+ if (++rxFront > rxBufCount) {
+ rxFront = 0;
+ }
+
+ // Enqueue the just-filled buffer for the player
+ result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes);
+ if (SL_RESULT_SUCCESS == result) {
+
+ // There was room in the play queue, update our model of it
+ assert(txFront <= txBufCount);
+ assert(txRear <= txBufCount);
+ SLuint32 txRearNext = txRear+1;
+ if (txRearNext > txBufCount) {
+ txRearNext = 0;
+ }
+ assert(txRearNext != txFront);
+ txBuffers[txRear] = buffer;
+ txRear = txRearNext;
+
+ } else {
+
+ // Here if record has a filled buffer to play, but play queue is full.
+ assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
+ write(1, "?", 1);
+
+ // We could either try again later, or discard. For now we discard and re-use buffer.
+ // Enqueue this same buffer for the recorder to fill again.
+ result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
+ ASSERT_EQ(SL_RESULT_SUCCESS, result);
+
+ // Update our model of the record queue
+ SLuint32 rxRearNext = rxRear+1;
+ if (rxRearNext > rxBufCount) {
+ rxRearNext = 0;
+ }
+ assert(rxRearNext != rxFront);
+ rxBuffers[rxRear] = buffer;
+ rxRear = rxRearNext;
+
+ }
+
+ pthread_mutex_unlock(&mutex);
}
-// Called after audio recorder fills a buffer with data
-static void recorderCallback(SLAndroidSimpleBufferQueueItf caller, void *context)
+
+// Called after audio player empties a buffer of data
+static void playerCallback(SLBufferQueueItf caller, void *context)
{
SLresult result;
- if (verbose) {
- putchar('*');
- fflush(stdout);
+
+ pthread_mutex_lock(&mutex);
+
+ // Get the buffer that just finished playing
+ assert(txFront <= txBufCount);
+ assert(txRear <= txBufCount);
+ assert(txFront != txRear);
+ char *buffer = txBuffers[txFront];
+ if (++txFront > txBufCount) {
+ txFront = 0;
}
- // Enqueue the next empty buffer for the recorder to fill
- assert(whichRecord < appBufCount);
- void *buffer = &buffers[bufSizeInBytes * whichRecord];
+ // First try to enqueue the free buffer for recording
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- if (++whichRecord >= appBufCount)
- whichRecord = 0;
-
- // Enqueue the just-filled buffer for the player to empty
- assert(whichPlay < appBufCount); // sic not tx
- buffer = &buffers[bufSizeInBytes * whichPlay];
- result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes);
- // FIXME not sure yet why this is overflowing
if (SL_RESULT_SUCCESS == result) {
- if (++whichPlay >= appBufCount)
- whichPlay = 0;
+
+ // There was room in the record queue, update our model of it
+ assert(rxFront <= rxBufCount);
+ assert(rxRear <= rxBufCount);
+ SLuint32 rxRearNext = rxRear+1;
+ if (rxRearNext > rxBufCount) {
+ rxRearNext = 0;
+ }
+ assert(rxRearNext != rxFront);
+ rxBuffers[rxRear] = buffer;
+ rxRear = rxRearNext;
+
} else {
- ASSERT_EQ(SL_RESULT_BUFFER_INSUFFICIENT, result);
+
+ // Here if record queue is full
+ assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
+
+ // Instead enqueue the free buffer on the free queue
+ assert(freeFront <= freeBufCount);
+ assert(freeRear <= freeBufCount);
+ SLuint32 freeRearNext = freeRear+1;
+ if (freeRearNext > freeBufCount) {
+ freeRearNext = 0;
+ }
+ // There must always be room in the free queue
+ assert(freeRearNext != freeFront);
+ freeBuffers[freeRear] = buffer;
+ freeRear = freeRearNext;
+
}
+ pthread_mutex_unlock(&mutex);
}
+// Main program
int main(int argc, char **argv)
{
// process command-line options
int i;
for (i = 1; i < argc; ++i) {
char *arg = argv[i];
- if (arg[0] != '-')
+ if (arg[0] != '-') {
break;
- // -r# number of receive buffers
+ }
+ // -r# number of slots in receive buffer queue
if (!strncmp(arg, "-r", 2)) {
rxBufCount = atoi(&arg[2]);
- if (rxBufCount < 1 || rxBufCount > 8)
- fprintf(stderr, "%s: unusual receive buffer queue size (%u buffers)", argv[0],
+ if (rxBufCount < 1 || rxBufCount > 16) {
+ fprintf(stderr, "%s: unusual receive buffer queue size (%u buffers)\n", argv[0],
(unsigned) rxBufCount);
- // -t# number of receive buffers
+ }
+ // -t# number of slots in transmit buffer queue
} else if (!strncmp(arg, "-t", 2)) {
txBufCount = atoi(&arg[2]);
- if (txBufCount < 1 || txBufCount > 8)
- fprintf(stderr, "%s: unusual transmit buffer queue size (%u buffers)", argv[0],
+ if (txBufCount < 1 || txBufCount > 16) {
+ fprintf(stderr, "%s: unusual transmit buffer queue size (%u buffers)\n", argv[0],
(unsigned) txBufCount);
- // -n# number of application buffers
- } else if (!strncmp(arg, "-n", 2)) {
- appBufCount = atoi(&arg[2]);
+ }
// -f# size of each buffer in frames
} else if (!strncmp(arg, "-f", 2)) {
bufSizeInFrames = atoi(&arg[2]);
@@ -136,41 +215,60 @@ int main(int argc, char **argv)
switch (sampleRate) {
case 8000:
case 11025:
+ case 12000:
case 16000:
case 22050:
+ case 24000:
case 32000:
case 44100:
+ case 48000:
break;
default:
fprintf(stderr, "%s: unusual sample rate (%u Hz)\n", argv[0],
(unsigned) sampleRate);
break;
}
- // -v verbose
- } else if (!strcmp(arg, "-v")) {
- verbose = SL_BOOLEAN_TRUE;
+ // -e# exit after this many seconds
+ } else if (!strncmp(arg, "-e", 2)) {
+ exitAfterSeconds = atoi(&arg[2]);
} else
fprintf(stderr, "%s: unknown option %s\n", argv[0], arg);
}
+ // no other arguments allowed
if (i < argc) {
- fprintf(stderr, "usage: %s -r# -t# -f# -r# -m/-s\n", argv[0]);
+ fprintf(stderr, "usage: %s -r# -t# -f# -s# -c#\n", argv[0]);
fprintf(stderr, " -r# receive buffer queue count for microphone input, default 1\n");
fprintf(stderr, " -t# transmit buffer queue count for speaker output, default 2\n");
fprintf(stderr, " -f# number of frames per buffer, default 512\n");
fprintf(stderr, " -s# sample rate in Hz, default 44100\n");
- fprintf(stderr, " -n# number of application-allocated buffers, default max(-r#,-t#)\n");
fprintf(stderr, " -c1 mono\n");
fprintf(stderr, " -c2 stereo, default\n");
}
- if (appBufCount == 0)
- appBufCount = max(rxBufCount, txBufCount);
- if (appBufCount == 0)
- appBufCount = 1;
- if (appBufCount < max(rxBufCount, txBufCount))
- fprintf(stderr, "%s: unusual application buffer count (%u buffers)", argv[0],
- (unsigned) appBufCount);
+ // compute total free buffers as -r plus -t
+ freeBufCount = rxBufCount + txBufCount;
+ // compute buffer size
bufSizeInBytes = channels * bufSizeInFrames * sizeof(short);
- buffers = (char *) malloc(bufSizeInBytes * appBufCount);
+
+ // Initialize free buffers
+ freeBuffers = (char **) calloc(freeBufCount+1, sizeof(char *));
+ unsigned j;
+ for (j = 0; j < freeBufCount; ++j) {
+ freeBuffers[j] = (char *) malloc(bufSizeInBytes);
+ }
+ freeFront = 0;
+ freeRear = freeBufCount;
+ freeBuffers[j] = NULL;
+
+ // Initialize record queue
+ rxBuffers = (char **) calloc(rxBufCount+1, sizeof(char *));
+ rxFront = 0;
+ rxRear = 0;
+
+ // Initialize play queue
+ txBuffers = (char **) calloc(txBufCount+1, sizeof(char *));
+ txFront = 0;
+ txRear = 0;
+
SLresult result;
// create engine
@@ -212,11 +310,16 @@ int main(int argc, char **argv)
audiosrc.pFormat = &pcm;
audiosnk.pLocator = &locator_outputmix;
audiosnk.pFormat = NULL;
- SLObjectItf playerObject;
+ SLObjectItf playerObject = NULL;
+ SLObjectItf recorderObject = NULL;
SLInterfaceID ids_tx[1] = {SL_IID_BUFFERQUEUE};
SLboolean flags_tx[1] = {SL_BOOLEAN_TRUE};
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audiosrc, &audiosnk,
1, ids_tx, flags_tx);
+ if (SL_RESULT_CONTENT_UNSUPPORTED == result) {
+ fprintf(stderr, "Could not create audio player (result %lx), check sample rate\n", result);
+ goto cleanup;
+ }
ASSERT_EQ(SL_RESULT_SUCCESS, result);
result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
ASSERT_EQ(SL_RESULT_SUCCESS, result);
@@ -225,6 +328,8 @@ int main(int argc, char **argv)
ASSERT_EQ(SL_RESULT_SUCCESS, result);
result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, &playerBufferQueue);
ASSERT_EQ(SL_RESULT_SUCCESS, result);
+ result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, playerCallback, NULL);
+ ASSERT_EQ(SL_RESULT_SUCCESS, result);
result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
ASSERT_EQ(SL_RESULT_SUCCESS, result);
@@ -243,11 +348,17 @@ int main(int argc, char **argv)
locator_bufferqueue_rx.numBuffers = rxBufCount;
audiosnk.pLocator = &locator_bufferqueue_rx;
audiosnk.pFormat = &pcm;
- SLObjectItf recorderObject;
+ {
SLInterfaceID ids_rx[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
SLboolean flags_rx[1] = {SL_BOOLEAN_TRUE};
result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audiosrc,
&audiosnk, 1, ids_rx, flags_rx);
+ if (SL_RESULT_SUCCESS != result) {
+ fprintf(stderr, "Could not create audio recorder (result %lx), "
+ "check sample rate and channel count\n", result);
+ goto cleanup;
+ }
+ }
ASSERT_EQ(SL_RESULT_SUCCESS, result);
result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
ASSERT_EQ(SL_RESULT_SUCCESS, result);
@@ -261,37 +372,54 @@ int main(int argc, char **argv)
ASSERT_EQ(SL_RESULT_SUCCESS, result);
// Enqueue some empty buffers for the recorder
- SLuint32 temp = min(rxBufCount, appBufCount);
- for (whichRecord = 0; whichRecord < (temp <= 1 ? 1 : temp - 1); ++whichRecord) {
+ for (j = 0; j < rxBufCount; ++j) {
+
+ // allocate a free buffer
+ assert(freeFront != freeRear);
+ char *buffer = freeBuffers[freeFront];
+ if (++freeFront > freeBufCount) {
+ freeFront = 0;
+ }
+
+ // put on record queue
+ SLuint32 rxRearNext = rxRear + 1;
+ if (rxRearNext > rxBufCount) {
+ rxRearNext = 0;
+ }
+ assert(rxRearNext != rxFront);
+ rxBuffers[rxRear] = buffer;
+ rxRear = rxRearNext;
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue,
- &buffers[bufSizeInBytes * whichRecord], bufSizeInBytes);
+ buffer, bufSizeInBytes);
ASSERT_EQ(SL_RESULT_SUCCESS, result);
}
- if (whichRecord >= appBufCount)
- whichRecord = 0;
// Kick off the recorder
- whichPlay = 0;
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
ASSERT_EQ(SL_RESULT_SUCCESS, result);
// Wait patiently
- for (;;) {
+ do {
usleep(1000000);
- putchar('.');
+ write(1, ".", 1);
SLBufferQueueState playerBQState;
result = (*playerBufferQueue)->GetState(playerBufferQueue, &playerBQState);
ASSERT_EQ(SL_RESULT_SUCCESS, result);
SLAndroidSimpleBufferQueueState recorderBQState;
result = (*recorderBufferQueue)->GetState(recorderBufferQueue, &recorderBQState);
ASSERT_EQ(SL_RESULT_SUCCESS, result);
- if (verbose) {
- printf("pC%u pI%u rC%u rI%u\n", (unsigned) playerBQState.count,
- (unsigned) playerBQState.playIndex, (unsigned) recorderBQState.count,
- (unsigned) recorderBQState.index);
- fflush(stdout);
- }
+ } while (--exitAfterSeconds);
+
+ // Tear down the objects and exit
+cleanup:
+ if (NULL != playerObject) {
+ (*playerObject)->Destroy(playerObject);
+ }
+ if (NULL != recorderObject) {
+ (*recorderObject)->Destroy(recorderObject);
}
+ (*outputmixObject)->Destroy(outputmixObject);
+ (*engineObject)->Destroy(engineObject);
- //return EXIT_SUCCESS;
+ return EXIT_SUCCESS;
}
diff --git a/opensles/tests/examples/slesTestRecBuffQueue.cpp b/opensles/tests/examples/slesTestRecBuffQueue.cpp
index 6a247620..4ffa3d1a 100644
--- a/opensles/tests/examples/slesTestRecBuffQueue.cpp
+++ b/opensles/tests/examples/slesTestRecBuffQueue.cpp
@@ -14,6 +14,27 @@
* limitations under the License.
*/
+/* Audio Record Test
+
+First run the program from shell:
+ # slesTest_recBuffQueue /sdcard/myrec.raw 4
+
+These use adb on host to retrive the file:
+ % adb pull /sdcard/myrec.raw myrec.raw
+
+How to examine the output with Audacity:
+ Project / Import raw data
+ Select myrec.raw file, then click Open button
+ Choose these options:
+ Signed 16-bit PCM
+ Little-endian
+ 1 Channel (Mono)
+ Sample rate 22050 Hz
+ Click Import button
+
+*/
+
+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
diff --git a/opensles/tests/mimeUri/slesTestPlayStreamType.cpp b/opensles/tests/mimeUri/slesTestPlayStreamType.cpp
index ad5c3946..acf1d056 100644
--- a/opensles/tests/mimeUri/slesTestPlayStreamType.cpp
+++ b/opensles/tests/mimeUri/slesTestPlayStreamType.cpp
@@ -107,8 +107,10 @@ void TestStreamTypeConfiguration( SLObjectItf sl, const char* path, const SLint3
/* (SLPlayItf is implicit) */
required[0] = SL_BOOLEAN_TRUE;
iidArray[0] = SL_IID_PREFETCHSTATUS;
+#ifdef ANDROID
required[1] = SL_BOOLEAN_TRUE;
iidArray[1] = SL_IID_ANDROIDCONFIGURATION;
+#endif
/* Setup the data source structure for the URI */
diff --git a/opensles/tests/mimeUri/slesTestPlayUri.cpp b/opensles/tests/mimeUri/slesTestPlayUri.cpp
index fdab0431..d9247007 100644
--- a/opensles/tests/mimeUri/slesTestPlayUri.cpp
+++ b/opensles/tests/mimeUri/slesTestPlayUri.cpp
@@ -63,6 +63,8 @@ void ExitOnErrorFunc( SLresult result , int line)
}
}
+bool prefetchError = false;
+
//-----------------------------------------------------------------
/* PrefetchStatusItf callback for an audio player */
void PrefetchEventCallback( SLPrefetchStatusItf caller, void *pContext, SLuint32 event)
@@ -75,7 +77,7 @@ void PrefetchEventCallback( SLPrefetchStatusItf caller, void *pContext, SLuint3
if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE))
&& (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
fprintf(stdout, "PrefetchEventCallback: Error while prefetching data, exiting\n");
- //exit(EXIT_FAILURE);
+ prefetchError = true;
}
if (event & SL_PREFETCHEVENT_FILLLEVELCHANGE) {
fprintf(stdout, "PrefetchEventCallback: Buffer fill level is = %d\n", level);
@@ -207,13 +209,14 @@ void TestPlayUri( SLObjectItf sl, const char* path)
//SLpermille fillLevel = 0;
SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
SLuint32 timeOutIndex = 100; // 10s
- while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0)) {
+ while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0) &&
+ !prefetchError) {
usleep(100 * 1000);
(*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
timeOutIndex--;
}
- if (timeOutIndex == 0) {
+ if (timeOutIndex == 0 || prefetchError) {
fprintf(stderr, "We\'re done waiting, failed to prefetch data in time, exiting\n");
goto destroyRes;
}
diff --git a/opensles/tests/sandbox/Android.mk b/opensles/tests/sandbox/Android.mk
index 8bc8cac6..2e91f766 100644
--- a/opensles/tests/sandbox/Android.mk
+++ b/opensles/tests/sandbox/Android.mk
@@ -22,6 +22,8 @@ ifeq ($(TARGET_OS),linux)
#LOCAL_SHARED_LIBRARIES += librt
endif
+LOCAL_CFLAGS += -UNDEBUG
+
LOCAL_MODULE:= slesTest_intbufq
include $(BUILD_EXECUTABLE)
@@ -46,6 +48,8 @@ ifeq ($(TARGET_OS),linux)
LOCAL_CFLAGS += -DXP_UNIX
endif
+LOCAL_CFLAGS += -UNDEBUG
+
LOCAL_MODULE:= slesTest_multiplay
include $(BUILD_EXECUTABLE)
@@ -73,6 +77,8 @@ ifeq ($(TARGET_OS),linux)
LOCAL_CFLAGS += -DXP_UNIX
endif
+LOCAL_CFLAGS += -UNDEBUG
+
LOCAL_MODULE:= slesTest_engine
include $(BUILD_EXECUTABLE)
@@ -100,6 +106,8 @@ ifeq ($(TARGET_OS),linux)
LOCAL_CFLAGS += -DXP_UNIX
endif
+LOCAL_CFLAGS += -UNDEBUG
+
LOCAL_MODULE:= slesTest_object
include $(BUILD_EXECUTABLE)
@@ -245,3 +253,32 @@ LOCAL_CFLAGS += -UNDEBUG
LOCAL_MODULE:= slesTest_dim
include $(BUILD_EXECUTABLE)
+
+# multithread
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_C_INCLUDES:= \
+ system/media/opensles/include
+
+LOCAL_SRC_FILES:= \
+ multithread.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_multithread
+
+include $(BUILD_EXECUTABLE)
diff --git a/opensles/tests/sandbox/engine.c b/opensles/tests/sandbox/engine.c
index a3092af6..16d60fe3 100644
--- a/opensles/tests/sandbox/engine.c
+++ b/opensles/tests/sandbox/engine.c
@@ -28,11 +28,15 @@ int main(int argc, char **argv)
SLuint32 numSupportedInterfaces = 12345;
result = slQueryNumSupportedEngineInterfaces(&numSupportedInterfaces);
assert(SL_RESULT_SUCCESS == result);
+ result = slQueryNumSupportedEngineInterfaces(NULL);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+
printf("Engine number of supported interfaces %lu\n", numSupportedInterfaces);
- SLInterfaceID *engine_ids = calloc(numSupportedInterfaces, sizeof(SLInterfaceID));
+ SLInterfaceID *engine_ids = calloc(numSupportedInterfaces+1, sizeof(SLInterfaceID));
assert(engine_ids != NULL);
- SLboolean *engine_req = calloc(numSupportedInterfaces, sizeof(SLboolean));
+ SLboolean *engine_req = calloc(numSupportedInterfaces+1, sizeof(SLboolean));
assert(engine_req != NULL);
+
printf("Display the ID of each available interface\n");
SLuint32 index;
for (index = 0; index < numSupportedInterfaces + 1; ++index) {
@@ -48,12 +52,65 @@ int main(int argc, char **argv)
} else {
assert(SL_RESULT_PARAMETER_INVALID == result);
}
+ result = slQuerySupportedEngineInterfaces(index, NULL);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
}
+
printf("Create an engine and request all available interfaces\n");
SLObjectItf engineObject;
- result = slCreateEngine(&engineObject, 0, NULL, numSupportedInterfaces, engine_ids, engine_req);
+ if (0 < numSupportedInterfaces) {
+ printf("Create engine with numSupportedInterfaces > 0 but NULL pointers\n");
+ result = slCreateEngine(&engineObject, 0, NULL, numSupportedInterfaces, engine_ids, NULL);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ assert(NULL == engineObject);
+ result = slCreateEngine(&engineObject, 0, NULL, numSupportedInterfaces, NULL, engine_req);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ assert(NULL == engineObject);
+ }
+
+ printf("Create engine with no place to return the new engine object\n");
+ result = slCreateEngine(NULL, 0, NULL, numSupportedInterfaces, engine_ids, engine_req);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+
+ printf("Create engine with NULL interface pointer\n");
+ SLInterfaceID null_id[1] = {NULL};
+ SLboolean null_req[1] = {SL_BOOLEAN_FALSE};
+ result = slCreateEngine(&engineObject, 0, NULL, 1, null_id, null_req);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ assert(NULL == engineObject);
+
+ printf("Create an engine with numOptions > 0 but NULL pointer\n");
+ result = slCreateEngine(&engineObject, 1, NULL, 0, NULL, NULL);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ assert(NULL == engineObject);
+ SLEngineOption options[2];
+ options[0].feature = 0x12345;
+ options[0].data = 0;
+
+ printf("Create engine with non-sensical option\n");
+ result = slCreateEngine(&engineObject, 1, options, 0, NULL, NULL);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ assert(NULL == engineObject);
+
+ printf("Create an engine and require non-sensical volume interface\n");
+ engine_ids[numSupportedInterfaces] = SL_IID_VOLUME;
+ engine_req[numSupportedInterfaces] = SL_BOOLEAN_TRUE;
+ result = slCreateEngine(&engineObject, 0, NULL, numSupportedInterfaces+1, engine_ids,
+ engine_req);
+ assert(SL_RESULT_FEATURE_UNSUPPORTED == result);
+ assert(NULL == engineObject);
+
+ printf("Create an engine and politely request a non-sensical interface with options\n");
+ engine_req[numSupportedInterfaces] = SL_BOOLEAN_FALSE;
+ options[0].feature = SL_ENGINEOPTION_THREADSAFE;
+ options[0].data = (SLuint32) SL_BOOLEAN_TRUE;
+ options[1].feature = SL_ENGINEOPTION_LOSSOFCONTROL;
+ options[1].data = (SLuint32) SL_BOOLEAN_FALSE;
+ result = slCreateEngine(&engineObject, 2, options, numSupportedInterfaces+1, engine_ids,
+ engine_req);
assert(SL_RESULT_SUCCESS == result);
printf("Engine object %p\n", engineObject);
+
printf("Get each available interface before realization\n");
for (index = 0; index < numSupportedInterfaces; ++index) {
void *interface = NULL;
@@ -65,15 +122,19 @@ int main(int argc, char **argv)
slesutPrintIID(engine_ids[index]);
}
}
+
printf("Destroy engine before realization\n");
(*engineObject)->Destroy(engineObject);
+
printf("Create engine again\n");
result = slCreateEngine(&engineObject, 0, NULL, numSupportedInterfaces, engine_ids, engine_req);
assert(SL_RESULT_SUCCESS == result);
printf("Engine object %p\n", engineObject);
+
printf("Realize the engine\n");
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
+
printf("Get each available interface after realization\n");
for (index = 0; index < numSupportedInterfaces; ++index) {
void *interface = NULL;
@@ -88,16 +149,20 @@ int main(int argc, char **argv)
// Calling GetInterface multiple times should return the same interface
assert(interface_again == interface);
}
+
printf("Create too many engines\n");
SLObjectItf engineObject2;
result = slCreateEngine(&engineObject2, 0, NULL, 0, NULL, NULL);
assert(SL_RESULT_RESOURCE_ERROR == result);
assert(NULL == engineObject2);
+
printf("Destroy engine\n");
(*engineObject)->Destroy(engineObject);
+
printf("Now should be able to create another engine\n");
result = slCreateEngine(&engineObject2, 0, NULL, 0, NULL, NULL);
assert(SL_RESULT_SUCCESS == result);
+
printf("Exit without destroying engine -- examine log for expected error message\n");
return EXIT_SUCCESS;
}
diff --git a/opensles/tests/sandbox/multithread.c b/opensles/tests/sandbox/multithread.c
new file mode 100644
index 00000000..35b0d8e4
--- /dev/null
+++ b/opensles/tests/sandbox/multithread.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+// Multiple threads create and destroy objects
+
+#include "SLES/OpenSLES.h"
+#include <assert.h>
+#include <pthread.h>
+//#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+typedef struct {
+ SLuint32 mObjectID;
+ SLchar *mURI;
+ SLEngineItf mEngineEngine;
+ SLObjectItf mMixObject;
+ SLuint32 mCounter;
+} ThreadArgument;
+
+volatile int timeToExit = 0;
+#define MAX_THREAD 10
+pthread_t threads[MAX_THREAD];
+ThreadArgument thread_args[MAX_THREAD];
+
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void *thread_start(void *param)
+{
+ //pthread_mutex_lock(&mutex);
+ //pthread_mutex_unlock(&mutex);
+ ThreadArgument *ta = (ThreadArgument *) param;
+
+ while (!timeToExit) {
+ SLresult result;
+
+ ++ta->mCounter;
+ switch (ta->mObjectID) {
+ case SL_OBJECTID_OUTPUTMIX:
+ {
+ SLObjectItf myMixObject;
+ result = (*ta->mEngineEngine)->CreateOutputMix(ta->mEngineEngine, &myMixObject, 0, NULL,
+ NULL);
+ assert(SL_RESULT_SUCCESS == result);
+ result = (*myMixObject)->Realize(myMixObject, SL_BOOLEAN_FALSE);
+ assert(SL_RESULT_SUCCESS == result);
+ (*myMixObject)->Destroy(myMixObject);
+ }
+ break;
+
+ case SL_OBJECTID_AUDIOPLAYER:
+ {
+ SLDataLocator_URI locURI = {SL_DATALOCATOR_URI, ta->mURI};
+ SLDataFormat_MIME dfMIME = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
+ SLDataSource audioSrc = {&locURI, &dfMIME};
+ SLDataLocator_OutputMix locOutputMix = {SL_DATALOCATOR_OUTPUTMIX, ta->mMixObject};
+ SLDataSink audioSnk = {&locOutputMix, NULL};
+ SLObjectItf myPlayerObject;
+ result = (*ta->mEngineEngine)->CreateAudioPlayer(ta->mEngineEngine, &myPlayerObject,
+ &audioSrc, &audioSnk, 0, NULL, NULL);
+ assert(SL_RESULT_SUCCESS == result);
+ result = (*myPlayerObject)->Realize(myPlayerObject, SL_BOOLEAN_FALSE);
+ assert(SL_RESULT_SUCCESS == result);
+ SLPlayItf playerPlay;
+ result = (*myPlayerObject)->GetInterface(myPlayerObject, SL_IID_PLAY, &playerPlay);
+ assert(SL_RESULT_SUCCESS == result);
+ result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);//PAUSED);
+ assert(SL_RESULT_SUCCESS == result);
+ usleep(1000000 + (rand() & 0xFFFFF));//Android crash on 10000 and PAUSED
+ (*myPlayerObject)->Destroy(myPlayerObject);
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ //usleep(100000);
+ }
+
+ return NULL;
+}
+
+
+const char * const uris[4] = {"wav/frog.wav", "wav/bach.wav", "wav/8days.wav", "wav/help16.wav"};
+
+// Main program
+
+int main(int argc, char **argv)
+{
+ SLresult result;
+
+ // create engine
+ SLObjectItf engineObject;
+ result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
+ assert(SL_RESULT_SUCCESS == result);
+ result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
+ assert(SL_RESULT_SUCCESS == result);
+ SLEngineItf engineEngine;
+ result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // create output mix
+ SLObjectItf mixObject;
+ result = (*engineEngine)->CreateOutputMix(engineEngine, &mixObject, 0, NULL, NULL);
+ assert(SL_RESULT_SUCCESS == result);
+ result = (*mixObject)->Realize(mixObject, SL_BOOLEAN_FALSE);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // create threads
+ int i;
+ int ok;
+ for (i = 0; i < MAX_THREAD; ++i) {
+ ThreadArgument *ta = &thread_args[i];
+ int r = rand();
+ switch (r & 1) {
+#if 0
+ case 0:
+ ta->mObjectID = SL_OBJECTID_OUTPUTMIX;
+ ta->mURI = NULL;
+ ta->mEngineEngine = engineEngine;
+ ta->mMixObject = NULL;
+ ta->mCounter = 0;
+ break;
+ case 1:
+#endif
+ default:
+ ta->mObjectID = SL_OBJECTID_AUDIOPLAYER;
+ ta->mURI = (SLchar *) uris[(r >> 1) & 3];
+ ta->mEngineEngine = engineEngine;
+ ta->mMixObject = mixObject;
+ ta->mCounter = 0;
+ break;
+ }
+ //pthread_mutex_lock(&mutex);
+ //pthread_mutex_unlock(&mutex);
+ ok = pthread_create(&threads[i], (const pthread_attr_t *) NULL, thread_start,
+ &thread_args[i]);
+ assert(0 == ok);
+ }
+
+ // let it run for a while
+ int j;
+ for (j = 0; j < 10; ++j) {
+ sleep(1);
+ for (i = 0; i < MAX_THREAD; ++i) {
+ ThreadArgument *ta = &thread_args[i];
+ printf("[%d]=%lu ", j, ta->mCounter);
+ }
+ printf("\n");
+ }
+
+ // signal threads that they should exit
+ timeToExit = 1;
+
+ for (j = 0; j < 3; ++j) {
+ sleep(1);
+ for (i = 0; i < MAX_THREAD; ++i) {
+ ThreadArgument *ta = &thread_args[i];
+ printf("[%d]=%lu ", j, ta->mCounter);
+ }
+ printf("\n");
+ }
+
+ // now wait for the threads to actually exit
+ for (i = 0; i < MAX_THREAD; ++i) {
+ ok = pthread_join(threads[i], NULL);
+ assert(0 == ok);
+ }
+
+ // tear down objects
+ (*mixObject)->Destroy(mixObject);
+ (*engineObject)->Destroy(engineObject);
+
+ return EXIT_SUCCESS;
+}
diff --git a/opensles/tests/sandbox/object.c b/opensles/tests/sandbox/object.c
index 2285ed76..9257a350 100644
--- a/opensles/tests/sandbox/object.c
+++ b/opensles/tests/sandbox/object.c
@@ -17,6 +17,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "SLES/OpenSLES.h"
#include "SLES/OpenSLESUT.h"
@@ -34,26 +35,40 @@ int main(int arg, char **argv)
SLEngineItf engineEngine;
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
assert(SL_RESULT_SUCCESS == result);
+ SLuint32 i;
// loop through both valid and invalid object IDs
SLuint32 objectID;
- for (objectID = 0x1000; objectID <= 0x100B; ++objectID) {
+ // Test object IDs from one less than the first valid object
+ // ID, up to one more than the last valid object ID. This way
+ // we can test for both valid and invalid object IDs at both
+ // ends. If more objects are added, be sure to update the macros.
+#define FIRST_VALID SL_OBJECTID_ENGINE
+#define LAST_VALID SL_OBJECTID_METADATAEXTRACTOR
+ for (objectID = FIRST_VALID - 1; objectID <= LAST_VALID + 1; ++objectID) {
printf("object ID %lx", objectID);
const char *string = slesutObjectIDToString(objectID);
if (NULL != string)
printf(" (%s)", string);
printf(":\n");
+ result = (*engineEngine)->QueryNumSupportedInterfaces(engineEngine, objectID, NULL);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
SLuint32 numSupportedInterfaces = 12345;
result = (*engineEngine)->QueryNumSupportedInterfaces(engineEngine, objectID,
&numSupportedInterfaces);
+ SLInterfaceID interfaceID;
if (SL_RESULT_FEATURE_UNSUPPORTED == result) {
printf(" unsupported\n");
+ result = (*engineEngine)->QuerySupportedInterfaces(engineEngine, objectID, 0,
+ &interfaceID);
+ assert(SL_RESULT_FEATURE_UNSUPPORTED == result);
+ assert(NULL == interfaceID);
continue;
}
assert(SL_RESULT_SUCCESS == result);
printf("numSupportedInterfaces %lu\n", numSupportedInterfaces);
- SLuint32 i;
for (i = 0; i < numSupportedInterfaces + 1; ++i) {
- SLInterfaceID interfaceID;
+ result = (*engineEngine)->QuerySupportedInterfaces(engineEngine, objectID, i, NULL);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
result = (*engineEngine)->QuerySupportedInterfaces(engineEngine, objectID, i,
&interfaceID);
if (i < numSupportedInterfaces) {
@@ -65,5 +80,100 @@ int main(int arg, char **argv)
}
}
}
+ // query number of extensions
+ result = (*engineEngine)->QueryNumSupportedExtensions(engineEngine, NULL);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ SLuint32 numExtensions = 0x12345;
+ result = (*engineEngine)->QueryNumSupportedExtensions(engineEngine, &numExtensions);
+ assert(SL_RESULT_SUCCESS == result);
+ printf("numExtensions = %lu\n", numExtensions);
+ // query names of the extensions
+ for (i = 0; i < numExtensions + 1; ++i) {
+ SLchar extensionName[32];
+ result = (*engineEngine)->QuerySupportedExtension(engineEngine, i, extensionName, NULL);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ SLint16 nameLength = -1;
+ result = (*engineEngine)->QuerySupportedExtension(engineEngine, i, NULL, &nameLength);
+ if (i < numExtensions) {
+ assert(SL_RESULT_SUCCESS == result);
+ printf(" extension[%lu] length = %u\n", i, nameLength);
+ } else {
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ assert(0 == nameLength);
+ }
+ memset(extensionName, 'X', sizeof(extensionName));
+ nameLength = -1;
+ result = (*engineEngine)->QuerySupportedExtension(engineEngine, i, extensionName,
+ &nameLength);
+ if (i < numExtensions) {
+ assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
+ } else {
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ }
+ assert('X' == extensionName[0]);
+ nameLength = 0;
+ result = (*engineEngine)->QuerySupportedExtension(engineEngine, i, extensionName,
+ &nameLength);
+ if (i < numExtensions) {
+ assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
+ } else {
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ }
+ assert('X' == extensionName[0]);
+ nameLength = 1;
+ result = (*engineEngine)->QuerySupportedExtension(engineEngine, i, extensionName,
+ &nameLength);
+ if (i < numExtensions) {
+ assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
+ assert('\0' == extensionName[0]);
+ } else {
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ }
+ assert('X' == extensionName[1]);
+ nameLength = sizeof(extensionName);
+ result = (*engineEngine)->QuerySupportedExtension(engineEngine, i, extensionName,
+ &nameLength);
+ if (i < numExtensions) {
+ assert(SL_RESULT_SUCCESS == result);
+ assert((1 <= nameLength) && (nameLength <= (SLint16) sizeof(extensionName)));
+ printf(" extension[%lu] = \"%.*s\"\n", i, nameLength, extensionName);
+ } else {
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ assert(0 == nameLength);
+ }
+ }
+ // check if extension is supported
+ SLboolean isSupported = SL_BOOLEAN_TRUE;
+ result = (*engineEngine)->IsExtensionSupported(engineEngine, NULL, &isSupported);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ assert(SL_BOOLEAN_FALSE == isSupported);
+ SLchar *unsupportedExt = (SLchar *) "fish";
+ result = (*engineEngine)->IsExtensionSupported(engineEngine, unsupportedExt, NULL);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ isSupported = SL_BOOLEAN_TRUE;
+ result = (*engineEngine)->IsExtensionSupported(engineEngine, unsupportedExt, &isSupported);
+ assert(SL_RESULT_SUCCESS == result);
+ assert(SL_BOOLEAN_FALSE == isSupported);
+ SLchar *supportedExt;
+#ifdef ANDROID
+ supportedExt = (SLchar *) "ANDROID_NDK_LEVEL_9";
+#else
+ supportedExt = (SLchar *) "WILHELM_DESKTOP";
+#endif
+ isSupported = SL_BOOLEAN_FALSE;
+ result = (*engineEngine)->IsExtensionSupported(engineEngine, supportedExt, &isSupported);
+ assert(SL_RESULT_SUCCESS == result);
+ assert(SL_BOOLEAN_TRUE == isSupported);
+ // create an extension object with no place to put the new object
+ result = (*engineEngine)->CreateExtensionObject(engineEngine, NULL, NULL, 0x123, 0, NULL, NULL);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
+ // create an extension object, which is unsupported
+ SLObjectItf extensionObject;
+ result = (*engineEngine)->CreateExtensionObject(engineEngine, &extensionObject, NULL, 0x123, 0,
+ NULL, NULL);
+ assert(SL_RESULT_FEATURE_UNSUPPORTED == result);
+ assert(NULL == extensionObject);
+ // destroy engine
+ (*engineObject)->Destroy(engineObject);
return EXIT_SUCCESS;
}
diff --git a/opensles/tests/sandbox/outputmix.c b/opensles/tests/sandbox/outputmix.c
index b98b5daa..f0d15f69 100644
--- a/opensles/tests/sandbox/outputmix.c
+++ b/opensles/tests/sandbox/outputmix.c
@@ -53,6 +53,9 @@ int main(int argc, char **argv)
printf(" [%lu] = ", i);
slesutPrintIID(interfaceID);
}
+ // create output mix, with no place to put the new object
+ result = (*engineEngine)->CreateOutputMix(engineEngine, NULL, 0, NULL, NULL);
+ assert(SL_RESULT_PARAMETER_INVALID == result);
// create output mix, requesting no explicit interfaces
SLObjectItf outputMixObject;
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);